From 6365c58bd45d51c1c44bac9321290aa7917e70de Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Thu, 6 Jun 2019 01:15:49 +0200 Subject: [PATCH 01/72] Initial commit --- .gitignore | 3 + Cargo.lock | 183 +++++++++++++++++++++++++++++++++++ Cargo.toml | 16 ++++ README.md | 18 ++++ download.sh | 3 + process.py | 172 +++++++++++++++++++++++++++++++++ src/main.rs | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 667 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 download.sh create mode 100644 process.py create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..832207a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +.vscode/** \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..416bf99 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,183 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "csv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ed_ldr" +version = "0.1.0" +dependencies = [ + "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "humantime" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pdqselect" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rstar" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" +"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" +"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" +"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd08ae4f9661517777346592956ea6cdbba2895a28037af7daa600382f4b4001" +"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" +"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" +"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" +"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a874f2a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ed_ldr" +version = "0.1.0" +authors = ["Daniel Seiller "] +edition = "2018" + +# [profile.release] +# debug = true + +[dependencies] +csv = "1.0.7" +serde = "1.0.92" +serde_derive = "1.0.92" +rstar = "0.4.0" +humantime = "1.2.0" +fnv = "1.0.6" diff --git a/README.md b/README.md new file mode 100644 index 0000000..a65ba25 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Elite: Dangerous Long Range Router (Rust Version) + +## Usage: + +#. run `download.sh` and `process.py` (you can hit Ctrl+C when it says "Building KD-Tree..") +#. edit source, destination and range in `src/main.rs` +#. (optional) `set RUSTFLAGS=-C target-cpu=native` (Windows) or `export RUSTFLAGS=-C target-cpu=native` (Linux) +#. `cargo run --release` + + + +## Dependencies + +- Python 3.7 + - Pandas + - uJSON +- Working nightly Rust Compiler (tested with `rustc 1.37.0-nightly (5d8f59f4b 2019-06-04)`) +- ~8GB of free RAM \ No newline at end of file diff --git a/download.sh b/download.sh new file mode 100644 index 0000000..ea5226e --- /dev/null +++ b/download.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash +rm systemsWithCoordinates.json bodies.json *.aria2 +wget https://www.edsm.net/dump/systemsWithCoordinates.json https://www.edsm.net/dump/bodies.json \ No newline at end of file diff --git a/process.py b/process.py new file mode 100644 index 0000000..6416cbc --- /dev/null +++ b/process.py @@ -0,0 +1,172 @@ +import ujson as json +from tqdm import tqdm +from pprint import pprint +import itertools as ITT +import os +import sys +import csv +import sqlite3 +import pandas as pd + + +def is_scoopable(entry): + first = entry.type.split()[0] + return first == "Neutron" or first == "White" or first in "KGBFOAM" + + +def get_mult(name): + try: + first = name.split()[0] + except: + return 1 + if first == "Neutron": + return 4 + if first == "White": + return 1.5 + return 1 + + +def dict_factory(cursor, row): + d = {} + for idx, col in enumerate(cursor.description): + d[col[0]] = row[idx] + return d + + +def blocks(files, size=65536): + while True: + b = files.read(size) + if not b: + break + yield b + + +def getlines(f, fn, show_progbar=False): + f.seek(0, 2) + size = f.tell() + f.seek(0) + progbar = tqdm( + desc="Processing " + fn, + total=size, + unit="b", + unit_scale=True, + unit_divisor=1024, + ascii=True, + leave=True, + disable=(not show_progbar), + ) + buffer = [] + for block in blocks(f): + progbar.n = f.tell() + progbar.update(0) + if buffer: + buffer += (buffer.pop(0) + block).splitlines(keepends=True) + else: + buffer += block.splitlines(keepends=True) + while buffer and buffer[0].endswith("\n"): + try: + yield json.loads(buffer.pop(0).strip().rstrip(",")) + except ValueError: + pass + while buffer: + try: + yield json.loads(buffer.pop(0).strip().rstrip(",")) + except ValueError: + pass + + +def process_file(fn, show_progbar=False): + with open(fn, "r") as f: + for line in tqdm( + getlines(f, fn, show_progbar), + desc=fn, + unit=" lines", + unit_scale=True, + ascii=True, + leave=True, + disable=(not show_progbar), + ): + yield line + + +if not os.path.isfile("stars.jl"): + print("Filtering for Neutron Stars") + with open("stars.jl", "w") as neut: + for body in process_file("bodies.json", True): + T = body.get("type") or "" + if "Star" in T: + neut.write(json.dumps(body) + "\n") + + +def load_systems(load=False): + load = not os.path.isfile("systems.db") + cache = sqlite3.connect("systems.db") + cache.row_factory = dict_factory + c = cache.cursor() + if load: + print("Caching Systems") + c.execute("DROP TABLE IF EXISTS systems") + c.execute( + "CREATE TABLE systems (id64 int primary key, name text, x real, y real, z real)" + ) + cache.commit() + recs = [] + for system in process_file("systemsWithCoordinates.json", True): + rec = [ + system["id64"], + system["name"], + system["coords"]["x"], + system["coords"]["y"], + system["coords"]["z"], + ] + recs.append(rec) + if len(recs) % 1024 * 1024 == 0: + c.executemany("INSERT INTO systems VALUES (?,?,?,?,?)", recs) + recs.clear() + c.executemany("INSERT INTO systems VALUES (?,?,?,?,?)", recs) + cache.commit() + return cache, c + + +if not os.path.isfile("stars.csv"): + cache, cur = load_systems() + rows = [] + with open("stars.csv", "w", newline="") as sys_csv: + csv_writer = csv.writer(sys_csv, dialect="excel") + for neut in process_file("stars.jl", True): + cur.execute( + "SELECT * FROM systems WHERE id64==?", (neut.get("systemId64"),) + ) + system = cur.fetchone() + if not system: + continue + row = [ + neut["systemId64"], + neut["subType"], + neut["name"], + get_mult(neut["subType"]), + system["x"], + system["y"], + system["z"], + ] + rows.append(row) + if len(rows) > 1024: + csv_writer.writerows(rows) + rows.clear() + csv_writer.writerows(rows) + print() + cache.close() + +if not os.path.isfile("stars.kdt"): + tqdm.pandas(ascii=True, leave=True) + print("Loading data...") + data = pd.read_csv( + "stars.csv", + encoding="utf-8", + names=["id", "type", "name", "mult", "x", "y", "z"], + ) + print("Cleaning data...") + data.type.fillna("Unknown", inplace=True) + data.drop_duplicates("id", inplace=True) + print("Writing CSV...") + data.to_csv("stars.csv", header=False, index=False) diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..c9ed87a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,272 @@ +extern crate csv; +extern crate serde; +#[macro_use] +extern crate serde_derive; + +extern crate fnv; +extern crate humantime; +use fnv::{FnvHashMap, FnvHashSet}; +use humantime::format_duration; +use rstar::{PointDistance, RTree, RTreeObject, AABB}; +use std::collections::VecDeque; +use std::hash::{Hash, Hasher}; +use std::io::Write; +use std::time::Instant; + +#[derive(Debug, Deserialize)] +struct Record { + id: i64, + star_type: String, + name: String, + mult: f32, + x: f32, + y: f32, + z: f32, +} +#[derive(Debug)] +struct System { + id: i64, + star_type: String, + name: String, + mult: f32, +} + +#[derive(Debug)] +struct Point { + id: i64, + x: f32, + y: f32, + z: f32, +} + +impl Point { + pub fn dist2(&self, p: &[f32; 3]) -> f32 { + let dx = self.x - p[0]; + let dy = self.y - p[1]; + let dz = self.z - p[2]; + + return dx * dx + dy * dy + dz * dz; + } + pub fn distp(&self, p: &Point) -> f32 { + return self.distp2(p).sqrt(); + } + pub fn distp2(&self, p: &Point) -> f32 { + return self.dist2(&[p.x, p.y, p.z]); + } +} +impl PartialEq for Point { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for Point {} + +impl Hash for Point { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl RTreeObject for Point { + type Envelope = AABB<[f32; 3]>; + + fn envelope(&self) -> Self::Envelope { + return AABB::from_point([self.x, self.y, self.z]); + } +} + +impl PointDistance for Point { + fn distance_2(&self, point: &[f32; 3]) -> f32 { + return self.dist2(&point); + } +} + +struct Router { + tree: RTree, + systems: FnvHashMap, + range: f32, + scoopable: FnvHashSet, +} + +impl Router { + pub fn new(path: &str, range: f32) -> Self { + let mut scoopable = FnvHashSet::default(); + let mut systems: FnvHashMap = FnvHashMap::default(); + let mut reader = csv::ReaderBuilder::new() + .has_headers(false) + .from_path(path) + .unwrap(); + println!("Loading {}...", path); + let points = reader + .deserialize() + .map(|res: Result| { + let sys = res.unwrap(); + systems.insert( + sys.id, + System { + id: sys.id, + star_type: sys.star_type.clone(), + name: sys.name, + mult: sys.mult, + }, + ); + if sys.mult > 1.0f32 { + scoopable.insert(sys.id); + } else { + for c in "KGBFOAM".chars() { + if sys.star_type.starts_with(c) { + scoopable.insert(sys.id); + break; + } + } + } + return Point { + x: sys.x, + y: sys.y, + z: sys.z, + id: sys.id, + }; + }) + .collect(); + return Self { + tree: RTree::::bulk_load(points), + systems, + range, + scoopable, + }; + } + + fn preload_points(&self) -> FnvHashMap { + let mut ret = FnvHashMap::default(); + for point in &self.tree { + ret.insert(point.id, point); + } + return ret; + } + + fn closest(&self, point: &[f32; 3]) -> &Point { + return self.tree.nearest_neighbor(point).unwrap(); + } + fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { + let center: [f32; 3] = *center; + return self + .tree + .locate_in_envelope(&AABB::from_corners( + [ + center[0] - radius * 1f32, + center[1] - radius * 1f32, + center[2] - radius * 1f32, + ], + [ + center[0] + radius * 1f32, + center[1] + radius * 1f32, + center[2] + radius * 1f32, + ], + )) + .filter(move |p| (p.dist2(¢er) < (radius * radius))); + } + + fn mult(&self, id: i64) -> f32 { + if let Some(sys) = self.systems.get(&id) { + return sys.mult; + }; + return 1.0; + } + fn neighbours(&self, sys: &Point) -> impl Iterator { + return self.points_in_sphere(&[sys.x, sys.y, sys.z], self.mult(sys.id) * self.range); + } + + fn valid(&self, sys: &Point) -> bool { + return self.scoopable.contains(&sys.id); + } + + pub fn route(&mut self, src: &[f32; 3], dst: &[f32; 3]) -> Vec<(&System, &Point)> { + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut depth = 0; + let mut queue: VecDeque<(usize, &Point)> = VecDeque::new(); + let mut r_queue: VecDeque<(usize, &Point)> = VecDeque::new(); + queue.push_front((0, &start_sys)); + r_queue.push_front((0, &goal_sys)); + seen.insert(start_sys.id); + while let Some((d, sys)) = queue.pop_front() { + if d != depth { + depth = d; + print!( + "\r[{}] Depth: {}, Queue: {}, Seen: {} ({:.2}%) ", + format_duration(t_start.elapsed()), + d, + queue.len(), + prev.len(), + ((prev.len() as f32) / total) * 100.0 + ); + std::io::stdout().flush().unwrap(); + } + if sys.id == goal_sys.id { + println!(); + let points = self.preload_points(); + let mut v: Vec<(&System, &Point)> = Vec::new(); + let mut prev_sys_id = sys.id; + loop { + if let Some(sys) = self.systems.get(&prev_sys_id) { + v.push((sys, points[&sys.id])); + } else { + break; + }; + match prev.get(&prev_sys_id) { + Some(sys_id) => prev_sys_id = *sys_id, + None => { + break; + } + } + } + v.reverse(); + return v; + } + let nbs = self + .neighbours(&sys) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))); + for nb in nbs { + if seen.insert(nb.id) { + prev.insert(nb.id, sys.id); + queue.push_back((d + 1, nb)); + } + } + } + println!("No route found!"); + return Vec::new(); + } +} + +fn main() { + let path = r#"D:\devel\files\python\EDSM\stars.csv"#; + let t_load = Instant::now(); + let mut router: Router = Router::new(path, 48.0); + println!("Done in {}!", format_duration(t_load.elapsed())); + let t_route = Instant::now(); + let route = router.route( + &[-65.21875, 7.75, -111.03125], // Ix + &[-1111.5625, -134.21875, 65269.75], // Beagle Point + // &[-7095.375, 401.25, 2396.8125], // V1357 Cygni, + ); // Ix -> BP 537 + println!( + "Done in {} ({} Jumps)!\n", + format_duration(t_route.elapsed()), + route.len() + ); + + let mut total: f32 = 0.0; + for ((sys1, p1), (_, p2)) in route.iter().zip(route.iter().skip(1)) { + let dist = p1.distp(p2); + total += dist; + println!("{} [{}]: {:.2} Ly", sys1.name, sys1.star_type, dist); + } + let sys = route.iter().last().unwrap().0; + println!("{} [{}]: {:.2} Ly\n", sys.name, sys.star_type, 0.0); + println!("Total: {:.2} Ly", total); +} From 4a4276f30f7f0d49b6a7a3a36c24ab85c1aeb48c Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Wed, 5 Jun 2019 23:17:00 +0000 Subject: [PATCH 02/72] Update README.md Fix formatting --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a65ba25..cd0a995 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ -# Elite: Dangerous Long Range Router (Rust Version) - -## Usage: - -#. run `download.sh` and `process.py` (you can hit Ctrl+C when it says "Building KD-Tree..") -#. edit source, destination and range in `src/main.rs` -#. (optional) `set RUSTFLAGS=-C target-cpu=native` (Windows) or `export RUSTFLAGS=-C target-cpu=native` (Linux) -#. `cargo run --release` - - - -## Dependencies - -- Python 3.7 - - Pandas - - uJSON -- Working nightly Rust Compiler (tested with `rustc 1.37.0-nightly (5d8f59f4b 2019-06-04)`) +# Elite: Dangerous Long Range Router (Rust Version) + +## Usage: + +1. run `download.sh` and `process.py` (you can hit Ctrl+C when it says "Building KD-Tree..") +1. edit source, destination and range in `src/main.rs` +1. (optional) `set RUSTFLAGS=-C target-cpu=native` (Windows) or `export RUSTFLAGS=-C target-cpu=native` (Linux) +1. `cargo run --release` + + + +## Dependencies + +- Python 3.7 + - Pandas + - uJSON +- Working nightly Rust Compiler (tested with `rustc 1.37.0-nightly (5d8f59f4b 2019-06-04)`) - ~8GB of free RAM \ No newline at end of file From f00237cb657fc31f87c982005e72569d57294f5b Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Thu, 6 Jun 2019 18:22:45 +0200 Subject: [PATCH 03/72] Add second queue to make paralellization easier --- src/main.rs | 98 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/main.rs b/src/main.rs index c9ed87a..572c243 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,8 @@ extern crate serde_derive; extern crate fnv; extern crate humantime; +// extern crate rayon; +// use rayon::prelude::*; use fnv::{FnvHashMap, FnvHashSet}; use humantime::format_duration; use rstar::{PointDistance, RTree, RTreeObject, AABB}; @@ -181,7 +183,7 @@ impl Router { return self.scoopable.contains(&sys.id); } - pub fn route(&mut self, src: &[f32; 3], dst: &[f32; 3]) -> Vec<(&System, &Point)> { + pub fn route(&mut self, src: &[f32; 3], dst: &[f32; 3]) -> Option> { let start_sys = self.closest(src); let goal_sys = self.closest(dst); let total = self.tree.size() as f32; @@ -189,57 +191,63 @@ impl Router { let mut seen = FnvHashSet::default(); let t_start = Instant::now(); let mut depth = 0; + let mut found = false; let mut queue: VecDeque<(usize, &Point)> = VecDeque::new(); - let mut r_queue: VecDeque<(usize, &Point)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, &Point)> = VecDeque::new(); queue.push_front((0, &start_sys)); - r_queue.push_front((0, &goal_sys)); seen.insert(start_sys.id); - while let Some((d, sys)) = queue.pop_front() { - if d != depth { - depth = d; - print!( - "\r[{}] Depth: {}, Queue: {}, Seen: {} ({:.2}%) ", - format_duration(t_start.elapsed()), - d, - queue.len(), - prev.len(), - ((prev.len() as f32) / total) * 100.0 - ); - std::io::stdout().flush().unwrap(); - } - if sys.id == goal_sys.id { - println!(); - let points = self.preload_points(); - let mut v: Vec<(&System, &Point)> = Vec::new(); - let mut prev_sys_id = sys.id; - loop { - if let Some(sys) = self.systems.get(&prev_sys_id) { - v.push((sys, points[&sys.id])); - } else { - break; - }; - match prev.get(&prev_sys_id) { - Some(sys_id) => prev_sys_id = *sys_id, - None => { - break; - } + while !queue.is_empty() { + while let Some((d, sys)) = queue.pop_front() { + if d != depth { + depth = d; + print!( + "\r[{}] Depth: {}, Queue: {}, Seen: {} ({:.2}%) ", + format_duration(t_start.elapsed()), + d, + queue.len(), + prev.len(), + ((prev.len() as f32) / total) * 100.0 + ); + std::io::stdout().flush().unwrap(); + } + if sys.id == goal_sys.id { + found = true; + break; + } + let nbs = self + .neighbours(&sys) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))); + for nb in nbs { + if seen.insert(nb.id) { + prev.insert(nb.id, sys.id); + queue_next.push_back((d + 1, nb)); } } - v.reverse(); - return v; } - let nbs = self - .neighbours(&sys) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))); - for nb in nbs { - if seen.insert(nb.id) { - prev.insert(nb.id, sys.id); - queue.push_back((d + 1, nb)); + std::mem::swap(&mut queue, &mut queue_next); + } + println!(); + if !found { + return None; + } + let points = self.preload_points(); + let mut v: Vec<(&System, &Point)> = Vec::new(); + let mut prev_sys_id = goal_sys.id; + loop { + if let Some(sys) = self.systems.get(&prev_sys_id) { + v.push((sys, points[&sys.id])); + } else { + break; + }; + match prev.get(&prev_sys_id) { + Some(sys_id) => prev_sys_id = *sys_id, + None => { + break; } } } - println!("No route found!"); - return Vec::new(); + v.reverse(); + return Some(v); } } @@ -254,6 +262,10 @@ fn main() { &[-1111.5625, -134.21875, 65269.75], // Beagle Point // &[-7095.375, 401.25, 2396.8125], // V1357 Cygni, ); // Ix -> BP 537 + let route = match route { + Some(r) => r, + None => Vec::new(), + }; println!( "Done in {} ({} Jumps)!\n", format_duration(t_route.elapsed()), From 8e8587a335ca15c5f29c82d9ebcc6bb999f92d92 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sun, 9 Jun 2019 04:08:31 +0200 Subject: [PATCH 04/72] Update main.rs and process.py process.py: - Add hint for file download when input files are missing main.rs - Add multi-hop-routing - Add searching for source and destination by name --- download.sh | 3 - process.py => dumps/process.py | 10 +- src/main.rs | 161 +++++++++++++++++++++++---------- 3 files changed, 123 insertions(+), 51 deletions(-) delete mode 100644 download.sh rename process.py => dumps/process.py (90%) diff --git a/download.sh b/download.sh deleted file mode 100644 index ea5226e..0000000 --- a/download.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/bash -rm systemsWithCoordinates.json bodies.json *.aria2 -wget https://www.edsm.net/dump/systemsWithCoordinates.json https://www.edsm.net/dump/bodies.json \ No newline at end of file diff --git a/process.py b/dumps/process.py similarity index 90% rename from process.py rename to dumps/process.py index 6416cbc..02b8102 100644 --- a/process.py +++ b/dumps/process.py @@ -7,6 +7,7 @@ import sys import csv import sqlite3 import pandas as pd +from urllib.parse import urljoin def is_scoopable(entry): @@ -89,8 +90,15 @@ def process_file(fn, show_progbar=False): yield line +if not ( + os.path.isfile("bodies.json") and os.path.isfile("systemsWithCoordinates.json") +): + exit( + "Please download bodies.json and systemsWithCoordinates.json from https://www.edsm.net/en/nightly-dumps/" + ) + if not os.path.isfile("stars.jl"): - print("Filtering for Neutron Stars") + print("Filtering for Stars") with open("stars.jl", "w") as neut: for body in process_file("bodies.json", True): T = body.get("type") or "" diff --git a/src/main.rs b/src/main.rs index 572c243..fec16cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,8 @@ extern crate csv; extern crate serde; #[macro_use] extern crate serde_derive; - extern crate fnv; extern crate humantime; -// extern crate rayon; -// use rayon::prelude::*; use fnv::{FnvHashMap, FnvHashSet}; use humantime::format_duration; use rstar::{PointDistance, RTree, RTreeObject, AABB}; @@ -25,7 +22,7 @@ struct Record { y: f32, z: f32, } -#[derive(Debug)] +#[derive(Debug, Clone)] struct System { id: i64, star_type: String, @@ -33,7 +30,7 @@ struct System { mult: f32, } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] struct Point { id: i64, x: f32, @@ -41,6 +38,14 @@ struct Point { z: f32, } +fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + let dx = p1[0] - p2[0]; + let dy = p1[1] - p2[1]; + let dz = p1[2] - p2[2]; + + return (dx * dx + dy * dy + dz * dz).sqrt(); +} + impl Point { pub fn dist2(&self, p: &[f32; 3]) -> f32 { let dx = self.x - p[0]; @@ -87,12 +92,11 @@ impl PointDistance for Point { struct Router { tree: RTree, systems: FnvHashMap, - range: f32, scoopable: FnvHashSet, } impl Router { - pub fn new(path: &str, range: f32) -> Self { + pub fn new(path: &str) -> Self { let mut scoopable = FnvHashSet::default(); let mut systems: FnvHashMap = FnvHashMap::default(); let mut reader = csv::ReaderBuilder::new() @@ -134,7 +138,6 @@ impl Router { return Self { tree: RTree::::bulk_load(points), systems, - range, scoopable, }; } @@ -175,17 +178,88 @@ impl Router { }; return 1.0; } - fn neighbours(&self, sys: &Point) -> impl Iterator { - return self.points_in_sphere(&[sys.x, sys.y, sys.z], self.mult(sys.id) * self.range); + fn neighbours(&self, sys: &Point, r: f32) -> impl Iterator { + return self.points_in_sphere(&[sys.x, sys.y, sys.z], self.mult(sys.id) * r); } fn valid(&self, sys: &Point) -> bool { return self.scoopable.contains(&sys.id); } - pub fn route(&mut self, src: &[f32; 3], dst: &[f32; 3]) -> Option> { + pub fn name_multiroute(&self, waypoints: &[&str], range: f32) -> Vec<(&System, &Point)> { + let mut coords = Vec::new(); + for p in waypoints { + let p = self.name_to_point(p); + let s = [p.x, p.y, p.z]; + coords.push(s); + } + return self.multiroute(coords.as_slice(), range); + } + pub fn multiroute(&self, waypoints: &[[f32; 3]], range: f32) -> Vec<(&System, &Point)> { + let mut route = Vec::new(); + for pair in waypoints.windows(2) { + match pair { + &[src, dst] => { + let block = self.route(&src, &dst, range); + if route.is_empty() { + route.extend(block.iter()); + } else { + route.extend(block.iter().skip(1)); + } + } + _ => panic!("Invalid routing parameters!"), + } + } + return route; + } + + fn sys_to_point(&self, id: i64) -> Option<&Point> { + for p in &self.tree { + if p.id == id { + return Some(p); + } + } + return None; + } + + fn name_to_point(&self, name: &str) -> &Point { + for sys in self.systems.values() { + if sys.name == name { + return self.sys_to_point(sys.id).unwrap(); + } + } + eprintln!("Sytem not found: {}", name); + std::process::exit(1); + } + + pub fn route_by_name(&self, src: &str, dst: &str, range: f32) -> Vec<(&System, &Point)> { + let start_sys = self.name_to_point(src); + let goal_sys = self.name_to_point(dst); + return self.route( + &[start_sys.x, start_sys.y, start_sys.z], + &[goal_sys.x, goal_sys.y, goal_sys.z], + range, + ); + } + + pub fn route(&self, src: &[f32; 3], dst: &[f32; 3], range: f32) -> Vec<(&System, &Point)> { let start_sys = self.closest(src); let goal_sys = self.closest(dst); + { + let d = dist(src, dst); + let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); + let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); + println!( + "Computing route from {} to {}...", + start_sys_name, goal_sys_name + ); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } let total = self.tree.size() as f32; let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); @@ -197,42 +271,41 @@ impl Router { queue.push_front((0, &start_sys)); seen.insert(start_sys.id); while !queue.is_empty() { + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); while let Some((d, sys)) = queue.pop_front() { - if d != depth { - depth = d; - print!( - "\r[{}] Depth: {}, Queue: {}, Seen: {} ({:.2}%) ", - format_duration(t_start.elapsed()), - d, - queue.len(), - prev.len(), - ((prev.len() as f32) / total) * 100.0 - ); - std::io::stdout().flush().unwrap(); - } if sys.id == goal_sys.id { found = true; break; } - let nbs = self - .neighbours(&sys) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))); - for nb in nbs { - if seen.insert(nb.id) { - prev.insert(nb.id, sys.id); - queue_next.push_back((d + 1, nb)); - } - } + queue_next.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys.id); + return (d + 1, nb); + }), + ); } std::mem::swap(&mut queue, &mut queue_next); + depth += 1; } println!(); if !found { - return None; + return Vec::new(); } let points = self.preload_points(); let mut v: Vec<(&System, &Point)> = Vec::new(); let mut prev_sys_id = goal_sys.id; + let prev = prev; loop { if let Some(sys) = self.systems.get(&prev_sys_id) { v.push((sys, points[&sys.id])); @@ -247,36 +320,30 @@ impl Router { } } v.reverse(); - return Some(v); + return v; } } fn main() { let path = r#"D:\devel\files\python\EDSM\stars.csv"#; let t_load = Instant::now(); - let mut router: Router = Router::new(path, 48.0); + let router: Router = Router::new(path); println!("Done in {}!", format_duration(t_load.elapsed())); let t_route = Instant::now(); - let route = router.route( - &[-65.21875, 7.75, -111.03125], // Ix - &[-1111.5625, -134.21875, 65269.75], // Beagle Point - // &[-7095.375, 401.25, 2396.8125], // V1357 Cygni, - ); // Ix -> BP 537 - let route = match route { - Some(r) => r, - None => Vec::new(), - }; + let route = router.name_multiroute(&["Ix", "Colonia", "Sol"], 48.0); println!( "Done in {} ({} Jumps)!\n", format_duration(t_route.elapsed()), - route.len() + route.len(), ); - let mut total: f32 = 0.0; for ((sys1, p1), (_, p2)) in route.iter().zip(route.iter().skip(1)) { let dist = p1.distp(p2); total += dist; - println!("{} [{}]: {:.2} Ly", sys1.name, sys1.star_type, dist); + println!( + "{} [{}] ({},{},{}): {:.2} Ly", + sys1.name, sys1.star_type, p1.x, p1.y, p1.z, dist + ); } let sys = route.iter().last().unwrap().0; println!("{} [{}]: {:.2} Ly\n", sys.name, sys.star_type, 0.0); From ffdd1bb7a29b95000ac06933c100827b5881b08c Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Thu, 13 Jun 2019 01:49:05 +0200 Subject: [PATCH 05/72] Add usable CLI --- Cargo.lock | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 3 +- src/main.rs | 65 +++++++++++++-------- 3 files changed, 205 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 416bf99..c903725 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,47 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "csv" version = "1.0.7" @@ -25,7 +62,7 @@ dependencies = [ ] [[package]] -name = "ed_ldr" +name = "ed_lrr" version = "0.1.0" dependencies = [ "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -34,6 +71,7 @@ dependencies = [ "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -46,6 +84,14 @@ name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "humantime" version = "1.2.0" @@ -88,6 +134,11 @@ dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pdqselect" version = "0.1.0" @@ -114,6 +165,19 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_syscall" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rstar" version = "0.4.0" @@ -144,6 +208,31 @@ dependencies = [ "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "structopt" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.15.34" @@ -154,30 +243,102 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termion" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-segmentation" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd08ae4f9661517777346592956ea6cdbba2895a28037af7daa600382f4b4001" "checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" "checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" "checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" +"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" "checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" +"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index a874f2a..b8e7814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ed_ldr" +name = "ed_lrr" version = "0.1.0" authors = ["Daniel Seiller "] edition = "2018" @@ -14,3 +14,4 @@ serde_derive = "1.0.92" rstar = "0.4.0" humantime = "1.2.0" fnv = "1.0.6" +structopt = "0.2.16" diff --git a/src/main.rs b/src/main.rs index fec16cd..49f659b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ extern crate csv; extern crate serde; #[macro_use] +extern crate structopt; +#[macro_use] extern crate serde_derive; extern crate fnv; extern crate humantime; @@ -10,7 +12,9 @@ use rstar::{PointDistance, RTree, RTreeObject, AABB}; use std::collections::VecDeque; use std::hash::{Hash, Hasher}; use std::io::Write; +use std::path::PathBuf; use std::time::Instant; +use structopt::StructOpt; #[derive(Debug, Deserialize)] struct Record { @@ -37,7 +41,24 @@ struct Point { y: f32, z: f32, } - +#[derive(Debug, StructOpt)] +#[structopt(name = "ed_lrr", about = "Elite: Dangerous Long-Range Router")] +/// Plots a route through multiple systems using breadth-first search (Currently needs a lot of RAM (8+GB), sorry) +struct Opt { + #[structopt(short = "r", long = "range")] + /// Jump Range + range: f32, + #[structopt( + parse(from_os_str), + short = "p", + long = "path", + default_value = "./stars.csv" + )] + /// Path to stars.csv + file_path: PathBuf, + /// Systems to route through + systems: Vec, +} fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { let dx = p1[0] - p2[0]; let dy = p1[1] - p2[1]; @@ -96,14 +117,17 @@ struct Router { } impl Router { - pub fn new(path: &str) -> Self { + pub fn new(path: &PathBuf) -> Self { let mut scoopable = FnvHashSet::default(); let mut systems: FnvHashMap = FnvHashMap::default(); let mut reader = csv::ReaderBuilder::new() .has_headers(false) .from_path(path) - .unwrap(); - println!("Loading {}...", path); + .unwrap_or_else(|e| { + println!("Error loading {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + println!("Loading {}...", path.to_str().unwrap()); let points = reader .deserialize() .map(|res: Result| { @@ -186,7 +210,7 @@ impl Router { return self.scoopable.contains(&sys.id); } - pub fn name_multiroute(&self, waypoints: &[&str], range: f32) -> Vec<(&System, &Point)> { + pub fn name_multiroute(&self, waypoints: &Vec, range: f32) -> Vec<(&System, &Point)> { let mut coords = Vec::new(); for p in waypoints { let p = self.name_to_point(p); @@ -228,20 +252,10 @@ impl Router { return self.sys_to_point(sys.id).unwrap(); } } - eprintln!("Sytem not found: {}", name); + eprintln!("Sytem not found: \"{}\"", name); std::process::exit(1); } - pub fn route_by_name(&self, src: &str, dst: &str, range: f32) -> Vec<(&System, &Point)> { - let start_sys = self.name_to_point(src); - let goal_sys = self.name_to_point(dst); - return self.route( - &[start_sys.x, start_sys.y, start_sys.z], - &[goal_sys.x, goal_sys.y, goal_sys.z], - range, - ); - } - pub fn route(&self, src: &[f32; 3], dst: &[f32; 3], range: f32) -> Vec<(&System, &Point)> { let start_sys = self.closest(src); let goal_sys = self.closest(dst); @@ -250,7 +264,7 @@ impl Router { let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); println!( - "Computing route from {} to {}...", + "Plotting route from {} to {}...", start_sys_name, goal_sys_name ); println!( @@ -270,7 +284,7 @@ impl Router { let mut queue_next: VecDeque<(usize, &Point)> = VecDeque::new(); queue.push_front((0, &start_sys)); seen.insert(start_sys.id); - while !queue.is_empty() { + while !(queue.is_empty() || found) { print!( "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", format_duration(t_start.elapsed()), @@ -305,7 +319,6 @@ impl Router { let points = self.preload_points(); let mut v: Vec<(&System, &Point)> = Vec::new(); let mut prev_sys_id = goal_sys.id; - let prev = prev; loop { if let Some(sys) = self.systems.get(&prev_sys_id) { v.push((sys, points[&sys.id])); @@ -325,12 +338,13 @@ impl Router { } fn main() { - let path = r#"D:\devel\files\python\EDSM\stars.csv"#; + let opts = Opt::from_args(); + let path = opts.file_path; let t_load = Instant::now(); - let router: Router = Router::new(path); + let router: Router = Router::new(&path); println!("Done in {}!", format_duration(t_load.elapsed())); let t_route = Instant::now(); - let route = router.name_multiroute(&["Ix", "Colonia", "Sol"], 48.0); + let route = router.name_multiroute(&opts.systems, opts.range); println!( "Done in {} ({} Jumps)!\n", format_duration(t_route.elapsed()), @@ -345,7 +359,10 @@ fn main() { sys1.name, sys1.star_type, p1.x, p1.y, p1.z, dist ); } - let sys = route.iter().last().unwrap().0; - println!("{} [{}]: {:.2} Ly\n", sys.name, sys.star_type, 0.0); + let (sys, p) = route.iter().last().unwrap(); + println!( + "{} [{}] ({},{},{}): {:.2} Ly", + sys.name, sys.star_type, p.x, p.y, p.z, 0.0 + ); println!("Total: {:.2} Ly", total); } From afae1c08b5aa3a81978dccd432110c8ea97ed0be Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 17 Jun 2019 01:46:24 +0200 Subject: [PATCH 06/72] Big Update Add A*-Routing with tunable Greedy factor Add Greedy-Routing Add permutation option to find shortest order for systems Update CLI Update README --- Cargo.lock | 7 + Cargo.toml | 8 +- README.md | 8 +- src/main.rs | 408 +++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 392 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c903725..a5bbd6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,6 +68,7 @@ dependencies = [ "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", @@ -144,6 +145,11 @@ name = "pdqselect" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "permutohedron" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "0.4.30" @@ -320,6 +326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" +"checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" diff --git a/Cargo.toml b/Cargo.toml index b8e7814..05abe0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,12 @@ name = "ed_lrr" version = "0.1.0" authors = ["Daniel Seiller "] edition = "2018" +repository = "https://gitlab.com/Earthnuker/ed_lrr.git" +license = "WTFPL" -# [profile.release] -# debug = true +[[bin]] +name = "ed_lrr" +path = "src/main.rs" [dependencies] csv = "1.0.7" @@ -15,3 +18,4 @@ rstar = "0.4.0" humantime = "1.2.0" fnv = "1.0.6" structopt = "0.2.16" +permutohedron = "0.2.4" diff --git a/README.md b/README.md index cd0a995..4107199 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ ## Usage: -1. run `download.sh` and `process.py` (you can hit Ctrl+C when it says "Building KD-Tree..") -1. edit source, destination and range in `src/main.rs` -1. (optional) `set RUSTFLAGS=-C target-cpu=native` (Windows) or `export RUSTFLAGS=-C target-cpu=native` (Linux) -1. `cargo run --release` +1. download `bodies.json` and `systemsWithCoordinates.json` from https://www.edsm.net/en/nightly-dumps/ and place them in the `dumps` folder +2. run `process.py` in the `dumps` folder +3. run `cargo install --git https://gitlab.com/Earthnuker/ed_lrr.git` +4. run `ed_lrr --help` diff --git a/src/main.rs b/src/main.rs index 49f659b..88843c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,21 @@ extern crate csv; extern crate serde; -#[macro_use] extern crate structopt; #[macro_use] extern crate serde_derive; extern crate fnv; extern crate humantime; +extern crate permutohedron; +use core::cmp::Ordering; use fnv::{FnvHashMap, FnvHashSet}; use humantime::format_duration; +use permutohedron::LexicalPermutation; use rstar::{PointDistance, RTree, RTreeObject, AABB}; use std::collections::VecDeque; use std::hash::{Hash, Hasher}; use std::io::Write; use std::path::PathBuf; +use std::str::FromStr; use std::time::Instant; use structopt::StructOpt; @@ -41,21 +44,73 @@ struct Point { y: f32, z: f32, } + +#[derive(Debug)] +enum Mode { + BFS, + Greedy, + AStar, +} + +impl FromStr for Mode { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "bfs" => Ok(Mode::BFS), + "greedy" => Ok(Mode::Greedy), + "astar" => Ok(Mode::AStar), + _ => Err("Invalid Mode".to_string()), + } + } +} + #[derive(Debug, StructOpt)] -#[structopt(name = "ed_lrr", about = "Elite: Dangerous Long-Range Router")] -/// Plots a route through multiple systems using breadth-first search (Currently needs a lot of RAM (8+GB), sorry) +#[structopt( + name = "ed_lrr", + about = "Elite: Dangerous Long-Range Router", + rename_all = "kebab-case" +)] +/// Plots a route through multiple systems using breadth-first search (Currently needs a lot of RAM (about 6GB), sorry) struct Opt { - #[structopt(short = "r", long = "range")] + #[structopt(short, long = "range")] /// Jump Range range: f32, #[structopt( parse(from_os_str), - short = "p", + short = "f", long = "path", default_value = "./stars.csv" )] /// Path to stars.csv + /// + /// Generate using process.py (https://gitlab.com/Earthnuker/ed_lrr/raw/master/dumps/process.py) file_path: PathBuf, + + #[structopt(short = "p", long = "permute", conflicts_with = "full_permute")] + /// Permute intermediate hops to find shortest route + permute: bool, + + #[structopt(short = "fp", long = "full_permute", conflicts_with = "permute")] + /// Permute all hops to find shortest route + full_permute: bool, + + #[structopt(short = "g", long = "factor")] + /// Greedyness factor for A-Star (0=BFS, inf=Greedy) + factor: Option, + + #[structopt( + short, + long = "mode", + raw(possible_values = "&[\"bfs\", \"greedy\",\"astar\"]") + )] + /// Search mode + /// + /** + - BFS is guaranteed to find the shortest route but very slow + - Greedy is a lot faster but will probably not find the shortest route + - A-Star is a good middle ground between speed and accuracy + */ + mode: Mode, /// Systems to route through systems: Vec, } @@ -67,6 +122,15 @@ fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { return (dx * dx + dy * dy + dz * dz).sqrt(); } +fn fcmp(a: &f32, b: &f32) -> Ordering { + match (a, b) { + (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, + (x, _) if x.is_nan() => Ordering::Greater, + (_, y) if y.is_nan() => Ordering::Less, + (..) => a.partial_cmp(&b).unwrap(), + } +} + impl Point { pub fn dist2(&self, p: &[f32; 3]) -> f32 { let dx = self.x - p[0]; @@ -178,22 +242,7 @@ impl Router { return self.tree.nearest_neighbor(point).unwrap(); } fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { - let center: [f32; 3] = *center; - return self - .tree - .locate_in_envelope(&AABB::from_corners( - [ - center[0] - radius * 1f32, - center[1] - radius * 1f32, - center[2] - radius * 1f32, - ], - [ - center[0] + radius * 1f32, - center[1] + radius * 1f32, - center[2] + radius * 1f32, - ], - )) - .filter(move |p| (p.dist2(¢er) < (radius * radius))); + return self.tree.locate_within_distance(*center, radius * radius); } fn mult(&self, id: i64) -> f32 { @@ -210,21 +259,82 @@ impl Router { return self.scoopable.contains(&sys.id); } - pub fn name_multiroute(&self, waypoints: &Vec, range: f32) -> Vec<(&System, &Point)> { + pub fn best_name_multiroute( + &self, + waypoints: &Vec, + range: f32, + full: bool, + mode: Mode, + factor: f32, + ) -> Vec<(&System, &Point)> { + let mut best_score: f32 = std::f32::MAX; + let mut waypoints = waypoints.clone(); + let mut best_permutation_waypoints = waypoints.clone(); + let first = waypoints.first().cloned(); + let last = waypoints.last().cloned(); + let t_start = Instant::now(); + println!("Finding best permutation of hops..."); + while waypoints.prev_permutation() {} + loop { + let c_first = waypoints.first().cloned(); + let c_last = waypoints.last().cloned(); + if full || ((c_first == first) && (c_last == last)) { + let mut total_d = 0.0; + for pair in waypoints.windows(2) { + match pair { + [src, dst] => { + let (src, dst) = (self.name_to_point(&src), self.name_to_point(&dst)); + total_d += src.distp2(dst); + } + _ => panic!("Invalid routing parameters!"), + } + } + if total_d < best_score { + best_score = total_d; + best_permutation_waypoints = waypoints.clone(); + } + } + if !waypoints.next_permutation() { + break; + } + } + + println!("Done in {}!", format_duration(t_start.elapsed())); + println!("Best permutation: {:?}", best_permutation_waypoints); + return self.name_multiroute(&best_permutation_waypoints, range, mode, factor); + } + + pub fn name_multiroute( + &self, + waypoints: &Vec, + range: f32, + mode: Mode, + factor: f32, + ) -> Vec<(&System, &Point)> { let mut coords = Vec::new(); for p in waypoints { let p = self.name_to_point(p); let s = [p.x, p.y, p.z]; coords.push(s); } - return self.multiroute(coords.as_slice(), range); + return self.multiroute(coords.as_slice(), range, mode, factor); } - pub fn multiroute(&self, waypoints: &[[f32; 3]], range: f32) -> Vec<(&System, &Point)> { + pub fn multiroute( + &self, + waypoints: &[[f32; 3]], + range: f32, + mode: Mode, + factor: f32, + ) -> Vec<(&System, &Point)> { let mut route = Vec::new(); for pair in waypoints.windows(2) { match pair { &[src, dst] => { - let block = self.route(&src, &dst, range); + let block = match mode { + Mode::BFS => self.route_bfs(&src, &dst, range), + Mode::Greedy => self.route_greedy(&src, &dst, range), + Mode::AStar => self.route_astar(&src, &dst, range, factor), + }; if route.is_empty() { route.extend(block.iter()); } else { @@ -237,32 +347,241 @@ impl Router { return route; } - fn sys_to_point(&self, id: i64) -> Option<&Point> { + fn sys_to_point(&self, id: i64) -> &Point { for p in &self.tree { if p.id == id { - return Some(p); + return p; } } - return None; + eprintln!("Sytem-ID not found: \"{}\"", id); + std::process::exit(1); } fn name_to_point(&self, name: &str) -> &Point { for sys in self.systems.values() { if sys.name == name { - return self.sys_to_point(sys.id).unwrap(); + return self.sys_to_point(sys.id); } } eprintln!("Sytem not found: \"{}\"", name); std::process::exit(1); } - pub fn route(&self, src: &[f32; 3], dst: &[f32; 3], range: f32) -> Vec<(&System, &Point)> { + pub fn route_astar( + &self, + src: &[f32; 3], + dst: &[f32; 3], + range: f32, + factor: f32, + ) -> Vec<(&System, &Point)> { + if factor == 0.0 { + return self.route_bfs(src, dst, range); + } + println!("Running A-Star with greedy factor of {}", factor); let start_sys = self.closest(src); let goal_sys = self.closest(dst); + let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); + let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); + { + let d = dist(src, dst); + println!( + "Plotting route from {} to {}...", + start_sys_name, goal_sys_name + ); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut found = false; + let mut maxd = 0; + let mut queue: Vec<(usize, usize, &Point)> = Vec::new(); + queue.push(( + 0, // depth + (start_sys.distp(goal_sys) / range) as usize, // h + &start_sys, + )); + seen.insert(start_sys.id); + + while !(queue.is_empty() || found) { + while let Some((depth, _, sys)) = queue.pop() { + if depth > maxd { + maxd = depth; + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + } + if sys.id == goal_sys.id { + found = true; + break; + } + queue.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys.id); + let d_g = (nb.distp(goal_sys) / range) as usize; + return (depth + 1, d_g, nb); + }), + ); + queue.sort_by(|b, a| { + let (a_0, a_1) = (a.0 as f32, a.1 as f32); + let (b_0, b_1) = (b.0 as f32, b.1 as f32); + let v_a = a_0 + a_1 * factor; + let v_b = b_0 + b_1 * factor; + return fcmp(&v_a, &v_b); + }); + // queue.reverse(); + } + } + println!(); + + println!(); + if !found { + eprintln!( + "No route from {} to {} found!", + start_sys_name, goal_sys_name + ); + return Vec::new(); + } + let points = self.preload_points(); + let mut v: Vec<(&System, &Point)> = Vec::new(); + let mut prev_sys_id = goal_sys.id; + loop { + if let Some(sys) = self.systems.get(&prev_sys_id) { + v.push((sys, points[&sys.id])); + } else { + break; + }; + match prev.get(&prev_sys_id) { + Some(sys_id) => prev_sys_id = *sys_id, + None => { + break; + } + } + } + v.reverse(); + return v; + } + + pub fn route_greedy( + &self, + src: &[f32; 3], + dst: &[f32; 3], + range: f32, + ) -> Vec<(&System, &Point)> { + println!("Running Greedy-Search"); + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); + let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); + { + let d = dist(src, dst); + println!( + "Plotting route from {} to {}...", + start_sys_name, goal_sys_name + ); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut found = false; + let mut maxd = 0; + let mut queue: Vec<(f32, f32, usize, &Point)> = Vec::new(); + queue.push(( + -self.mult(goal_sys.id), + start_sys.distp2(goal_sys), + 0, + &start_sys, + )); + seen.insert(start_sys.id); + while !(queue.is_empty() || found) { + std::io::stdout().flush().unwrap(); + while let Some((_, _, depth, sys)) = queue.pop() { + if depth > maxd { + maxd = depth; + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + } + if sys.id == goal_sys.id { + found = true; + break; + } + queue.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys.id); + return (-self.mult(nb.id), nb.distp2(goal_sys), depth + 1, nb); + }), + ); + queue.sort_by(|a, b| fcmp(&a.0, &b.0).then(fcmp(&a.1, &b.1))); + queue.reverse(); + } + } + println!(); + if !found { + eprintln!( + "No route from {} to {} found!", + start_sys_name, goal_sys_name + ); + return Vec::new(); + } + let points = self.preload_points(); + let mut v: Vec<(&System, &Point)> = Vec::new(); + let mut prev_sys_id = goal_sys.id; + loop { + if let Some(sys) = self.systems.get(&prev_sys_id) { + v.push((sys, points[&sys.id])); + } else { + break; + }; + match prev.get(&prev_sys_id) { + Some(sys_id) => prev_sys_id = *sys_id, + None => { + break; + } + } + } + v.reverse(); + return v; + } + + pub fn route_bfs(&self, src: &[f32; 3], dst: &[f32; 3], range: f32) -> Vec<(&System, &Point)> { + println!("Running BFS"); + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); + let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); { let d = dist(src, dst); - let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); - let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); println!( "Plotting route from {} to {}...", start_sys_name, goal_sys_name @@ -314,6 +633,10 @@ impl Router { } println!(); if !found { + eprintln!( + "No route from {} to {} found!", + start_sys_name, goal_sys_name + ); return Vec::new(); } let points = self.preload_points(); @@ -344,12 +667,31 @@ fn main() { let router: Router = Router::new(&path); println!("Done in {}!", format_duration(t_load.elapsed())); let t_route = Instant::now(); - let route = router.name_multiroute(&opts.systems, opts.range); + let route = if opts.permute || opts.full_permute { + router.best_name_multiroute( + &opts.systems, + opts.range, + opts.full_permute, + opts.mode, + opts.factor.unwrap_or(1.0), + ) + } else { + router.name_multiroute( + &opts.systems, + opts.range, + opts.mode, + opts.factor.unwrap_or(1.0), + ) + }; println!( "Done in {} ({} Jumps)!\n", format_duration(t_route.elapsed()), route.len(), ); + if route.len() == 0 { + eprintln!("No route found!"); + return; + } let mut total: f32 = 0.0; for ((sys1, p1), (_, p2)) in route.iter().zip(route.iter().skip(1)) { let dist = p1.distp(p2); From ed53d5a3f0d8cad6cd91f5983f2a703aa0fd08ce Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 17 Jun 2019 01:51:37 +0200 Subject: [PATCH 07/72] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4107199..3172f13 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ 1. download `bodies.json` and `systemsWithCoordinates.json` from https://www.edsm.net/en/nightly-dumps/ and place them in the `dumps` folder 2. run `process.py` in the `dumps` folder -3. run `cargo install --git https://gitlab.com/Earthnuker/ed_lrr.git` -4. run `ed_lrr --help` +3. run `cargo install --path .` or `cargo install --git https://gitlab.com/Earthnuker/ed_lrr.git` +5. run `ed_lrr --help` From d42121c33bf36f284421bc76fd71195c52395ffb Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 17 Jun 2019 02:22:45 +0200 Subject: [PATCH 08/72] Update main.rs move stdout flush in Greedy-Search to after print statement --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 88843c6..efa6305 100644 --- a/src/main.rs +++ b/src/main.rs @@ -516,7 +516,6 @@ impl Router { )); seen.insert(start_sys.id); while !(queue.is_empty() || found) { - std::io::stdout().flush().unwrap(); while let Some((_, _, depth, sys)) = queue.pop() { if depth > maxd { maxd = depth; @@ -528,6 +527,7 @@ impl Router { seen.len(), ((seen.len() * 100) as f32) / total ); + std::io::stdout().flush().unwrap(); } if sys.id == goal_sys.id { found = true; From 84bc08a2e1cd13ebbeee2488a6792d73f840ccdd Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 29 Jun 2019 10:32:47 +0200 Subject: [PATCH 09/72] Big update - Add ed_lrr_pp to preprocess JSON-Dumps into CSV files - Add route-graph-precomputation to ed_lrr - Add option to only route through primary stars --- .cargo/config | 2 + .gitignore | 6 +- Cargo.lock | 543 ++++++++++++++++++++++++++++++++++--- Cargo.toml | 21 +- README.md | 14 +- dumps/process.py | 2 +- dumps/urls.txt | 2 + src/bin/ed_lrr_pp.rs | 188 +++++++++++++ src/main.rs | 632 ++++++++++++++++++++++++++----------------- 9 files changed, 1109 insertions(+), 301 deletions(-) create mode 100644 .cargo/config create mode 100644 dumps/urls.txt create mode 100644 src/bin/ed_lrr_pp.rs diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..f0b7483 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "target-cpu=native"] \ No newline at end of file diff --git a/.gitignore b/.gitignore index 832207a..ac00f51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ /target **/*.rs.bk -.vscode/** \ No newline at end of file +.vscode/** +*.csv +*.router +dumps/*.json +plot.py diff --git a/Cargo.lock b/Cargo.lock index a5bbd6e..67bca1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,13 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -13,8 +21,8 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -23,11 +31,66 @@ name = "autocfg" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bincode" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bstr" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "clap" version = "2.33.0" @@ -43,36 +106,85 @@ dependencies = [ ] [[package]] -name = "csv" -version = "1.0.7" +name = "clicolors-control" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "console" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "csv-core" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "digest" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ed_lrr" version = "0.1.0" dependencies = [ - "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -80,11 +192,29 @@ name = "either" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "encode_unicode" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "heck" version = "0.3.1" @@ -101,6 +231,18 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indicatif" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.8.0" @@ -115,16 +257,34 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "libc" -version = "0.2.55" +name = "keccak" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lock_api" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "memchr" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -135,11 +295,49 @@ dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "number_prefix" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "numtoa" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "opaque-debug" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "parking_lot" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pdqselect" version = "0.1.0" @@ -171,6 +369,110 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.54" @@ -184,6 +486,34 @@ dependencies = [ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-automata" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rstar" version = "0.4.0" @@ -192,6 +522,15 @@ dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -200,20 +539,73 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "serde" -version = "1.0.92" +name = "ryu" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_derive" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_json" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "smallvec" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "strsim" version = "0.8.0" @@ -221,27 +613,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.34" +version = "0.15.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -251,15 +643,23 @@ dependencies = [ [[package]] name = "termion" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termios" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -268,6 +668,24 @@ dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ucd-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-segmentation" version = "1.3.0" @@ -283,6 +701,11 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "utf8-ranges" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.1" @@ -308,43 +731,93 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" +"checksum bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc0572e02f76cb335f309b19e0a0d585b4f62788f7d26de2a13a836a637385f" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" -"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" +"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" +"checksum csv 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a54cd62557f353f140b42305fb4efcff2ae08e32fbabaf5b0929423000febb63" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" +"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" +"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" +"checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86" +"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" "checksum rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd08ae4f9661517777346592956ea6cdbba2895a28037af7daa600382f4b4001" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" -"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" -"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b" +"checksum serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "ef45eb79d6463b22f5f9e16d283798b7c0175ba6050bc25c1a946c122727fe7b" +"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" +"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff" -"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f" -"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe" -"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" +"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +"checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" +"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" +"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" diff --git a/Cargo.toml b/Cargo.toml index 05abe0f..0283f87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,16 +6,19 @@ edition = "2018" repository = "https://gitlab.com/Earthnuker/ed_lrr.git" license = "WTFPL" -[[bin]] -name = "ed_lrr" -path = "src/main.rs" +[profile.release] +# debug=true [dependencies] -csv = "1.0.7" -serde = "1.0.92" -serde_derive = "1.0.92" -rstar = "0.4.0" +csv = "1.1.0" +serde = "1.0.94" +serde_derive = "1.0.94" +rstar = {version="0.4.0",features=["serde"]} humantime = "1.2.0" -fnv = "1.0.6" -structopt = "0.2.16" +structopt = "0.2.18" permutohedron = "0.2.4" +serde_json = "1.0.39" +indicatif = "0.11.0" +fnv = "1.0.6" +bincode = "1.1.4" +sha3 = "0.8.2" diff --git a/README.md b/README.md index 3172f13..46f73b0 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,18 @@ ## Usage: 1. download `bodies.json` and `systemsWithCoordinates.json` from https://www.edsm.net/en/nightly-dumps/ and place them in the `dumps` folder -2. run `process.py` in the `dumps` folder -3. run `cargo install --path .` or `cargo install --git https://gitlab.com/Earthnuker/ed_lrr.git` -5. run `ed_lrr --help` +2. run `cargo install --path .` or `cargo install --git https://gitlab.com/Earthnuker/ed_lrr.git` +3. run `ed_lrr_pp --bodies dumps/bodies.json --systems dumps/systemsWithCoordinates.json` + - Alternatively run `proces.py` in the `dumps` folder +4. run `ed_lrr --help` ## Dependencies -- Python 3.7 +- Working nightly Rust Compiler (tested with `rustc 1.37.0-nightly (5d8f59f4b 2019-06-04)`) +- ~8GB of free RAM +- Optional: + - Python 3.7 - Pandas - uJSON -- Working nightly Rust Compiler (tested with `rustc 1.37.0-nightly (5d8f59f4b 2019-06-04)`) -- ~8GB of free RAM \ No newline at end of file diff --git a/dumps/process.py b/dumps/process.py index 02b8102..039d9e4 100644 --- a/dumps/process.py +++ b/dumps/process.py @@ -165,7 +165,7 @@ if not os.path.isfile("stars.csv"): print() cache.close() -if not os.path.isfile("stars.kdt"): +if not os.path.isfile("stars.csv"): tqdm.pandas(ascii=True, leave=True) print("Loading data...") data = pd.read_csv( diff --git a/dumps/urls.txt b/dumps/urls.txt new file mode 100644 index 0000000..58a4f38 --- /dev/null +++ b/dumps/urls.txt @@ -0,0 +1,2 @@ +https://www.edsm.net/dump/systemsWithCoordinates.json +https://www.edsm.net/dump/bodies.json \ No newline at end of file diff --git a/src/bin/ed_lrr_pp.rs b/src/bin/ed_lrr_pp.rs new file mode 100644 index 0000000..df0ec67 --- /dev/null +++ b/src/bin/ed_lrr_pp.rs @@ -0,0 +1,188 @@ +#![feature(seek_convenience)] +use fnv::FnvHashMap; +use humantime::format_duration; +use indicatif::{ProgressBar, ProgressStyle}; +use serde::{Deserialize, Serialize}; +use serde_json::Result; +use std::fs::File; +use std::io::{BufRead, BufReader, BufWriter, Seek}; +use std::path::PathBuf; +use std::str; +use std::time::Instant; +use structopt::StructOpt; + +#[derive(Debug, Clone, Serialize)] +struct Record { + id: u64, + star_type: String, + name: String, + mult: f32, + distance: u32, + x: f64, + y: f64, + z: f64, +} +#[derive(Debug, Deserialize)] +#[allow(non_snake_case)] +struct Body { + name: String, + subType: String, + #[serde(rename = "type")] + body_type: String, + systemId: i32, + systemId64: i64, + #[serde(rename = "distanceToArrival")] + distance: u32, +} + +#[derive(Debug, Deserialize)] +struct Coords { + x: f64, + y: f64, + z: f64, +} + +#[derive(Debug, Deserialize)] +struct System { + id: i32, + id64: i64, + name: String, + coords: Coords, + date: String, +} + +#[derive(Debug, StructOpt)] +#[structopt( + name = "ed_lrr_pp", + about = "Preprocessor for Elite: Dangerous Long-Range Router", + rename_all = "snake_case" +)] +/// Preprocess data for ed_lrr +struct Opt { + #[structopt(short, long = "bodies")] + /// Path to bodies.json + bodies: PathBuf, + #[structopt(short, long = "systems")] + /// Path to systemsWithCoordinates.json + systems: PathBuf, + #[structopt(default_value = "stars")] + /// outfile prefix + prefix: String, +} + +fn get_mult(star_type: &str) -> f32 { + if star_type.contains("White Dwarf") { + return 1.5; + } + if star_type.contains("Neutron") { + return 4.0; + } + return 1.0; +} + +fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std::io::Result<()> { + let mut cnt = 0; + let mut buffer = String::new(); + let t_start = Instant::now(); + let fh = File::open(path)?; + let prog_bar = ProgressBar::new(fh.metadata()?.len()); + prog_bar.set_style( + ProgressStyle::default_bar() + .template( + "[{elapsed_precise}/{eta_precise}]{spinner} [{wide_bar}] {binary_bytes}/{binary_total_bytes} ({percent}%)", + ) + .progress_chars("#9876543210 ") + .tick_chars("/-\\|"), + ); + prog_bar.set_draw_delta(1024 * 1024); + let mut reader = BufReader::new(fh); + println!("Loading {} ...", path.to_str().unwrap()); + while let Ok(n) = reader.read_line(&mut buffer) { + if n == 0 { + break; + } + buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string(); + if !buffer.is_empty() { + func(&buffer); + } + prog_bar.set_position(reader.stream_position().unwrap()); + cnt += 1; + buffer.clear(); + } + prog_bar.finish_and_clear(); + println!( + "Processed {} lines in {} ...", + cnt, + format_duration(t_start.elapsed()) + ); + return Ok(()); +} + +fn process_systems(path: &PathBuf) -> FnvHashMap { + let mut ret = FnvHashMap::default(); + process(path, &mut |line| { + let sys_res: Result = serde_json::from_str(&line); + if let Ok(sys) = sys_res { + ret.insert(sys.id64, sys); + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); + } + }) + .unwrap(); + return ret; +} + +fn process_bodies( + path: &PathBuf, + out_prefix: &String, + systems: &FnvHashMap, +) -> std::io::Result<()> { + let out_path = PathBuf::from(format!("{}.csv", out_prefix)); + println!( + "Processing {} into {} ...", + path.to_str().unwrap(), + out_path.to_str().unwrap(), + ); + let mut n: u64 = 0; + let mut wtr = csv::Writer::from_writer(BufWriter::new(File::create(out_path).unwrap())); + process(path, &mut |line| { + if !line.contains("Star") { + return; + } + let body_res: Result = serde_json::from_str(&line); + if let Ok(body) = body_res { + if !body.body_type.contains("Star") { + return; + } + if let Some(sys) = systems.get(&body.systemId64) { + let sub_type = body.subType; + let mult = get_mult(&sub_type); + let body_name = body.name; + let rec = Record { + id: n, + star_type: sub_type, + name: body_name, + mult, + distance: body.distance, + x: sys.coords.x, + y: sys.coords.y, + z: sys.coords.z, + }; + wtr.serialize(rec).unwrap(); + n += 1; + }; + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); + } + }) + .unwrap(); + println!("Total Systems: {}", n); + return Ok(()); +} + +fn main() -> std::io::Result<()> { + let opts = Opt::from_args(); + let systems = process_systems(&opts.systems); + process_bodies(&opts.bodies, &opts.prefix, &systems)?; + return Ok(()); +} diff --git a/src/main.rs b/src/main.rs index efa6305..8f66e74 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,49 +1,48 @@ -extern crate csv; -extern crate serde; -extern crate structopt; -#[macro_use] -extern crate serde_derive; -extern crate fnv; -extern crate humantime; -extern crate permutohedron; use core::cmp::Ordering; use fnv::{FnvHashMap, FnvHashSet}; use humantime::format_duration; use permutohedron::LexicalPermutation; use rstar::{PointDistance, RTree, RTreeObject, AABB}; +use serde::{Deserialize, Serialize}; +use sha3::{Digest, Sha3_256}; use std::collections::VecDeque; +use std::fs::File; use std::hash::{Hash, Hasher}; -use std::io::Write; +use std::io::{BufReader, BufWriter, Write}; use std::path::PathBuf; use std::str::FromStr; use std::time::Instant; use structopt::StructOpt; -#[derive(Debug, Deserialize)] -struct Record { - id: i64, - star_type: String, - name: String, - mult: f32, - x: f32, - y: f32, - z: f32, -} -#[derive(Debug, Clone)] -struct System { - id: i64, - star_type: String, - name: String, - mult: f32, +#[derive(Debug)] +#[allow(dead_code)] +enum StarType { + Neutron, + WhiteDwarf, + Scoopable, + NonScoopable, } -#[derive(Debug, Clone, Copy)] -struct Point { - id: i64, +#[derive(Debug, Clone, Deserialize)] +struct SystemSerde { + id: u32, + star_type: String, + name: String, + mult: f32, + distance: u32, x: f32, y: f32, z: f32, } +#[derive(Debug, Clone, Deserialize, Serialize)] +struct System { + id: u32, + star_type: String, + name: String, + mult: f32, + distance: u32, + pos: [f32; 3], +} #[derive(Debug)] enum Mode { @@ -68,29 +67,53 @@ impl FromStr for Mode { #[structopt( name = "ed_lrr", about = "Elite: Dangerous Long-Range Router", - rename_all = "kebab-case" + rename_all = "snake_case" )] -/// Plots a route through multiple systems using breadth-first search (Currently needs a lot of RAM (about 6GB), sorry) -struct Opt { +/// Plots a route through multiple systems +struct Opts { #[structopt(short, long = "range")] /// Jump Range - range: f32, + range: Option, #[structopt( parse(from_os_str), - short = "f", + short = "i", long = "path", default_value = "./stars.csv" )] /// Path to stars.csv /// - /// Generate using process.py (https://gitlab.com/Earthnuker/ed_lrr/raw/master/dumps/process.py) + /// Generate using ed_lrr_pp file_path: PathBuf, + #[structopt( + parse(from_os_str), + long = "precomp_file", + conflicts_with = "precompute" + )] + /// Path to precomputed route graph + /// + /// Generate using --precompute option + precomp_file: Option, + + #[structopt( + short = "c", + long = "precompute", + conflicts_with = "full_permute", + conflicts_with = "permute", + conflicts_with = "precomp_file" + )] + /// Precompute all routes for the specified jump range starting at the specified system and write the result to {system}_{range}.bin + precompute: bool, + #[structopt(short = "p", long = "permute", conflicts_with = "full_permute")] /// Permute intermediate hops to find shortest route permute: bool, - #[structopt(short = "fp", long = "full_permute", conflicts_with = "permute")] + #[structopt(short = "o", long = "primary")] + /// Only route through the primary star of a system + primary: bool, + + #[structopt(short = "f", long = "full_permute", conflicts_with = "permute")] /// Permute all hops to find shortest route full_permute: bool, @@ -100,8 +123,9 @@ struct Opt { #[structopt( short, - long = "mode", - raw(possible_values = "&[\"bfs\", \"greedy\",\"astar\"]") + long, + raw(possible_values = "&[\"bfs\", \"greedy\",\"astar\"]"), + default_value = "bfs" )] /// Search mode /// @@ -114,15 +138,19 @@ struct Opt { /// Systems to route through systems: Vec, } -fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { +fn dist2(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { let dx = p1[0] - p2[0]; let dy = p1[1] - p2[1]; let dz = p1[2] - p2[2]; - return (dx * dx + dy * dy + dz * dz).sqrt(); + return dx * dx + dy * dy + dz * dz; } -fn fcmp(a: &f32, b: &f32) -> Ordering { +fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + return dist2(p1, p2).sqrt(); +} + +fn fcmp(a: f32, b: f32) -> Ordering { match (a, b) { (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, (x, _) if x.is_nan() => Ordering::Greater, @@ -131,80 +159,83 @@ fn fcmp(a: &f32, b: &f32) -> Ordering { } } -impl Point { +impl System { pub fn dist2(&self, p: &[f32; 3]) -> f32 { - let dx = self.x - p[0]; - let dy = self.y - p[1]; - let dz = self.z - p[2]; - - return dx * dx + dy * dy + dz * dz; + return dist2(&self.pos, p); } - pub fn distp(&self, p: &Point) -> f32 { - return self.distp2(p).sqrt(); + pub fn distp(&self, p: &System) -> f32 { + return dist(&self.pos, &p.pos); } - pub fn distp2(&self, p: &Point) -> f32 { - return self.dist2(&[p.x, p.y, p.z]); + pub fn distp2(&self, p: &System) -> f32 { + return self.dist2(&p.pos); } } -impl PartialEq for Point { +impl PartialEq for System { fn eq(&self, other: &Self) -> bool { self.id == other.id } } -impl Eq for Point {} +impl Eq for System {} -impl Hash for Point { +impl Hash for System { fn hash(&self, state: &mut H) { self.id.hash(state); } } -impl RTreeObject for Point { +impl RTreeObject for System { type Envelope = AABB<[f32; 3]>; fn envelope(&self) -> Self::Envelope { - return AABB::from_point([self.x, self.y, self.z]); + return AABB::from_point(self.pos); } } -impl PointDistance for Point { +impl PointDistance for System { fn distance_2(&self, point: &[f32; 3]) -> f32 { return self.dist2(&point); } } +fn hash_file(path: &PathBuf) -> Vec { + let mut hash_reader = BufReader::new(File::open(path).unwrap()); + let mut hasher = Sha3_256::new(); + std::io::copy(&mut hash_reader, &mut hasher).unwrap(); + hasher.result().iter().map(|v| *v).collect() +} + +#[derive(Deserialize, Serialize)] struct Router { - tree: RTree, - systems: FnvHashMap, - scoopable: FnvHashSet, + tree: RTree, + scoopable: FnvHashSet, + route_tree: Option>, + range: f32, + primary_only: bool, } impl Router { - pub fn new(path: &PathBuf) -> Self { + pub fn new(path: &PathBuf, range: f32, primary_only: bool) -> Self { let mut scoopable = FnvHashSet::default(); - let mut systems: FnvHashMap = FnvHashMap::default(); let mut reader = csv::ReaderBuilder::new() - .has_headers(false) .from_path(path) .unwrap_or_else(|e| { - println!("Error loading {}: {}", path.to_str().unwrap(), e); + println!("Error opening {}: {}", path.to_str().unwrap(), e); std::process::exit(1); }); + let t_load = Instant::now(); println!("Loading {}...", path.to_str().unwrap()); - let points = reader - .deserialize() - .map(|res: Result| { - let sys = res.unwrap(); - systems.insert( - sys.id, - System { - id: sys.id, - star_type: sys.star_type.clone(), - name: sys.name, - mult: sys.mult, - }, - ); + let systems: Vec = reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| { + if primary_only { + sys.distance == 0 + } else { + true + } + }) + .map(|sys| { if sys.mult > 1.0f32 { scoopable.insert(sys.id); } else { @@ -215,61 +246,79 @@ impl Router { } } } - return Point { - x: sys.x, - y: sys.y, - z: sys.z, + return System { id: sys.id, + star_type: sys.star_type, + name: sys.name, + mult: sys.mult, + distance: sys.distance, + pos: [sys.x, sys.y, sys.z], }; }) .collect(); - return Self { - tree: RTree::::bulk_load(points), - systems, + println!("Building RTree..."); + let ret = Self { + tree: RTree::bulk_load(systems), scoopable, + route_tree: None, + range, + primary_only, }; - } - - fn preload_points(&self) -> FnvHashMap { - let mut ret = FnvHashMap::default(); - for point in &self.tree { - ret.insert(point.id, point); - } + println!( + "{} Systems loaded in {}", + ret.tree.size(), + format_duration(t_load.elapsed()) + ); return ret; } - fn closest(&self, point: &[f32; 3]) -> &Point { + pub fn from_file(filename: &PathBuf) -> Self { + let t_load = Instant::now(); + let mut reader = BufReader::new(File::open(&filename).unwrap()); + println!("Loading {}", filename.to_str().unwrap()); + let (primary, range, file_hash, path, route_tree): ( + bool, + f32, + Vec, + String, + FnvHashMap, + ) = bincode::deserialize_from(&mut reader).unwrap(); + let path = PathBuf::from(path); + println!("Done in {}!", format_duration(t_load.elapsed())); + if hash_file(&path) != file_hash { + panic!("File hash mismatch!") + } + let mut rtr = Self::new(&path, range, primary); + rtr.route_tree = Some(route_tree); + return rtr; + } + + fn closest(&self, point: &[f32; 3]) -> &System { return self.tree.nearest_neighbor(point).unwrap(); } - fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { + fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { return self.tree.locate_within_distance(*center, radius * radius); } - fn mult(&self, id: i64) -> f32 { - if let Some(sys) = self.systems.get(&id) { - return sys.mult; - }; - return 1.0; - } - fn neighbours(&self, sys: &Point, r: f32) -> impl Iterator { - return self.points_in_sphere(&[sys.x, sys.y, sys.z], self.mult(sys.id) * r); + fn neighbours(&self, sys: &System, r: f32) -> impl Iterator { + return self.points_in_sphere(&sys.pos, sys.mult * r); } - fn valid(&self, sys: &Point) -> bool { + fn valid(&self, sys: &System) -> bool { return self.scoopable.contains(&sys.id); } pub fn best_name_multiroute( &self, - waypoints: &Vec, + waypoints: &[String], range: f32, full: bool, mode: Mode, factor: f32, - ) -> Vec<(&System, &Point)> { + ) -> Vec { let mut best_score: f32 = std::f32::MAX; - let mut waypoints = waypoints.clone(); - let mut best_permutation_waypoints = waypoints.clone(); + let mut waypoints = waypoints.to_owned(); + let mut best_permutation_waypoints = waypoints.to_owned(); let first = waypoints.first().cloned(); let last = waypoints.last().cloned(); let t_start = Instant::now(); @@ -283,7 +332,11 @@ impl Router { for pair in waypoints.windows(2) { match pair { [src, dst] => { - let (src, dst) = (self.name_to_point(&src), self.name_to_point(&dst)); + let (mut src, dst) = + (self.name_to_systems(&src), self.name_to_systems(&dst)); + src.sort_by_key(|&p| (p.mult * 10.0) as u8); + let src = src.last().unwrap(); + let dst = dst.last().unwrap(); total_d += src.distp2(dst); } _ => panic!("Invalid routing parameters!"), @@ -291,7 +344,7 @@ impl Router { } if total_d < best_score { best_score = total_d; - best_permutation_waypoints = waypoints.clone(); + best_permutation_waypoints = waypoints.to_owned(); } } if !waypoints.next_permutation() { @@ -306,39 +359,44 @@ impl Router { pub fn name_multiroute( &self, - waypoints: &Vec, + waypoints: &[String], range: f32, mode: Mode, factor: f32, - ) -> Vec<(&System, &Point)> { + ) -> Vec { let mut coords = Vec::new(); - for p in waypoints { - let p = self.name_to_point(p); - let s = [p.x, p.y, p.z]; - coords.push(s); + for p_name in waypoints { + let mut p_l = self.name_to_systems(p_name); + p_l.sort_by_key(|&p| (p.mult * 10.0) as u8); + let p = p_l.last().unwrap(); + coords.push((p_name, p.pos)); } return self.multiroute(coords.as_slice(), range, mode, factor); } pub fn multiroute( &self, - waypoints: &[[f32; 3]], + waypoints: &[(&String, [f32; 3])], range: f32, mode: Mode, factor: f32, - ) -> Vec<(&System, &Point)> { - let mut route = Vec::new(); + ) -> Vec { + let mut route: Vec = Vec::new(); for pair in waypoints.windows(2) { - match pair { - &[src, dst] => { + match *pair { + [src, dst] => { let block = match mode { Mode::BFS => self.route_bfs(&src, &dst, range), Mode::Greedy => self.route_greedy(&src, &dst, range), Mode::AStar => self.route_astar(&src, &dst, range, factor), }; if route.is_empty() { - route.extend(block.iter()); + for sys in block.iter() { + route.push(sys.clone()); + } } else { - route.extend(block.iter().skip(1)); + for sys in block.iter().skip(1) { + route.push(sys.clone()); + } } } _ => panic!("Invalid routing parameters!"), @@ -347,20 +405,10 @@ impl Router { return route; } - fn sys_to_point(&self, id: i64) -> &Point { - for p in &self.tree { - if p.id == id { - return p; - } - } - eprintln!("Sytem-ID not found: \"{}\"", id); - std::process::exit(1); - } - - fn name_to_point(&self, name: &str) -> &Point { - for sys in self.systems.values() { + fn name_to_systems(&self, name: &str) -> Vec<&System> { + for sys in &self.tree { if sys.name == name { - return self.sys_to_point(sys.id); + return self.neighbours(&sys, 0.0).collect(); } } eprintln!("Sytem not found: \"{}\"", name); @@ -369,25 +417,22 @@ impl Router { pub fn route_astar( &self, - src: &[f32; 3], - dst: &[f32; 3], + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), range: f32, factor: f32, - ) -> Vec<(&System, &Point)> { + ) -> Vec { if factor == 0.0 { return self.route_bfs(src, dst, range); } println!("Running A-Star with greedy factor of {}", factor); + let (src_name, src) = src; + let (dst_name, dst) = dst; let start_sys = self.closest(src); let goal_sys = self.closest(dst); - let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); - let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); { let d = dist(src, dst); - println!( - "Plotting route from {} to {}...", - start_sys_name, goal_sys_name - ); + println!("Plotting route from {} to {}...", src_name, dst_name); println!( "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", range, @@ -401,7 +446,7 @@ impl Router { let t_start = Instant::now(); let mut found = false; let mut maxd = 0; - let mut queue: Vec<(usize, usize, &Point)> = Vec::new(); + let mut queue: Vec<(usize, usize, &System)> = Vec::new(); queue.push(( 0, // depth (start_sys.distp(goal_sys) / range) as usize, // h @@ -432,7 +477,7 @@ impl Router { .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { - prev.insert(nb.id, sys.id); + prev.insert(nb.id, sys); let d_g = (nb.distp(goal_sys) / range) as usize; return (depth + 1, d_g, nb); }), @@ -442,7 +487,7 @@ impl Router { let (b_0, b_1) = (b.0 as f32, b.1 as f32); let v_a = a_0 + a_1 * factor; let v_b = b_0 + b_1 * factor; - return fcmp(&v_a, &v_b); + return fcmp(v_a, v_b); }); // queue.reverse(); } @@ -451,23 +496,15 @@ impl Router { println!(); if !found { - eprintln!( - "No route from {} to {} found!", - start_sys_name, goal_sys_name - ); + eprintln!("No route from {} to {} found!", src_name, dst_name); return Vec::new(); } - let points = self.preload_points(); - let mut v: Vec<(&System, &Point)> = Vec::new(); - let mut prev_sys_id = goal_sys.id; + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; loop { - if let Some(sys) = self.systems.get(&prev_sys_id) { - v.push((sys, points[&sys.id])); - } else { - break; - }; - match prev.get(&prev_sys_id) { - Some(sys_id) => prev_sys_id = *sys_id, + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, None => { break; } @@ -479,21 +516,18 @@ impl Router { pub fn route_greedy( &self, - src: &[f32; 3], - dst: &[f32; 3], + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), range: f32, - ) -> Vec<(&System, &Point)> { + ) -> Vec { println!("Running Greedy-Search"); + let (src_name, src) = src; + let (dst_name, dst) = dst; let start_sys = self.closest(src); let goal_sys = self.closest(dst); - let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); - let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); { let d = dist(src, dst); - println!( - "Plotting route from {} to {}...", - start_sys_name, goal_sys_name - ); + println!("Plotting route from {} to {}...", src_name, dst_name); println!( "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", range, @@ -507,13 +541,8 @@ impl Router { let t_start = Instant::now(); let mut found = false; let mut maxd = 0; - let mut queue: Vec<(f32, f32, usize, &Point)> = Vec::new(); - queue.push(( - -self.mult(goal_sys.id), - start_sys.distp2(goal_sys), - 0, - &start_sys, - )); + let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); + queue.push((-goal_sys.mult, start_sys.distp2(goal_sys), 0, &start_sys)); seen.insert(start_sys.id); while !(queue.is_empty() || found) { while let Some((_, _, depth, sys)) = queue.pop() { @@ -538,33 +567,26 @@ impl Router { .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { - prev.insert(nb.id, sys.id); - return (-self.mult(nb.id), nb.distp2(goal_sys), depth + 1, nb); + prev.insert(nb.id, sys); + return (-nb.mult, nb.distp2(goal_sys), depth + 1, nb); }), ); - queue.sort_by(|a, b| fcmp(&a.0, &b.0).then(fcmp(&a.1, &b.1))); + queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); queue.reverse(); } } println!(); + println!(); if !found { - eprintln!( - "No route from {} to {} found!", - start_sys_name, goal_sys_name - ); + eprintln!("No route from {} to {} found!", src_name, dst_name); return Vec::new(); } - let points = self.preload_points(); - let mut v: Vec<(&System, &Point)> = Vec::new(); - let mut prev_sys_id = goal_sys.id; + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; loop { - if let Some(sys) = self.systems.get(&prev_sys_id) { - v.push((sys, points[&sys.id])); - } else { - break; - }; - match prev.get(&prev_sys_id) { - Some(sys_id) => prev_sys_id = *sys_id, + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, None => { break; } @@ -574,18 +596,97 @@ impl Router { return v; } - pub fn route_bfs(&self, src: &[f32; 3], dst: &[f32; 3], range: f32) -> Vec<(&System, &Point)> { + pub fn precompute(&mut self, src: &String) { + println!("Precomputing route starting at {} ...", src); + let mut sys_l = self.name_to_systems(src); + sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8); + let sys = sys_l.last().unwrap(); + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut depth = 0; + let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); + queue.push_front((0, &sys)); + seen.insert(sys.id); + while !queue.is_empty() { + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + while let Some((d, sys)) = queue.pop_front() { + queue_next.extend( + self.neighbours(&sys, self.range) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys.id); + return (d + 1, nb); + }), + ); + } + std::mem::swap(&mut queue, &mut queue_next); + depth += 1; + } + self.route_tree = Some(prev); + } + + pub fn route_to(&mut self, dst: &str) -> Vec { + let mut id_map: FnvHashMap = FnvHashMap::default(); + let mut id_set: FnvHashSet = FnvHashSet::default(); + let prev = self.route_tree.as_ref().unwrap(); + let mut dst = self.name_to_systems(dst); + dst.sort_by_key(|&p| (p.mult * 10.0) as u8); + let dst: System = dst.last().cloned().unwrap().clone(); + if !prev.contains_key(&dst.id) { + eprintln!("System-ID {} not found", dst.id); + std::process::exit(1); + }; + let mut v_ids: Vec = Vec::new(); + let mut v: Vec = Vec::new(); + let mut curr_sys: u32 = dst.id; + loop { + v_ids.push(curr_sys); + id_set.insert(curr_sys); + match prev.get(&curr_sys) { + Some(sys_id) => curr_sys = *sys_id, + None => { + break; + } + } + } + v_ids.reverse(); + for sys in &self.tree { + if id_set.contains(&sys.id) { + id_map.insert(sys.id, &sys); + } + } + for sys_id in v_ids { + let sys = *(id_map.get(&sys_id).unwrap()); + v.push(sys.clone()) + } + return v; + } + + pub fn route_bfs( + &self, + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), + range: f32, + ) -> Vec { println!("Running BFS"); + let (src_name, src) = src; + let (dst_name, dst) = dst; let start_sys = self.closest(src); let goal_sys = self.closest(dst); - let start_sys_name = self.systems.get(&start_sys.id).unwrap().name.clone(); - let goal_sys_name = self.systems.get(&goal_sys.id).unwrap().name.clone(); { let d = dist(src, dst); - println!( - "Plotting route from {} to {}...", - start_sys_name, goal_sys_name - ); + println!("Plotting route from {} to {}...", src_name, dst_name); println!( "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", range, @@ -599,8 +700,8 @@ impl Router { let t_start = Instant::now(); let mut depth = 0; let mut found = false; - let mut queue: VecDeque<(usize, &Point)> = VecDeque::new(); - let mut queue_next: VecDeque<(usize, &Point)> = VecDeque::new(); + let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); queue.push_front((0, &start_sys)); seen.insert(start_sys.id); while !(queue.is_empty() || found) { @@ -623,7 +724,7 @@ impl Router { .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { - prev.insert(nb.id, sys.id); + prev.insert(nb.id, sys); return (d + 1, nb); }), ); @@ -632,24 +733,17 @@ impl Router { depth += 1; } println!(); + println!(); if !found { - eprintln!( - "No route from {} to {} found!", - start_sys_name, goal_sys_name - ); + eprintln!("No route from {} to {} found!", src_name, dst_name); return Vec::new(); } - let points = self.preload_points(); - let mut v: Vec<(&System, &Point)> = Vec::new(); - let mut prev_sys_id = goal_sys.id; + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; loop { - if let Some(sys) = self.systems.get(&prev_sys_id) { - v.push((sys, points[&sys.id])); - } else { - break; - }; - match prev.get(&prev_sys_id) { - Some(sys_id) => prev_sys_id = *sys_id, + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, None => { break; } @@ -661,50 +755,90 @@ impl Router { } fn main() { - let opts = Opt::from_args(); + let t_start = Instant::now(); + let opts = Opts::from_args(); + if opts.systems.len() == 0 { + if opts.precomp_file.is_some() { + eprintln!("Error: Please specify exatly one system"); + } else { + if opts.precompute { + eprintln!("Error: Please specify at least one system"); + } else { + eprintln!("Error: Please specify at least two systems"); + } + } + std::process::exit(1); + } let path = opts.file_path; - let t_load = Instant::now(); - let router: Router = Router::new(&path); - println!("Done in {}!", format_duration(t_load.elapsed())); - let t_route = Instant::now(); - let route = if opts.permute || opts.full_permute { - router.best_name_multiroute( - &opts.systems, - opts.range, - opts.full_permute, - opts.mode, - opts.factor.unwrap_or(1.0), - ) + let mut router: Router = if opts.precomp_file.is_some() { + Router::from_file(&opts.precomp_file.unwrap()) } else { - router.name_multiroute( - &opts.systems, - opts.range, - opts.mode, - opts.factor.unwrap_or(1.0), - ) + Router::new(&path, opts.range.unwrap(), opts.primary) }; - println!( - "Done in {} ({} Jumps)!\n", - format_duration(t_route.elapsed()), - route.len(), - ); - if route.len() == 0 { + if opts.precompute { + for sys in opts.systems { + router.route_tree = None; + router.precompute(&sys); + let ofn = format!( + "{}_{}{}.router", + sys.replace("*", "").replace(" ", "_"), + opts.range.unwrap(), + if router.primary_only { "_primary" } else { "" } + ); + println!("\nSaving to {}", ofn); + let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); + // (range, path, route_tree) + let data = ( + router.primary_only, + router.range, + hash_file(&path), + String::from(path.to_str().unwrap()), + router.route_tree.unwrap(), + ); + bincode::serialize_into(&mut out_fh, &data).unwrap(); + } + std::process::exit(0); + } + let t_route = Instant::now(); + let route = if router.route_tree.is_some() { + router.route_to(opts.systems.first().unwrap()) + } else { + if opts.permute || opts.full_permute { + router.best_name_multiroute( + &opts.systems, + opts.range.unwrap(), + opts.full_permute, + opts.mode, + opts.factor.unwrap_or(1.0), + ) + } else { + router.name_multiroute( + &opts.systems, + opts.range.unwrap(), + opts.mode, + opts.factor.unwrap_or(1.0), + ) + } + }; + println!("Route computed in {}\n", format_duration(t_route.elapsed())); + if route.is_empty() { eprintln!("No route found!"); return; } let mut total: f32 = 0.0; - for ((sys1, p1), (_, p2)) in route.iter().zip(route.iter().skip(1)) { - let dist = p1.distp(p2); + for (sys1, sys2) in route.iter().zip(route.iter().skip(1)) { + let dist = sys1.distp(sys2); total += dist; println!( - "{} [{}] ({},{},{}): {:.2} Ly", - sys1.name, sys1.star_type, p1.x, p1.y, p1.z, dist + "{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly", + sys1.name, sys1.star_type, sys1.pos[0], sys1.pos[1], sys1.pos[2], sys1.distance, dist ); } - let (sys, p) = route.iter().last().unwrap(); + let sys = route.iter().last().unwrap(); println!( - "{} [{}] ({},{},{}): {:.2} Ly", - sys.name, sys.star_type, p.x, p.y, p.z, 0.0 + "{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly", + sys.name, sys.star_type, sys.pos[0], sys.pos[1], sys.pos[2], sys.distance, 0.0 ); - println!("Total: {:.2} Ly", total); + println!("Total: {:.2} Ly ({} Jumps)", total, route.len()); + println!("Total time: {}", format_duration(t_start.elapsed())); } From 38e6fc96f28f5af2e7f6bfae174e85200064b8e4 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 29 Jun 2019 09:08:41 +0000 Subject: [PATCH 10/72] Add .gitlab-ci.yml --- .gitlab-ci.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..fba3704 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,26 @@ +# This file is a template, and might need editing before it works on your project. +# Official language image. Look for the different tagged releases at: +# https://hub.docker.com/r/library/rust/tags/ +image: "rust:latest" + +# Optional: Pick zero or more services to be used on all builds. +# Only needed when using a docker container to run your tests in. +# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service +# services: +# - mysql:latest +# - redis:latest +# - postgres:latest + +# Optional: Install a C compiler, cmake and git into the container. +# You will often need this when you (or any of your dependencies) depends on C code. +before_script: + - apt-get update -yqq + - apt-get install -yqq --no-install-recommends build-essential + - rustup update nightly + - rustup default nightly + +# Use cargo to test the project +test:cargo: + script: + - rustc --version && cargo --version # Print version info for debugging + - cargo build --release From 38949850f8bf9309eb0a12c0fc1071f36dfe9991 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 29 Jun 2019 11:20:13 +0200 Subject: [PATCH 11/72] Fix typo in README --- .gitignore | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ac00f51..04952d3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.router dumps/*.json plot.py +*.tmp diff --git a/README.md b/README.md index 46f73b0..9d187d3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ 1. download `bodies.json` and `systemsWithCoordinates.json` from https://www.edsm.net/en/nightly-dumps/ and place them in the `dumps` folder 2. run `cargo install --path .` or `cargo install --git https://gitlab.com/Earthnuker/ed_lrr.git` 3. run `ed_lrr_pp --bodies dumps/bodies.json --systems dumps/systemsWithCoordinates.json` - - Alternatively run `proces.py` in the `dumps` folder + - Alternatively run `process.py` in the `dumps` folder 4. run `ed_lrr --help` From 5f341ae5f151fca27413c347779b459c30cf9346 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 29 Jun 2019 12:21:36 +0200 Subject: [PATCH 12/72] Update README.md add "+nightly" to cargo commands --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d187d3..9be370c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Usage: 1. download `bodies.json` and `systemsWithCoordinates.json` from https://www.edsm.net/en/nightly-dumps/ and place them in the `dumps` folder -2. run `cargo install --path .` or `cargo install --git https://gitlab.com/Earthnuker/ed_lrr.git` +2. run `cargo +nightly install --path .` or `cargo +nightly install --git https://gitlab.com/Earthnuker/ed_lrr.git` 3. run `ed_lrr_pp --bodies dumps/bodies.json --systems dumps/systemsWithCoordinates.json` - Alternatively run `process.py` in the `dumps` folder 4. run `ed_lrr --help` From 273e5c74c39cf5f014b1205ba3881cbcbca32b78 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 29 Jun 2019 18:11:32 +0200 Subject: [PATCH 13/72] Check if name is a substring of system name instead of exact match --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8f66e74..460666b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -407,11 +407,11 @@ impl Router { fn name_to_systems(&self, name: &str) -> Vec<&System> { for sys in &self.tree { - if sys.name == name { + if sys.name.contains(name) { return self.neighbours(&sys, 0.0).collect(); } } - eprintln!("Sytem not found: \"{}\"", name); + eprintln!("System not found: \"{}\"", name); std::process::exit(1); } From bac5907f1509a910ba613c5a6d829ef60719051d Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sun, 30 Jun 2019 02:01:14 +0200 Subject: [PATCH 14/72] Update main.rs Accelerate search for multiple systems by id/name by doing a single pass and returning a map --- src/main.rs | 122 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 20 deletions(-) diff --git a/src/main.rs b/src/main.rs index 460666b..e40dd31 100644 --- a/src/main.rs +++ b/src/main.rs @@ -272,7 +272,7 @@ impl Router { return ret; } - pub fn from_file(filename: &PathBuf) -> Self { + pub fn from_file(filename: &PathBuf) -> (PathBuf, Self) { let t_load = Instant::now(); let mut reader = BufReader::new(File::open(&filename).unwrap()); println!("Loading {}", filename.to_str().unwrap()); @@ -288,9 +288,16 @@ impl Router { if hash_file(&path) != file_hash { panic!("File hash mismatch!") } - let mut rtr = Self::new(&path, range, primary); - rtr.route_tree = Some(route_tree); - return rtr; + return ( + path, + Self { + tree: RTree::default(), + scoopable: FnvHashSet::default(), + route_tree: Some(route_tree), + range, + primary_only: primary, + }, + ); } fn closest(&self, point: &[f32; 3]) -> &System { @@ -636,13 +643,91 @@ impl Router { self.route_tree = Some(prev); } - pub fn route_to(&mut self, dst: &str) -> Vec { - let mut id_map: FnvHashMap = FnvHashMap::default(); - let mut id_set: FnvHashSet = FnvHashSet::default(); + fn get_systems_by_ids(path: &PathBuf, ids: &Vec) -> FnvHashMap { + let mut ret = FnvHashMap::default(); + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + println!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| ids.contains(&sys.id)) + .map(|sys| { + ret.insert( + sys.id, + System { + id: sys.id, + star_type: sys.star_type, + name: sys.name, + mult: sys.mult, + distance: sys.distance, + pos: [sys.x, sys.y, sys.z], + }, + ); + }) + .last() + .expect(&format!("No systems matching {:?} found!", ids)); + return ret; + } + + fn get_systems_by_names(path: &PathBuf, names: &Vec) -> FnvHashMap { + let mut ret = FnvHashMap::default(); + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + println!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| names.contains(&sys.name)) + .map(|sys| { + ret.insert( + sys.name.clone(), + System { + id: sys.id, + star_type: sys.star_type, + name: sys.name, + mult: sys.mult, + distance: sys.distance, + pos: [sys.x, sys.y, sys.z], + }, + ); + }) + .last() + .expect(&format!("No systems matching {:?} found!", names)); + return ret; + } + + fn get_system_by_name(path: &PathBuf, name: &str) -> System { + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + println!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + let sys = reader + .deserialize::() + .map(|res| res.unwrap()) + .find(|sys| sys.name == name) + .expect(&format!("System '{}' not found!", name)); + return System { + id: sys.id, + star_type: sys.star_type, + name: sys.name, + mult: sys.mult, + distance: sys.distance, + pos: [sys.x, sys.y, sys.z], + }; + } + + pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Vec { let prev = self.route_tree.as_ref().unwrap(); - let mut dst = self.name_to_systems(dst); - dst.sort_by_key(|&p| (p.mult * 10.0) as u8); - let dst: System = dst.last().cloned().unwrap().clone(); + let dst = Self::get_system_by_name(&systems_path, dst); if !prev.contains_key(&dst.id) { eprintln!("System-ID {} not found", dst.id); std::process::exit(1); @@ -652,7 +737,6 @@ impl Router { let mut curr_sys: u32 = dst.id; loop { v_ids.push(curr_sys); - id_set.insert(curr_sys); match prev.get(&curr_sys) { Some(sys_id) => curr_sys = *sys_id, None => { @@ -661,13 +745,9 @@ impl Router { } } v_ids.reverse(); - for sys in &self.tree { - if id_set.contains(&sys.id) { - id_map.insert(sys.id, &sys); - } - } + let id_map = Self::get_systems_by_ids(&systems_path, &v_ids); for sys_id in v_ids { - let sys = *(id_map.get(&sys_id).unwrap()); + let sys = id_map.get(&sys_id).unwrap(); v.push(sys.clone()) } return v; @@ -769,9 +849,11 @@ fn main() { } std::process::exit(1); } - let path = opts.file_path; + let mut path = opts.file_path; let mut router: Router = if opts.precomp_file.is_some() { - Router::from_file(&opts.precomp_file.unwrap()) + let ret = Router::from_file(&opts.precomp_file.clone().unwrap()); + path = ret.0; + ret.1 } else { Router::new(&path, opts.range.unwrap(), opts.primary) }; @@ -801,7 +883,7 @@ fn main() { } let t_route = Instant::now(); let route = if router.route_tree.is_some() { - router.route_to(opts.systems.first().unwrap()) + router.route_to(opts.systems.first().unwrap(), &path) } else { if opts.permute || opts.full_permute { router.best_name_multiroute( From 5c3cdac88f2cae5596870bdedfb3df1499caf437 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Thu, 4 Jul 2019 21:08:57 +0200 Subject: [PATCH 15/72] Refactoring Splite code into modules Merge ed_lrr and ed_lrr_pp into one binary and use subcommands (route and preprocess) Run clippy and fix warnings --- .gitignore | 1 + Cargo.lock | 1 + Cargo.toml | 2 + src/common.rs | 38 ++ src/lib.rs | 3 + src/main.rs | 922 +--------------------------------------------- src/preprocess.rs | 220 +++++++++++ src/route.rs | 913 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1190 insertions(+), 910 deletions(-) create mode 100644 src/common.rs create mode 100644 src/lib.rs create mode 100644 src/preprocess.rs create mode 100644 src/route.rs diff --git a/.gitignore b/.gitignore index 04952d3..ce01f3f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dumps/*.json plot.py *.tmp +*.idx diff --git a/Cargo.lock b/Cargo.lock index 67bca1b..564d063 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,6 +174,7 @@ name = "ed_lrr" version = "0.1.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 0283f87..936e294 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" repository = "https://gitlab.com/Earthnuker/ed_lrr.git" license = "WTFPL" + [profile.release] # debug=true @@ -22,3 +23,4 @@ indicatif = "0.11.0" fnv = "1.0.6" bincode = "1.1.4" sha3 = "0.8.2" +byteorder = "1.3.2" diff --git a/src/common.rs b/src/common.rs new file mode 100644 index 0000000..922aafd --- /dev/null +++ b/src/common.rs @@ -0,0 +1,38 @@ +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SystemSerde { + pub id: u32, + pub star_type: String, + pub system: String, + pub body: String, + pub mult: f32, + pub distance: u32, + pub x: f32, + pub y: f32, + pub z: f32, +} + +impl SystemSerde { + pub fn build(&self) -> System { + System { + id: self.id, + star_type: self.star_type.clone(), + system: self.system.clone(), + body: self.body.clone(), + mult: self.mult, + distance: self.distance, + pos: [self.x, self.y, self.z], + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct System { + pub id: u32, + pub star_type: String, + pub system: String, + pub body: String, + pub mult: f32, + pub distance: u32, + pub pos: [f32; 3], +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d79b416 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod common; +pub mod preprocess; +pub mod route; diff --git a/src/main.rs b/src/main.rs index e40dd31..3403ad9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,926 +1,28 @@ -use core::cmp::Ordering; -use fnv::{FnvHashMap, FnvHashSet}; +use ed_lrr::preprocess::{preprocess_files, PreprocessOpts}; +use ed_lrr::route::{route, RouteOpts}; use humantime::format_duration; -use permutohedron::LexicalPermutation; -use rstar::{PointDistance, RTree, RTreeObject, AABB}; -use serde::{Deserialize, Serialize}; -use sha3::{Digest, Sha3_256}; -use std::collections::VecDeque; -use std::fs::File; -use std::hash::{Hash, Hasher}; -use std::io::{BufReader, BufWriter, Write}; -use std::path::PathBuf; -use std::str::FromStr; use std::time::Instant; use structopt::StructOpt; - -#[derive(Debug)] -#[allow(dead_code)] -enum StarType { - Neutron, - WhiteDwarf, - Scoopable, - NonScoopable, -} - -#[derive(Debug, Clone, Deserialize)] -struct SystemSerde { - id: u32, - star_type: String, - name: String, - mult: f32, - distance: u32, - x: f32, - y: f32, - z: f32, -} -#[derive(Debug, Clone, Deserialize, Serialize)] -struct System { - id: u32, - star_type: String, - name: String, - mult: f32, - distance: u32, - pos: [f32; 3], -} - -#[derive(Debug)] -enum Mode { - BFS, - Greedy, - AStar, -} - -impl FromStr for Mode { - type Err = String; - fn from_str(s: &str) -> Result { - match s { - "bfs" => Ok(Mode::BFS), - "greedy" => Ok(Mode::Greedy), - "astar" => Ok(Mode::AStar), - _ => Err("Invalid Mode".to_string()), - } - } -} - #[derive(Debug, StructOpt)] #[structopt( name = "ed_lrr", about = "Elite: Dangerous Long-Range Router", rename_all = "snake_case" )] -/// Plots a route through multiple systems -struct Opts { - #[structopt(short, long = "range")] - /// Jump Range - range: Option, - #[structopt( - parse(from_os_str), - short = "i", - long = "path", - default_value = "./stars.csv" - )] - /// Path to stars.csv - /// - /// Generate using ed_lrr_pp - file_path: PathBuf, - - #[structopt( - parse(from_os_str), - long = "precomp_file", - conflicts_with = "precompute" - )] - /// Path to precomputed route graph - /// - /// Generate using --precompute option - precomp_file: Option, - - #[structopt( - short = "c", - long = "precompute", - conflicts_with = "full_permute", - conflicts_with = "permute", - conflicts_with = "precomp_file" - )] - /// Precompute all routes for the specified jump range starting at the specified system and write the result to {system}_{range}.bin - precompute: bool, - - #[structopt(short = "p", long = "permute", conflicts_with = "full_permute")] - /// Permute intermediate hops to find shortest route - permute: bool, - - #[structopt(short = "o", long = "primary")] - /// Only route through the primary star of a system - primary: bool, - - #[structopt(short = "f", long = "full_permute", conflicts_with = "permute")] - /// Permute all hops to find shortest route - full_permute: bool, - - #[structopt(short = "g", long = "factor")] - /// Greedyness factor for A-Star (0=BFS, inf=Greedy) - factor: Option, - - #[structopt( - short, - long, - raw(possible_values = "&[\"bfs\", \"greedy\",\"astar\"]"), - default_value = "bfs" - )] - /// Search mode - /// - /** - - BFS is guaranteed to find the shortest route but very slow - - Greedy is a lot faster but will probably not find the shortest route - - A-Star is a good middle ground between speed and accuracy - */ - mode: Mode, - /// Systems to route through - systems: Vec, -} -fn dist2(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { - let dx = p1[0] - p2[0]; - let dy = p1[1] - p2[1]; - let dz = p1[2] - p2[2]; - - return dx * dx + dy * dy + dz * dz; +enum Opts { + /// Plots a route through multiple systems + Route(RouteOpts), + /// Preprocess EDSM Dump + Preprocess(PreprocessOpts), } -fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { - return dist2(p1, p2).sqrt(); -} - -fn fcmp(a: f32, b: f32) -> Ordering { - match (a, b) { - (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, - (x, _) if x.is_nan() => Ordering::Greater, - (_, y) if y.is_nan() => Ordering::Less, - (..) => a.partial_cmp(&b).unwrap(), - } -} - -impl System { - pub fn dist2(&self, p: &[f32; 3]) -> f32 { - return dist2(&self.pos, p); - } - pub fn distp(&self, p: &System) -> f32 { - return dist(&self.pos, &p.pos); - } - pub fn distp2(&self, p: &System) -> f32 { - return self.dist2(&p.pos); - } -} -impl PartialEq for System { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - -impl Eq for System {} - -impl Hash for System { - fn hash(&self, state: &mut H) { - self.id.hash(state); - } -} - -impl RTreeObject for System { - type Envelope = AABB<[f32; 3]>; - - fn envelope(&self) -> Self::Envelope { - return AABB::from_point(self.pos); - } -} - -impl PointDistance for System { - fn distance_2(&self, point: &[f32; 3]) -> f32 { - return self.dist2(&point); - } -} - -fn hash_file(path: &PathBuf) -> Vec { - let mut hash_reader = BufReader::new(File::open(path).unwrap()); - let mut hasher = Sha3_256::new(); - std::io::copy(&mut hash_reader, &mut hasher).unwrap(); - hasher.result().iter().map(|v| *v).collect() -} - -#[derive(Deserialize, Serialize)] -struct Router { - tree: RTree, - scoopable: FnvHashSet, - route_tree: Option>, - range: f32, - primary_only: bool, -} - -impl Router { - pub fn new(path: &PathBuf, range: f32, primary_only: bool) -> Self { - let mut scoopable = FnvHashSet::default(); - let mut reader = csv::ReaderBuilder::new() - .from_path(path) - .unwrap_or_else(|e| { - println!("Error opening {}: {}", path.to_str().unwrap(), e); - std::process::exit(1); - }); - let t_load = Instant::now(); - println!("Loading {}...", path.to_str().unwrap()); - let systems: Vec = reader - .deserialize::() - .map(|res| res.unwrap()) - .filter(|sys| { - if primary_only { - sys.distance == 0 - } else { - true - } - }) - .map(|sys| { - if sys.mult > 1.0f32 { - scoopable.insert(sys.id); - } else { - for c in "KGBFOAM".chars() { - if sys.star_type.starts_with(c) { - scoopable.insert(sys.id); - break; - } - } - } - return System { - id: sys.id, - star_type: sys.star_type, - name: sys.name, - mult: sys.mult, - distance: sys.distance, - pos: [sys.x, sys.y, sys.z], - }; - }) - .collect(); - println!("Building RTree..."); - let ret = Self { - tree: RTree::bulk_load(systems), - scoopable, - route_tree: None, - range, - primary_only, - }; - println!( - "{} Systems loaded in {}", - ret.tree.size(), - format_duration(t_load.elapsed()) - ); - return ret; - } - - pub fn from_file(filename: &PathBuf) -> (PathBuf, Self) { - let t_load = Instant::now(); - let mut reader = BufReader::new(File::open(&filename).unwrap()); - println!("Loading {}", filename.to_str().unwrap()); - let (primary, range, file_hash, path, route_tree): ( - bool, - f32, - Vec, - String, - FnvHashMap, - ) = bincode::deserialize_from(&mut reader).unwrap(); - let path = PathBuf::from(path); - println!("Done in {}!", format_duration(t_load.elapsed())); - if hash_file(&path) != file_hash { - panic!("File hash mismatch!") - } - return ( - path, - Self { - tree: RTree::default(), - scoopable: FnvHashSet::default(), - route_tree: Some(route_tree), - range, - primary_only: primary, - }, - ); - } - - fn closest(&self, point: &[f32; 3]) -> &System { - return self.tree.nearest_neighbor(point).unwrap(); - } - fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { - return self.tree.locate_within_distance(*center, radius * radius); - } - - fn neighbours(&self, sys: &System, r: f32) -> impl Iterator { - return self.points_in_sphere(&sys.pos, sys.mult * r); - } - - fn valid(&self, sys: &System) -> bool { - return self.scoopable.contains(&sys.id); - } - - pub fn best_name_multiroute( - &self, - waypoints: &[String], - range: f32, - full: bool, - mode: Mode, - factor: f32, - ) -> Vec { - let mut best_score: f32 = std::f32::MAX; - let mut waypoints = waypoints.to_owned(); - let mut best_permutation_waypoints = waypoints.to_owned(); - let first = waypoints.first().cloned(); - let last = waypoints.last().cloned(); - let t_start = Instant::now(); - println!("Finding best permutation of hops..."); - while waypoints.prev_permutation() {} - loop { - let c_first = waypoints.first().cloned(); - let c_last = waypoints.last().cloned(); - if full || ((c_first == first) && (c_last == last)) { - let mut total_d = 0.0; - for pair in waypoints.windows(2) { - match pair { - [src, dst] => { - let (mut src, dst) = - (self.name_to_systems(&src), self.name_to_systems(&dst)); - src.sort_by_key(|&p| (p.mult * 10.0) as u8); - let src = src.last().unwrap(); - let dst = dst.last().unwrap(); - total_d += src.distp2(dst); - } - _ => panic!("Invalid routing parameters!"), - } - } - if total_d < best_score { - best_score = total_d; - best_permutation_waypoints = waypoints.to_owned(); - } - } - if !waypoints.next_permutation() { - break; - } - } - - println!("Done in {}!", format_duration(t_start.elapsed())); - println!("Best permutation: {:?}", best_permutation_waypoints); - return self.name_multiroute(&best_permutation_waypoints, range, mode, factor); - } - - pub fn name_multiroute( - &self, - waypoints: &[String], - range: f32, - mode: Mode, - factor: f32, - ) -> Vec { - let mut coords = Vec::new(); - for p_name in waypoints { - let mut p_l = self.name_to_systems(p_name); - p_l.sort_by_key(|&p| (p.mult * 10.0) as u8); - let p = p_l.last().unwrap(); - coords.push((p_name, p.pos)); - } - return self.multiroute(coords.as_slice(), range, mode, factor); - } - pub fn multiroute( - &self, - waypoints: &[(&String, [f32; 3])], - range: f32, - mode: Mode, - factor: f32, - ) -> Vec { - let mut route: Vec = Vec::new(); - for pair in waypoints.windows(2) { - match *pair { - [src, dst] => { - let block = match mode { - Mode::BFS => self.route_bfs(&src, &dst, range), - Mode::Greedy => self.route_greedy(&src, &dst, range), - Mode::AStar => self.route_astar(&src, &dst, range, factor), - }; - if route.is_empty() { - for sys in block.iter() { - route.push(sys.clone()); - } - } else { - for sys in block.iter().skip(1) { - route.push(sys.clone()); - } - } - } - _ => panic!("Invalid routing parameters!"), - } - } - return route; - } - - fn name_to_systems(&self, name: &str) -> Vec<&System> { - for sys in &self.tree { - if sys.name.contains(name) { - return self.neighbours(&sys, 0.0).collect(); - } - } - eprintln!("System not found: \"{}\"", name); - std::process::exit(1); - } - - pub fn route_astar( - &self, - src: &(&String, [f32; 3]), - dst: &(&String, [f32; 3]), - range: f32, - factor: f32, - ) -> Vec { - if factor == 0.0 { - return self.route_bfs(src, dst, range); - } - println!("Running A-Star with greedy factor of {}", factor); - let (src_name, src) = src; - let (dst_name, dst) = dst; - let start_sys = self.closest(src); - let goal_sys = self.closest(dst); - { - let d = dist(src, dst); - println!("Plotting route from {} to {}...", src_name, dst_name); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", - range, - d, - d / range - ); - } - let total = self.tree.size() as f32; - let mut prev = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); - let mut found = false; - let mut maxd = 0; - let mut queue: Vec<(usize, usize, &System)> = Vec::new(); - queue.push(( - 0, // depth - (start_sys.distp(goal_sys) / range) as usize, // h - &start_sys, - )); - seen.insert(start_sys.id); - - while !(queue.is_empty() || found) { - while let Some((depth, _, sys)) = queue.pop() { - if depth > maxd { - maxd = depth; - print!( - "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", - format_duration(t_start.elapsed()), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total - ); - std::io::stdout().flush().unwrap(); - } - if sys.id == goal_sys.id { - found = true; - break; - } - queue.extend( - self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys); - let d_g = (nb.distp(goal_sys) / range) as usize; - return (depth + 1, d_g, nb); - }), - ); - queue.sort_by(|b, a| { - let (a_0, a_1) = (a.0 as f32, a.1 as f32); - let (b_0, b_1) = (b.0 as f32, b.1 as f32); - let v_a = a_0 + a_1 * factor; - let v_b = b_0 + b_1 * factor; - return fcmp(v_a, v_b); - }); - // queue.reverse(); - } - } - println!(); - - println!(); - if !found { - eprintln!("No route from {} to {} found!", src_name, dst_name); - return Vec::new(); - } - let mut v: Vec = Vec::new(); - let mut curr_sys = goal_sys; - loop { - v.push(curr_sys.clone()); - match prev.get(&curr_sys.id) { - Some(sys) => curr_sys = *sys, - None => { - break; - } - } - } - v.reverse(); - return v; - } - - pub fn route_greedy( - &self, - src: &(&String, [f32; 3]), - dst: &(&String, [f32; 3]), - range: f32, - ) -> Vec { - println!("Running Greedy-Search"); - let (src_name, src) = src; - let (dst_name, dst) = dst; - let start_sys = self.closest(src); - let goal_sys = self.closest(dst); - { - let d = dist(src, dst); - println!("Plotting route from {} to {}...", src_name, dst_name); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", - range, - d, - d / range - ); - } - let total = self.tree.size() as f32; - let mut prev = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); - let mut found = false; - let mut maxd = 0; - let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); - queue.push((-goal_sys.mult, start_sys.distp2(goal_sys), 0, &start_sys)); - seen.insert(start_sys.id); - while !(queue.is_empty() || found) { - while let Some((_, _, depth, sys)) = queue.pop() { - if depth > maxd { - maxd = depth; - print!( - "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", - format_duration(t_start.elapsed()), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total - ); - std::io::stdout().flush().unwrap(); - } - if sys.id == goal_sys.id { - found = true; - break; - } - queue.extend( - self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys); - return (-nb.mult, nb.distp2(goal_sys), depth + 1, nb); - }), - ); - queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); - queue.reverse(); - } - } - println!(); - println!(); - if !found { - eprintln!("No route from {} to {} found!", src_name, dst_name); - return Vec::new(); - } - let mut v: Vec = Vec::new(); - let mut curr_sys = goal_sys; - loop { - v.push(curr_sys.clone()); - match prev.get(&curr_sys.id) { - Some(sys) => curr_sys = *sys, - None => { - break; - } - } - } - v.reverse(); - return v; - } - - pub fn precompute(&mut self, src: &String) { - println!("Precomputing route starting at {} ...", src); - let mut sys_l = self.name_to_systems(src); - sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8); - let sys = sys_l.last().unwrap(); - let total = self.tree.size() as f32; - let mut prev = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); - let mut depth = 0; - let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); - let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); - queue.push_front((0, &sys)); - seen.insert(sys.id); - while !queue.is_empty() { - print!( - "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", - format_duration(t_start.elapsed()), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total - ); - std::io::stdout().flush().unwrap(); - while let Some((d, sys)) = queue.pop_front() { - queue_next.extend( - self.neighbours(&sys, self.range) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys.id); - return (d + 1, nb); - }), - ); - } - std::mem::swap(&mut queue, &mut queue_next); - depth += 1; - } - self.route_tree = Some(prev); - } - - fn get_systems_by_ids(path: &PathBuf, ids: &Vec) -> FnvHashMap { - let mut ret = FnvHashMap::default(); - let mut reader = csv::ReaderBuilder::new() - .from_path(path) - .unwrap_or_else(|e| { - println!("Error opening {}: {}", path.to_str().unwrap(), e); - std::process::exit(1); - }); - reader - .deserialize::() - .map(|res| res.unwrap()) - .filter(|sys| ids.contains(&sys.id)) - .map(|sys| { - ret.insert( - sys.id, - System { - id: sys.id, - star_type: sys.star_type, - name: sys.name, - mult: sys.mult, - distance: sys.distance, - pos: [sys.x, sys.y, sys.z], - }, - ); - }) - .last() - .expect(&format!("No systems matching {:?} found!", ids)); - return ret; - } - - fn get_systems_by_names(path: &PathBuf, names: &Vec) -> FnvHashMap { - let mut ret = FnvHashMap::default(); - let mut reader = csv::ReaderBuilder::new() - .from_path(path) - .unwrap_or_else(|e| { - println!("Error opening {}: {}", path.to_str().unwrap(), e); - std::process::exit(1); - }); - reader - .deserialize::() - .map(|res| res.unwrap()) - .filter(|sys| names.contains(&sys.name)) - .map(|sys| { - ret.insert( - sys.name.clone(), - System { - id: sys.id, - star_type: sys.star_type, - name: sys.name, - mult: sys.mult, - distance: sys.distance, - pos: [sys.x, sys.y, sys.z], - }, - ); - }) - .last() - .expect(&format!("No systems matching {:?} found!", names)); - return ret; - } - - fn get_system_by_name(path: &PathBuf, name: &str) -> System { - let mut reader = csv::ReaderBuilder::new() - .from_path(path) - .unwrap_or_else(|e| { - println!("Error opening {}: {}", path.to_str().unwrap(), e); - std::process::exit(1); - }); - let sys = reader - .deserialize::() - .map(|res| res.unwrap()) - .find(|sys| sys.name == name) - .expect(&format!("System '{}' not found!", name)); - return System { - id: sys.id, - star_type: sys.star_type, - name: sys.name, - mult: sys.mult, - distance: sys.distance, - pos: [sys.x, sys.y, sys.z], - }; - } - - pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Vec { - let prev = self.route_tree.as_ref().unwrap(); - let dst = Self::get_system_by_name(&systems_path, dst); - if !prev.contains_key(&dst.id) { - eprintln!("System-ID {} not found", dst.id); - std::process::exit(1); - }; - let mut v_ids: Vec = Vec::new(); - let mut v: Vec = Vec::new(); - let mut curr_sys: u32 = dst.id; - loop { - v_ids.push(curr_sys); - match prev.get(&curr_sys) { - Some(sys_id) => curr_sys = *sys_id, - None => { - break; - } - } - } - v_ids.reverse(); - let id_map = Self::get_systems_by_ids(&systems_path, &v_ids); - for sys_id in v_ids { - let sys = id_map.get(&sys_id).unwrap(); - v.push(sys.clone()) - } - return v; - } - - pub fn route_bfs( - &self, - src: &(&String, [f32; 3]), - dst: &(&String, [f32; 3]), - range: f32, - ) -> Vec { - println!("Running BFS"); - let (src_name, src) = src; - let (dst_name, dst) = dst; - let start_sys = self.closest(src); - let goal_sys = self.closest(dst); - { - let d = dist(src, dst); - println!("Plotting route from {} to {}...", src_name, dst_name); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", - range, - d, - d / range - ); - } - let total = self.tree.size() as f32; - let mut prev = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); - let mut depth = 0; - let mut found = false; - let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); - let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); - queue.push_front((0, &start_sys)); - seen.insert(start_sys.id); - while !(queue.is_empty() || found) { - print!( - "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", - format_duration(t_start.elapsed()), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total - ); - std::io::stdout().flush().unwrap(); - while let Some((d, sys)) = queue.pop_front() { - if sys.id == goal_sys.id { - found = true; - break; - } - queue_next.extend( - self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys); - return (d + 1, nb); - }), - ); - } - std::mem::swap(&mut queue, &mut queue_next); - depth += 1; - } - println!(); - println!(); - if !found { - eprintln!("No route from {} to {} found!", src_name, dst_name); - return Vec::new(); - } - let mut v: Vec = Vec::new(); - let mut curr_sys = goal_sys; - loop { - v.push(curr_sys.clone()); - match prev.get(&curr_sys.id) { - Some(sys) => curr_sys = *sys, - None => { - break; - } - } - } - v.reverse(); - return v; - } -} - -fn main() { +fn main() -> std::io::Result<()> { let t_start = Instant::now(); let opts = Opts::from_args(); - if opts.systems.len() == 0 { - if opts.precomp_file.is_some() { - eprintln!("Error: Please specify exatly one system"); - } else { - if opts.precompute { - eprintln!("Error: Please specify at least one system"); - } else { - eprintln!("Error: Please specify at least two systems"); - } - } - std::process::exit(1); - } - let mut path = opts.file_path; - let mut router: Router = if opts.precomp_file.is_some() { - let ret = Router::from_file(&opts.precomp_file.clone().unwrap()); - path = ret.0; - ret.1 - } else { - Router::new(&path, opts.range.unwrap(), opts.primary) + let ret = match opts { + Opts::Route(opts) => route(opts), + Opts::Preprocess(opts) => preprocess_files(opts), }; - if opts.precompute { - for sys in opts.systems { - router.route_tree = None; - router.precompute(&sys); - let ofn = format!( - "{}_{}{}.router", - sys.replace("*", "").replace(" ", "_"), - opts.range.unwrap(), - if router.primary_only { "_primary" } else { "" } - ); - println!("\nSaving to {}", ofn); - let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); - // (range, path, route_tree) - let data = ( - router.primary_only, - router.range, - hash_file(&path), - String::from(path.to_str().unwrap()), - router.route_tree.unwrap(), - ); - bincode::serialize_into(&mut out_fh, &data).unwrap(); - } - std::process::exit(0); - } - let t_route = Instant::now(); - let route = if router.route_tree.is_some() { - router.route_to(opts.systems.first().unwrap(), &path) - } else { - if opts.permute || opts.full_permute { - router.best_name_multiroute( - &opts.systems, - opts.range.unwrap(), - opts.full_permute, - opts.mode, - opts.factor.unwrap_or(1.0), - ) - } else { - router.name_multiroute( - &opts.systems, - opts.range.unwrap(), - opts.mode, - opts.factor.unwrap_or(1.0), - ) - } - }; - println!("Route computed in {}\n", format_duration(t_route.elapsed())); - if route.is_empty() { - eprintln!("No route found!"); - return; - } - let mut total: f32 = 0.0; - for (sys1, sys2) in route.iter().zip(route.iter().skip(1)) { - let dist = sys1.distp(sys2); - total += dist; - println!( - "{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly", - sys1.name, sys1.star_type, sys1.pos[0], sys1.pos[1], sys1.pos[2], sys1.distance, dist - ); - } - let sys = route.iter().last().unwrap(); - println!( - "{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly", - sys.name, sys.star_type, sys.pos[0], sys.pos[1], sys.pos[2], sys.distance, 0.0 - ); - println!("Total: {:.2} Ly ({} Jumps)", total, route.len()); println!("Total time: {}", format_duration(t_start.elapsed())); + ret } diff --git a/src/preprocess.rs b/src/preprocess.rs new file mode 100644 index 0000000..baf3377 --- /dev/null +++ b/src/preprocess.rs @@ -0,0 +1,220 @@ +use crate::common::SystemSerde; +use fnv::FnvHashMap; +use humantime::format_duration; +use indicatif::{ProgressBar, ProgressStyle}; +use serde::Deserialize; +use serde_json::Result; +use std::fs::File; +use std::io::Seek; +use std::io::{BufRead, BufReader, BufWriter, SeekFrom}; +use std::path::PathBuf; +use std::str; +use std::time::Instant; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +pub struct PreprocessOpts { + #[structopt(short, long = "bodies")] + /// Path to bodies.json + pub bodies: PathBuf, + #[structopt(short, long = "systems")] + /// Path to systemsWithCoordinates.json + pub systems: PathBuf, + #[structopt(default_value = "stars")] + /// outfile prefix + pub prefix: String, +} + +#[derive(Debug, Deserialize)] +#[allow(non_snake_case)] +struct Body { + name: String, + subType: String, + #[serde(rename = "type")] + body_type: String, + systemId: i32, + systemId64: i64, + #[serde(rename = "distanceToArrival")] + distance: u32, +} + +#[derive(Debug, Deserialize)] +struct Coords { + x: f32, + y: f32, + z: f32, +} + +#[derive(Debug, Deserialize)] +struct System { + id: i32, + id64: i64, + name: String, + coords: Coords, + date: String, +} + +#[derive(Debug, StructOpt)] +#[structopt( + name = "ed_lrr_pp", + about = "Preprocessor for Elite: Dangerous Long-Range Router", + rename_all = "snake_case" +)] +/// Preprocess data for ed_lrr +struct Opt { + #[structopt(short, long = "bodies")] + /// Path to bodies.json + bodies: PathBuf, + #[structopt(short, long = "systems")] + /// Path to systemsWithCoordinates.json + systems: PathBuf, + #[structopt(default_value = "stars")] + /// outfile prefix + prefix: String, +} + +fn get_mult(star_type: &str) -> f32 { + if star_type.contains("White Dwarf") { + return 1.5; + } + if star_type.contains("Neutron") { + return 4.0; + } + 1.0 +} + +fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std::io::Result<()> { + let mut cnt = 0; + let mut buffer = String::new(); + let t_start = Instant::now(); + let fh = File::open(path)?; + let prog_bar = ProgressBar::new(fh.metadata()?.len()); + prog_bar.set_style( + ProgressStyle::default_bar() + .template( + "[{elapsed_precise}/{eta_precise}]{spinner} [{wide_bar}] {binary_bytes}/{binary_total_bytes} ({percent}%)", + ) + .progress_chars("#9876543210 ") + .tick_chars("/-\\|"), + ); + prog_bar.set_draw_delta(1024 * 1024); + let mut reader = BufReader::new(fh); + println!("Loading {} ...", path.to_str().unwrap()); + while let Ok(n) = reader.read_line(&mut buffer) { + if n == 0 { + break; + } + buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string(); + if !buffer.is_empty() { + func(&buffer); + } + prog_bar.set_position(reader.seek(SeekFrom::Current(0)).unwrap()); + cnt += 1; + buffer.clear(); + } + prog_bar.finish_and_clear(); + println!( + "Processed {} lines in {} ...", + cnt, + format_duration(t_start.elapsed()) + ); + Ok(()) +} + +fn process_systems(path: &PathBuf) -> FnvHashMap { + let mut ret = FnvHashMap::default(); + process(path, &mut |line| { + let sys_res: Result = serde_json::from_str(&line); + if let Ok(sys) = sys_res { + ret.insert(sys.id64, sys); + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); + } + }) + .unwrap(); + ret +} + +fn build_index(path: &PathBuf) -> std::io::Result<()> { + let mut wtr = BufWriter::new(File::create(path.with_extension("idx"))?); + let mut idx: Vec = Vec::new(); + let mut records = (csv::Reader::from_path(path)?).into_deserialize::(); + loop { + idx.push(records.reader().position().byte()); + if records.next().is_none() { + break; + } + } + bincode::serialize_into(&mut wtr, &idx).unwrap(); + Ok(()) +} + +fn process_bodies( + path: &PathBuf, + out_prefix: &str, + systems: &mut FnvHashMap, +) -> std::io::Result<()> { + let out_path = PathBuf::from(format!("{}.csv", out_prefix)); + println!( + "Processing {} into {} ...", + path.to_str().unwrap(), + out_path.to_str().unwrap(), + ); + let mut n: u32 = 0; + let mut wtr = csv::Writer::from_path(out_path)?; + process(path, &mut |line| { + if !line.contains("Star") { + return; + } + let body_res: Result = serde_json::from_str(&line); + if let Ok(body) = body_res { + if !body.body_type.contains("Star") { + return; + } + if let Some(sys) = systems.get(&body.systemId64) { + let sub_type = body.subType; + let mult = get_mult(&sub_type); + let sys_name = sys.name.clone(); + let mut body_name = body.name.replace(&sys_name, "").trim().to_string(); + if body_name == sys_name { + body_name = "".to_string(); + } + let rec = SystemSerde { + id: n, + star_type: sub_type, + system: sys_name, + body: body_name, + mult, + distance: body.distance, + x: sys.coords.x, + y: sys.coords.y, + z: sys.coords.z, + }; + wtr.serialize(rec).unwrap(); + n += 1; + }; + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); + } + }) + .unwrap(); + println!("Total Systems: {}", n); + systems.clear(); + Ok(()) +} + +pub fn preprocess_files(opts: PreprocessOpts) -> std::io::Result<()> { + let out_path = PathBuf::from(format!("{}.csv", &opts.prefix)); + if !out_path.exists() { + let mut systems = process_systems(&opts.systems); + process_bodies(&opts.bodies, &opts.prefix, &mut systems)?; + } else { + println!( + "File '{}' exists, not overwriting it", + out_path.to_str().unwrap() + ); + } + println!("Building index..."); + println!("Index result: {:?}", build_index(&out_path)); + Ok(()) +} diff --git a/src/route.rs b/src/route.rs new file mode 100644 index 0000000..4d5b8c8 --- /dev/null +++ b/src/route.rs @@ -0,0 +1,913 @@ +use core::cmp::Ordering; +use csv::StringRecord; +use fnv::{FnvHashMap, FnvHashSet}; +use humantime::format_duration; +use permutohedron::LexicalPermutation; +use rstar::{PointDistance, RTree, RTreeObject, AABB}; +use sha3::{Digest, Sha3_256}; +use std::collections::VecDeque; +use std::fs::File; +use std::hash::{Hash, Hasher}; +use std::io::Seek; +use std::io::{BufRead, BufReader, BufWriter, Write}; +use std::path::PathBuf; +use std::str::FromStr; +use std::time::Instant; +use structopt::StructOpt; + +use crate::common::{System, SystemSerde}; + +#[derive(Debug, StructOpt)] +pub struct RouteOpts { + #[structopt(short, long = "range")] + /// Jump Range + pub range: Option, + #[structopt( + parse(from_os_str), + short = "i", + long = "path", + default_value = "./stars.csv" + )] + /// Path to stars.csv + /// + /// Generate using ed_lrr_pp + pub file_path: PathBuf, + + #[structopt( + parse(from_os_str), + long = "precomp_file", + conflicts_with = "precompute" + )] + /// Path to precomputed route graph + /// + /// Generate using --precompute option + pub precomp_file: Option, + + #[structopt( + short = "c", + long = "precompute", + conflicts_with = "full_permute", + conflicts_with = "permute", + conflicts_with = "precomp_file" + )] + /// Precompute all routes for the specified jump range starting at the specified system and write the result to {system}_{range}.bin + pub precompute: bool, + + #[structopt(short = "p", long = "permute", conflicts_with = "full_permute")] + /// Permute intermediate hops to find shortest route + pub permute: bool, + + #[structopt(short = "o", long = "primary")] + /// Only route through the primary star of a system + pub primary: bool, + + #[structopt(short = "f", long = "full_permute", conflicts_with = "permute")] + /// Permute all hops to find shortest route + pub full_permute: bool, + + #[structopt(short = "g", long = "factor")] + /// Greedyness factor for A-Star (0=BFS, inf=Greedy) + pub factor: Option, + + #[structopt( + short, + long, + raw(possible_values = "&[\"bfs\", \"greedy\",\"astar\"]"), + default_value = "bfs" + )] + /// Search mode + /// + /** + - BFS is guaranteed to find the shortest route but very slow + - Greedy is a lot faster but will probably not find the shortest route + - A-Star is a good middle ground between speed and accuracy + */ + pub mode: Mode, + /// Systems to route through + pub systems: Vec, +} + +#[derive(Debug)] +pub enum Mode { + BFS, + Greedy, + AStar, +} + +impl FromStr for Mode { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "bfs" => Ok(Mode::BFS), + "greedy" => Ok(Mode::Greedy), + "astar" => Ok(Mode::AStar), + _ => Err("Invalid Mode".to_string()), + } + } +} + +fn dist2(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + let dx = p1[0] - p2[0]; + let dy = p1[1] - p2[1]; + let dz = p1[2] - p2[2]; + + dx * dx + dy * dy + dz * dz +} + +fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + dist2(p1, p2).sqrt() +} + +fn fcmp(a: f32, b: f32) -> Ordering { + match (a, b) { + (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, + (x, _) if x.is_nan() => Ordering::Greater, + (_, y) if y.is_nan() => Ordering::Less, + (..) => a.partial_cmp(&b).unwrap(), + } +} + +impl System { + pub fn dist2(&self, p: &[f32; 3]) -> f32 { + dist2(&self.pos, p) + } + pub fn distp(&self, p: &System) -> f32 { + dist(&self.pos, &p.pos) + } + pub fn distp2(&self, p: &System) -> f32 { + self.dist2(&p.pos) + } +} +impl PartialEq for System { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for System {} + +impl Hash for System { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl RTreeObject for System { + type Envelope = AABB<[f32; 3]>; + + fn envelope(&self) -> Self::Envelope { + AABB::from_point(self.pos) + } +} + +impl PointDistance for System { + fn distance_2(&self, point: &[f32; 3]) -> f32 { + self.dist2(&point) + } +} + +fn hash_file(path: &PathBuf) -> Vec { + let mut hash_reader = BufReader::new(File::open(path).unwrap()); + let mut hasher = Sha3_256::new(); + std::io::copy(&mut hash_reader, &mut hasher).unwrap(); + hasher.result().iter().copied().collect() +} + +struct LineCache { + cache: Vec, + file: BufReader, + header: Option, +} + +impl LineCache { + pub fn new(path: &PathBuf) -> std::io::Result { + let idx_path = path.with_extension("idx"); + let t_load = Instant::now(); + println!("Loading {}", path.to_str().unwrap()); + let mut idx_reader = BufReader::new(File::open(idx_path)?); + let cache = match bincode::deserialize_from(&mut idx_reader) { + Ok(value) => value, + err => err.unwrap(), + }; + let mut reader = BufReader::new(File::open(path)?); + let header = Self::read_record(&mut reader); + let ret = Self { + file: reader, + cache, + header, + }; + println!("Done in {}!", format_duration(t_load.elapsed())); + Ok(ret) + } + fn read_record(reader: &mut BufReader) -> Option { + let mut line = String::new(); + reader.read_line(&mut line).ok()?; + let v: Vec<_> = line.trim_end().split(',').collect(); + let rec = StringRecord::from(v); + Some(rec) + } + pub fn get(&mut self, id: u32) -> Option { + let pos = self.cache[id as usize]; + self.file.seek(std::io::SeekFrom::Start(pos)).unwrap(); + let rec = Self::read_record(&mut self.file).unwrap(); + let sys: SystemSerde = rec.deserialize(self.header.as_ref()).unwrap(); + Some(sys.build()) + } +} + +pub struct Router { + tree: RTree, + scoopable: FnvHashSet, + pub route_tree: Option>, + cache: Option, + range: f32, + primary_only: bool, + path: PathBuf, +} + +impl Router { + pub fn new(path: &PathBuf, range: f32, primary_only: bool) -> Self { + let mut scoopable = FnvHashSet::default(); + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + println!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + let t_load = Instant::now(); + println!("Loading {}...", path.to_str().unwrap()); + let systems: Vec = reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| { + if primary_only { + sys.distance == 0 + } else { + true + } + }) + .map(|sys| { + if sys.mult > 1.0f32 { + scoopable.insert(sys.id); + } else { + for c in "KGBFOAM".chars() { + if sys.star_type.starts_with(c) { + scoopable.insert(sys.id); + break; + } + } + } + sys.build() + }) + .collect(); + println!("Building RTree..."); + let ret = Self { + tree: RTree::bulk_load(systems), + scoopable, + route_tree: None, + range, + primary_only, + cache: LineCache::new(path).ok(), + path: path.clone(), + }; + println!( + "{} Systems loaded in {}", + ret.tree.size(), + format_duration(t_load.elapsed()) + ); + ret + } + + pub fn from_file(filename: &PathBuf) -> (PathBuf, Self) { + let t_load = Instant::now(); + let mut reader = BufReader::new(File::open(&filename).unwrap()); + println!("Loading {}", filename.to_str().unwrap()); + let (primary, range, file_hash, path, route_tree): ( + bool, + f32, + Vec, + String, + FnvHashMap, + ) = bincode::deserialize_from(&mut reader).unwrap(); + let path = PathBuf::from(path); + println!("Done in {}!", format_duration(t_load.elapsed())); + if hash_file(&path) != file_hash { + panic!("File hash mismatch!") + } + let cache = LineCache::new(&path).ok(); + ( + path.clone(), + Self { + tree: RTree::default(), + scoopable: FnvHashSet::default(), + route_tree: Some(route_tree), + range, + cache, + primary_only: primary, + path, + }, + ) + } + + fn closest(&self, point: &[f32; 3]) -> &System { + self.tree.nearest_neighbor(point).unwrap() + } + fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { + self.tree.locate_within_distance(*center, radius * radius) + } + + fn neighbours(&self, sys: &System, r: f32) -> impl Iterator { + self.points_in_sphere(&sys.pos, sys.mult * r) + } + + fn valid(&self, sys: &System) -> bool { + self.scoopable.contains(&sys.id) + } + + pub fn best_name_multiroute( + &self, + waypoints: &[String], + range: f32, + full: bool, + mode: Mode, + factor: f32, + ) -> Vec { + let mut best_score: f32 = std::f32::MAX; + let mut waypoints = waypoints.to_owned(); + let mut best_permutation_waypoints = waypoints.to_owned(); + let first = waypoints.first().cloned(); + let last = waypoints.last().cloned(); + let t_start = Instant::now(); + println!("Finding best permutation of hops..."); + while waypoints.prev_permutation() {} + loop { + let c_first = waypoints.first().cloned(); + let c_last = waypoints.last().cloned(); + if full || ((c_first == first) && (c_last == last)) { + let mut total_d = 0.0; + for pair in waypoints.windows(2) { + match pair { + [src, dst] => { + let (mut src, dst) = + (self.name_to_systems(&src), self.name_to_systems(&dst)); + src.sort_by_key(|&p| (p.mult * 10.0) as u8); + let src = src.last().unwrap(); + let dst = dst.last().unwrap(); + total_d += src.distp2(dst); + } + _ => panic!("Invalid routing parameters!"), + } + } + if total_d < best_score { + best_score = total_d; + best_permutation_waypoints = waypoints.to_owned(); + } + } + if !waypoints.next_permutation() { + break; + } + } + + println!("Done in {}!", format_duration(t_start.elapsed())); + println!("Best permutation: {:?}", best_permutation_waypoints); + self.name_multiroute(&best_permutation_waypoints, range, mode, factor) + } + + pub fn name_multiroute( + &self, + waypoints: &[String], + range: f32, + mode: Mode, + factor: f32, + ) -> Vec { + let mut coords = Vec::new(); + for p_name in waypoints { + let mut p_l = self.name_to_systems(p_name); + p_l.sort_by_key(|&p| (p.mult * 10.0) as u8); + let p = p_l.last().unwrap(); + coords.push((p_name, p.pos)); + } + self.multiroute(coords.as_slice(), range, mode, factor) + } + pub fn multiroute( + &self, + waypoints: &[(&String, [f32; 3])], + range: f32, + mode: Mode, + factor: f32, + ) -> Vec { + let mut route: Vec = Vec::new(); + for pair in waypoints.windows(2) { + match *pair { + [src, dst] => { + let block = match mode { + Mode::BFS => self.route_bfs(&src, &dst, range), + Mode::Greedy => self.route_greedy(&src, &dst, range), + Mode::AStar => self.route_astar(&src, &dst, range, factor), + }; + if route.is_empty() { + for sys in block.iter() { + route.push(sys.clone()); + } + } else { + for sys in block.iter().skip(1) { + route.push(sys.clone()); + } + } + } + _ => panic!("Invalid routing parameters!"), + } + } + route + } + + fn name_to_systems(&self, name: &str) -> Vec<&System> { + for sys in &self.tree { + if sys.system == name { + return self.neighbours(&sys, 0.0).collect(); + } + } + eprintln!("System not found: \"{}\"", name); + std::process::exit(1); + } + + pub fn route_astar( + &self, + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), + range: f32, + factor: f32, + ) -> Vec { + if factor == 0.0 { + return self.route_bfs(src, dst, range); + } + println!("Running A-Star with greedy factor of {}", factor); + let (src_name, src) = src; + let (dst_name, dst) = dst; + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + { + let d = dist(src, dst); + println!("Plotting route from {} to {}...", src_name, dst_name); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut found = false; + let mut maxd = 0; + let mut queue: Vec<(usize, usize, &System)> = Vec::new(); + queue.push(( + 0, // depth + (start_sys.distp(goal_sys) / range) as usize, // h + &start_sys, + )); + seen.insert(start_sys.id); + + while !(queue.is_empty() || found) { + while let Some((depth, _, sys)) = queue.pop() { + if depth > maxd { + maxd = depth; + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + } + if sys.id == goal_sys.id { + found = true; + break; + } + queue.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys); + let d_g = (nb.distp(goal_sys) / range) as usize; + (depth + 1, d_g, nb) + }), + ); + queue.sort_by(|b, a| { + let (a_0, a_1) = (a.0 as f32, a.1 as f32); + let (b_0, b_1) = (b.0 as f32, b.1 as f32); + let v_a = a_0 + a_1 * factor; + let v_b = b_0 + b_1 * factor; + fcmp(v_a, v_b) + }); + // queue.reverse(); + } + } + println!(); + + println!(); + if !found { + eprintln!("No route from {} to {} found!", src_name, dst_name); + return Vec::new(); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, + None => { + break; + } + } + } + v.reverse(); + v + } + + pub fn route_greedy( + &self, + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), + range: f32, + ) -> Vec { + println!("Running Greedy-Search"); + let (src_name, src) = src; + let (dst_name, dst) = dst; + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + { + let d = dist(src, dst); + println!("Plotting route from {} to {}...", src_name, dst_name); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut found = false; + let mut maxd = 0; + let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); + queue.push((-goal_sys.mult, start_sys.distp2(goal_sys), 0, &start_sys)); + seen.insert(start_sys.id); + while !(queue.is_empty() || found) { + while let Some((_, _, depth, sys)) = queue.pop() { + if depth > maxd { + maxd = depth; + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + } + if sys.id == goal_sys.id { + found = true; + break; + } + queue.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys); + (-nb.mult, nb.distp2(goal_sys), depth + 1, nb) + }), + ); + queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); + queue.reverse(); + } + } + println!(); + println!(); + if !found { + eprintln!("No route from {} to {} found!", src_name, dst_name); + return Vec::new(); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, + None => { + break; + } + } + } + v.reverse(); + v + } + + pub fn precompute(&mut self, src: &str) { + let mut sys_l = self.name_to_systems(src); + sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8); + let sys = sys_l.last().unwrap(); + println!("Precomputing routes starting at {} ...", sys.system); + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut depth = 0; + let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); + queue.push_front((0, &sys)); + seen.insert(sys.id); + while !queue.is_empty() { + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + while let Some((d, sys)) = queue.pop_front() { + queue_next.extend( + self.neighbours(&sys, self.range) + // .filter(|&nb| self.valid(nb)) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys.id); + (d + 1, nb) + }), + ); + } + std::mem::swap(&mut queue, &mut queue_next); + depth += 1; + } + self.route_tree = Some(prev); + let ofn = format!( + "{}_{}{}.router", + src.replace("*", "").replace(" ", "_"), + self.range, + if self.primary_only { "_primary" } else { "" } + ); + println!("\nSaving to {}", ofn); + let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); + // (range, path, route_tree) + let data = ( + self.primary_only, + self.range, + hash_file(&self.path), + String::from(self.path.to_str().unwrap()), + self.route_tree.as_ref().unwrap(), + ); + bincode::serialize_into(&mut out_fh, &data).unwrap(); + } + + fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> FnvHashMap { + println!("Processing {}", path.to_str().unwrap()); + let mut ret = FnvHashMap::default(); + if let Some(c) = &mut self.cache.as_mut() { + let mut missing = false; + for id in ids { + match c.get(*id) { + Some(sys) => { + ret.insert(*id, sys); + } + None => { + println!("ID {} not found in cache", id); + missing = true; + break; + } + } + } + if !missing { + return ret; + } + } + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + println!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| ids.contains(&sys.id)) + .map(|sys| { + ret.insert(sys.id, sys.build()); + }) + .last() + .unwrap_or_else(|| { + eprintln!("Error: No systems matching {:?} found!", ids); + std::process::exit(1); + }); + ret + } + + fn get_system_by_name(path: &PathBuf, name: &str) -> System { + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + eprintln!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + let sys = reader + .deserialize::() + .map(|res| res.unwrap()) + .find(|sys| sys.system == name) + .unwrap_or_else(|| { + eprintln!("Error: System '{}' not found!", name); + std::process::exit(1); + }); + sys.build() + } + + pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Vec { + let prev = self.route_tree.as_ref().unwrap(); + let dst = Self::get_system_by_name(&systems_path, dst); + if !prev.contains_key(&dst.id) { + eprintln!("System-ID {} not found", dst.id); + std::process::exit(1); + }; + let mut v_ids: Vec = Vec::new(); + let mut v: Vec = Vec::new(); + let mut curr_sys: u32 = dst.id; + loop { + v_ids.push(curr_sys); + match prev.get(&curr_sys) { + Some(sys_id) => curr_sys = *sys_id, + None => { + break; + } + } + } + v_ids.reverse(); + let id_map = self.get_systems_by_ids(&systems_path, &v_ids); + for sys_id in v_ids { + let sys = id_map.get(&sys_id).unwrap(); + v.push(sys.clone()) + } + v + } + + pub fn route_bfs( + &self, + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), + range: f32, + ) -> Vec { + println!("Running BFS"); + let (src_name, src) = src; + let (dst_name, dst) = dst; + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + { + let d = dist(src, dst); + println!("Plotting route from {} to {}...", src_name, dst_name); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut depth = 0; + let mut found = false; + let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); + queue.push_front((0, &start_sys)); + seen.insert(start_sys.id); + while !(queue.is_empty() || found) { + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + while let Some((d, sys)) = queue.pop_front() { + if sys.id == goal_sys.id { + found = true; + break; + } + queue_next.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys); + (d + 1, nb) + }), + ); + } + std::mem::swap(&mut queue, &mut queue_next); + depth += 1; + } + println!(); + println!(); + if !found { + eprintln!("No route from {} to {} found!", src_name, dst_name); + return Vec::new(); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, + None => { + break; + } + } + } + v.reverse(); + v + } +} +pub fn route(opts: RouteOpts) -> std::io::Result<()> { + if opts.systems.is_empty() { + if opts.precomp_file.is_some() { + eprintln!("Error: Please specify exatly one system"); + } else if opts.precompute { + eprintln!("Error: Please specify at least one system"); + } else { + eprintln!("Error: Please specify at least two systems"); + } + std::process::exit(1); + } + let mut path = opts.file_path; + let mut router: Router = if opts.precomp_file.is_some() { + let ret = Router::from_file(&opts.precomp_file.clone().unwrap()); + path = ret.0; + ret.1 + } else { + Router::new(&path, opts.range.unwrap(), opts.primary) + }; + if opts.precompute { + for sys in opts.systems { + router.route_tree = None; + router.precompute(&sys); + } + std::process::exit(0); + } + let t_route = Instant::now(); + let route = if router.route_tree.is_some() { + router.route_to(opts.systems.first().unwrap(), &path) + } else if opts.permute || opts.full_permute { + router.best_name_multiroute( + &opts.systems, + opts.range.unwrap(), + opts.full_permute, + opts.mode, + opts.factor.unwrap_or(1.0), + ) + } else { + router.name_multiroute( + &opts.systems, + opts.range.unwrap(), + opts.mode, + opts.factor.unwrap_or(1.0), + ) + }; + println!("Route computed in {}\n", format_duration(t_route.elapsed())); + if route.is_empty() { + eprintln!("No route found!"); + return Ok(()); + } + let mut total: f32 = 0.0; + for (sys1, sys2) in route.iter().zip(route.iter().skip(1)) { + let dist = sys1.distp(sys2); + total += dist; + println!( + "{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly", + format!("{} {}", sys1.system, sys1.system).trim_end(), + sys1.star_type, + sys1.pos[0], + sys1.pos[1], + sys1.pos[2], + sys1.distance, + dist + ); + } + let sys = route.iter().last().unwrap(); + println!( + "{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly", + sys.system, sys.star_type, sys.pos[0], sys.pos[1], sys.pos[2], sys.distance, 0.0 + ); + println!("Total: {:.2} Ly ({} Jumps)", total, route.len()); + Ok(()) +} From 2b9779193727df3346972575f37682db1d691e56 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 5 Jul 2019 01:05:17 +0200 Subject: [PATCH 16/72] Fix formatting error in route printout --- src/bin/ed_lrr_pp.rs | 188 ------------------------------------------- src/route.rs | 2 +- 2 files changed, 1 insertion(+), 189 deletions(-) delete mode 100644 src/bin/ed_lrr_pp.rs diff --git a/src/bin/ed_lrr_pp.rs b/src/bin/ed_lrr_pp.rs deleted file mode 100644 index df0ec67..0000000 --- a/src/bin/ed_lrr_pp.rs +++ /dev/null @@ -1,188 +0,0 @@ -#![feature(seek_convenience)] -use fnv::FnvHashMap; -use humantime::format_duration; -use indicatif::{ProgressBar, ProgressStyle}; -use serde::{Deserialize, Serialize}; -use serde_json::Result; -use std::fs::File; -use std::io::{BufRead, BufReader, BufWriter, Seek}; -use std::path::PathBuf; -use std::str; -use std::time::Instant; -use structopt::StructOpt; - -#[derive(Debug, Clone, Serialize)] -struct Record { - id: u64, - star_type: String, - name: String, - mult: f32, - distance: u32, - x: f64, - y: f64, - z: f64, -} -#[derive(Debug, Deserialize)] -#[allow(non_snake_case)] -struct Body { - name: String, - subType: String, - #[serde(rename = "type")] - body_type: String, - systemId: i32, - systemId64: i64, - #[serde(rename = "distanceToArrival")] - distance: u32, -} - -#[derive(Debug, Deserialize)] -struct Coords { - x: f64, - y: f64, - z: f64, -} - -#[derive(Debug, Deserialize)] -struct System { - id: i32, - id64: i64, - name: String, - coords: Coords, - date: String, -} - -#[derive(Debug, StructOpt)] -#[structopt( - name = "ed_lrr_pp", - about = "Preprocessor for Elite: Dangerous Long-Range Router", - rename_all = "snake_case" -)] -/// Preprocess data for ed_lrr -struct Opt { - #[structopt(short, long = "bodies")] - /// Path to bodies.json - bodies: PathBuf, - #[structopt(short, long = "systems")] - /// Path to systemsWithCoordinates.json - systems: PathBuf, - #[structopt(default_value = "stars")] - /// outfile prefix - prefix: String, -} - -fn get_mult(star_type: &str) -> f32 { - if star_type.contains("White Dwarf") { - return 1.5; - } - if star_type.contains("Neutron") { - return 4.0; - } - return 1.0; -} - -fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std::io::Result<()> { - let mut cnt = 0; - let mut buffer = String::new(); - let t_start = Instant::now(); - let fh = File::open(path)?; - let prog_bar = ProgressBar::new(fh.metadata()?.len()); - prog_bar.set_style( - ProgressStyle::default_bar() - .template( - "[{elapsed_precise}/{eta_precise}]{spinner} [{wide_bar}] {binary_bytes}/{binary_total_bytes} ({percent}%)", - ) - .progress_chars("#9876543210 ") - .tick_chars("/-\\|"), - ); - prog_bar.set_draw_delta(1024 * 1024); - let mut reader = BufReader::new(fh); - println!("Loading {} ...", path.to_str().unwrap()); - while let Ok(n) = reader.read_line(&mut buffer) { - if n == 0 { - break; - } - buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string(); - if !buffer.is_empty() { - func(&buffer); - } - prog_bar.set_position(reader.stream_position().unwrap()); - cnt += 1; - buffer.clear(); - } - prog_bar.finish_and_clear(); - println!( - "Processed {} lines in {} ...", - cnt, - format_duration(t_start.elapsed()) - ); - return Ok(()); -} - -fn process_systems(path: &PathBuf) -> FnvHashMap { - let mut ret = FnvHashMap::default(); - process(path, &mut |line| { - let sys_res: Result = serde_json::from_str(&line); - if let Ok(sys) = sys_res { - ret.insert(sys.id64, sys); - } else { - eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); - } - }) - .unwrap(); - return ret; -} - -fn process_bodies( - path: &PathBuf, - out_prefix: &String, - systems: &FnvHashMap, -) -> std::io::Result<()> { - let out_path = PathBuf::from(format!("{}.csv", out_prefix)); - println!( - "Processing {} into {} ...", - path.to_str().unwrap(), - out_path.to_str().unwrap(), - ); - let mut n: u64 = 0; - let mut wtr = csv::Writer::from_writer(BufWriter::new(File::create(out_path).unwrap())); - process(path, &mut |line| { - if !line.contains("Star") { - return; - } - let body_res: Result = serde_json::from_str(&line); - if let Ok(body) = body_res { - if !body.body_type.contains("Star") { - return; - } - if let Some(sys) = systems.get(&body.systemId64) { - let sub_type = body.subType; - let mult = get_mult(&sub_type); - let body_name = body.name; - let rec = Record { - id: n, - star_type: sub_type, - name: body_name, - mult, - distance: body.distance, - x: sys.coords.x, - y: sys.coords.y, - z: sys.coords.z, - }; - wtr.serialize(rec).unwrap(); - n += 1; - }; - } else { - eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); - } - }) - .unwrap(); - println!("Total Systems: {}", n); - return Ok(()); -} - -fn main() -> std::io::Result<()> { - let opts = Opt::from_args(); - let systems = process_systems(&opts.systems); - process_bodies(&opts.bodies, &opts.prefix, &systems)?; - return Ok(()); -} diff --git a/src/route.rs b/src/route.rs index 4d5b8c8..336da7a 100644 --- a/src/route.rs +++ b/src/route.rs @@ -894,7 +894,7 @@ pub fn route(opts: RouteOpts) -> std::io::Result<()> { total += dist; println!( "{} [{}] ({},{},{}) [{} Ls]: {:.2} Ly", - format!("{} {}", sys1.system, sys1.system).trim_end(), + sys1.system, sys1.star_type, sys1.pos[0], sys1.pos[1], From a647d26337a2773ffa63ec808785a0046e912055 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 15 Jul 2019 00:43:57 +0200 Subject: [PATCH 17/72] Initial commit --- .gitignore | 10 + MANIFEST.in | 2 + README.md | 43 + build_gui.py | 13 + clean.bat | 5 + ed_lrr_gui/__init__.py | 2 + ed_lrr_gui/__main__.py | 235 ++++ ed_lrr_gui/config.py | 45 + ed_lrr_gui/gui/__init__.py | 0 ed_lrr_gui/gui/ed_lrr.py | 350 ++++++ ed_lrr_gui/gui/ed_lrr.ui | 584 ++++++++++ pyproject.toml | 2 + rust/.cargo/config | 2 + rust/Cargo.lock | 2091 ++++++++++++++++++++++++++++++++++++ rust/Cargo.toml | 34 + rust/src/common.rs | 38 + rust/src/download.rs | 63 ++ rust/src/lib.rs | 66 ++ rust/src/preprocess.rs | 220 ++++ rust/src/route.rs | 879 +++++++++++++++ setup.py | 23 + 21 files changed, 4707 insertions(+) create mode 100644 .gitignore create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 build_gui.py create mode 100644 clean.bat create mode 100644 ed_lrr_gui/__init__.py create mode 100644 ed_lrr_gui/__main__.py create mode 100644 ed_lrr_gui/config.py create mode 100644 ed_lrr_gui/gui/__init__.py create mode 100644 ed_lrr_gui/gui/ed_lrr.py create mode 100644 ed_lrr_gui/gui/ed_lrr.ui create mode 100644 pyproject.toml create mode 100644 rust/.cargo/config create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/src/common.rs create mode 100644 rust/src/download.rs create mode 100644 rust/src/lib.rs create mode 100644 rust/src/preprocess.rs create mode 100644 rust/src/route.rs create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86707f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/target +/dist +/build +**/*.rs.bk +*.tmp +*.idx +.vscode/** +build.bat +test.bat +__pycache__ \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..900cc3b --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include rust/Cargo.toml +recursive-include rust/src * \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..299b692 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# Testing + +```bash +conda create -n ed_lrr_gui_env python=3 +conda activate ed_lrr_gui_env +python build_gui.py +pip install -e . +rs_gui_test +``` + +# Building + +```bash +conda create -n ed_lrr_gui_env python=3 +conda activate ed_lrr_gui_env +python build_gui.py +python build_gui.py +python build_gui.py +pip install setuptools_rust +pip install . +python setup.py build +python setup.py bdist_wheel +python setup.py sdist +mkdir exe +cd exe +pyinstaller --noupx --name ed_lrr_gui ../ed_lrr_gui/__main__.py +pyinstaller --noupx --onefile --name ed_lrr_gui ../ed_lrr_gui/__main__.py +cd .. +``` + +# Clean + +```bash +rm -rfv _*.pyd *.pyc *.egg-info pip-wheel-metadata dist exe build __pycache__ +cd rust +cargo clean +cargo clean --release +cd .. +``` + +# TODO +- refactor ed_lrr to use callbacks +- integrate callbacks into the GUI \ No newline at end of file diff --git a/build_gui.py b/build_gui.py new file mode 100644 index 0000000..6327ad2 --- /dev/null +++ b/build_gui.py @@ -0,0 +1,13 @@ +import subprocess as SP +from glob import glob +import os + + +ui_path = os.path.dirname(os.path.abspath(__file__)) +for root, folders, files in os.walk(ui_path): + for file in files: + file = os.path.join(root, file) + outfile, ext = os.path.splitext(file) + if ext == ".ui": + outfile = outfile + ".py" + SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file]) diff --git a/clean.bat b/clean.bat new file mode 100644 index 0000000..098a107 --- /dev/null +++ b/clean.bat @@ -0,0 +1,5 @@ +rm -rfv _*.pyd *.egg-info pip-wheel-metadata dist exe build __pycache__ +cd rust +cargo clean +cargo clean --release +cd .. \ No newline at end of file diff --git a/ed_lrr_gui/__init__.py b/ed_lrr_gui/__init__.py new file mode 100644 index 0000000..2d1a9d6 --- /dev/null +++ b/ed_lrr_gui/__init__.py @@ -0,0 +1,2 @@ +from _ed_lrr import * +from . import gui diff --git a/ed_lrr_gui/__main__.py b/ed_lrr_gui/__main__.py new file mode 100644 index 0000000..7f83a54 --- /dev/null +++ b/ed_lrr_gui/__main__.py @@ -0,0 +1,235 @@ +import sys +from PyQt5.QtCore import QThread, pyqtSignal, Qt +from PyQt5.QtWidgets import ( + QMainWindow, + QApplication, + QFileDialog, + QProgressDialog, + QTreeWidgetItem, +) +from PyQt5.QtGui import QPalette, QColor +import ed_lrr_gui +import ed_lrr_gui.config as cfg +from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR +import os +from datetime import datetime + +# print(ed_lrr_gui.test({"a": 1, "b": 2})) +# exit(1) + + +class Progressdialog(QProgressDialog): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setWindowModality(Qt.WindowModal) + + +class App(QApplication): + def __init__(self): + super().__init__(sys.argv) + self.setStyle("Fusion") + self.set_pallete() + + def set_pallete(self): + colors = { + "Window": QColor(53, 53, 53), + "WindowText": Qt.white, + "Base": QColor(15, 15, 15), + "AlternateBase": QColor(53, 53, 53), + "ToolTipBase": Qt.white, + "ToolTipText": Qt.white, + "Text": Qt.white, + "Button": QColor(53, 53, 53), + "ButtonText": Qt.white, + "BrightText": Qt.red, + "Highlight": QColor(255, 128, 0), + "HighlightedText": Qt.black, + } + palette = QPalette() + for entry, color in colors.items(): + palette.setColor(getattr(QPalette, entry), color) + if color == Qt.darkGray: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) + ) + else: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray + ) + self.setPalette(palette) + + +class ED_LRR(Ui_ED_LRR): + pbar_thread = None + + def __init__(self): + super().__init__() + self.config = cfg.load() + + def get_open_file(self, filetypes, callback=None): + fileName, _ = QFileDialog.getOpenFileName( + self.main_window, + "Open file", + str(cfg.data_dir), + filetypes, + options=QFileDialog.DontUseNativeDialog, + ) + if callback: + return callback(fileName) + return fileName + + def get_save_file(self, filetypes, callback=None): + fileName, _ = QFileDialog.getSaveFileName( + self.main_window, + "Save file", + str(cfg.data_dir), + filetypes, + options=QFileDialog.DontUseNativeDialog, + ) + if callback: + return callback(fileName) + return fileName + + def set_sys_lst(self, path): + if path not in self.config.history_out_path: + self.config.history_out_path.append(path) + self.inp_sys_lst.addItem(path) + self.inp_out_pp.addItem(path) + + def set_bodies_file(self, path): + if path not in self.config.history_bodies_path: + self.config.history_bodies_path.append(path) + self.inp_bodies_pp.addItem(path) + + def set_systems_file(self, path): + if path not in self.config.history_systems_path: + self.config.history_systems_path.append(path) + self.inp_systems_pp.addItem(path) + + def update_dropdowns(self): + return + + def log(self, *args): + t = datetime.today() + msg_t = "[{}] {}".format(t, str.format(*args)) + self.txt_log.append(msg_t) + + def set_comp_mode(self, _): + if self.rd_comp.isChecked(): + comp_mode = "Compute Route" + self.btn_add.setText("Search+Add") + self.lst_sys.setEnabled(True) + self.btn_rm.setEnabled(True) + self.cmb_mode.setEnabled(True) + mode = self.cmb_mode.currentText() + self.set_route_mode(mode) + if self.rd_precomp.isChecked(): + comp_mode = "Precompute Graph" + self.btn_add.setText("Select") + self.lst_sys.setEnabled(False) + self.btn_rm.setEnabled(False) + self.lbl_greedyness.setEnabled(False) + self.sld_greedyness.setEnabled(False) + self.cmb_mode.setEnabled(False) + + def set_route_mode(self, mode): + self.lbl_greedyness.setEnabled(mode == "A*-Search") + self.sld_greedyness.setEnabled(mode == "A*-Search") + + def set_greedyness(self, value): + val = value / 100 + self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(val)) + + def sys_to_dict(self, n): + header = [ + self.lst_sys.headerItem().data(c, 0) + for c in range(self.lst_sys.headerItem().columnCount()) + ] + system = [ + self.lst_sys.topLevelItem(n).data(c, 0) + for c in range(self.lst_sys.topLevelItem(n).columnCount()) + ] + return dict(zip(header, system)) + + def run(self): + settings = {} + settings["permute"] = [None, False, True][self.chk_permute_keep.checkState()] + settings["range"] = self.sb_range.value() + settings["systems"] = [ + self.sys_to_dict(i) for i in range(self.lst_sys.topLevelItemCount()) + ] + print(settings) + # progress = Progressdialog("TEST\nBLAH", "Cancel", 0, 0, self.main_window) + # progress.setWindowTitle("Computing Route") + # progress.setFixedSize(400, 100) + # progress.setRange(0, 0) + # progress.show() + + def add_system(self): + n = self.lst_sys.topLevelItemCount() + 1 + item = QTreeWidgetItem(self.lst_sys, ["A" + str(n), "B" + str(n)]) + item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) + + def remove_system(self): + root = self.lst_sys.invisibleRootItem() + for item in self.lst_sys.selectedItems(): + root.removeChild(item) + + def setup_signals(self): + self.set_greedyness(self.sld_greedyness.value()) + self.cmb_mode.currentTextChanged.connect(self.set_route_mode) + self.rd_comp.toggled.connect(self.set_comp_mode) + self.rd_precomp.toggled.connect(self.set_comp_mode) + self.sld_greedyness.valueChanged.connect(self.set_greedyness) + self.btn_go.clicked.connect(self.run) + self.btn_add.clicked.connect(self.add_system) + self.btn_rm.clicked.connect(self.remove_system) + self.btn_out_browse_pp.clicked.connect( + lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) + ) + self.btn_sys_lst_browse.clicked.connect( + lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst) + ) + + self.btn_bodies_browse_pp.clicked.connect( + lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file) + ) + self.btn_bodies_dest_browse_dl.clicked.connect( + lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file) + ) + self.btn_systems_browse_pp.clicked.connect( + lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file) + ) + self.btn_systems_dest_browse_dl.clicked.connect( + lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file) + ) + self.menu_act_quit.triggered.connect(self.app.quit) + + def handle_close(self): + cfg.write(self.config) + print("BYEEEEEE!") + + def setupUi(self, MainWindow, app): + super().setupUi(MainWindow) + self.update_dropdowns() + self.main_window = MainWindow + self.app = app + self.setup_signals() + self.lst_sys.setHeaderLabels(["Name", "Type"]) + + +def main(): + import sys + + app = App() + MainWindow = QMainWindow() + ui = ED_LRR() + ui.setupUi(MainWindow, app) + MainWindow.show() + ret = app.exec_() + ui.handle_close() + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/ed_lrr_gui/config.py b/ed_lrr_gui/config.py new file mode 100644 index 0000000..3e748b7 --- /dev/null +++ b/ed_lrr_gui/config.py @@ -0,0 +1,45 @@ +import pathlib +import appdirs +import yaml +from collections import namedtuple + +config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR")) +config_dir.mkdir(parents=True, exist_ok=True) +config_file = config_dir / "config.yml" +config_file.touch() + +data_dir = pathlib.Path(appdirs.user_data_dir("ED_LRR")) +data_dir.mkdir(parents=True, exist_ok=True) + + +def make_config(): + return { + "history_bodies_url": [], + "history_systems_url": [], + "history_bodies_path": [], + "history_systems_path": [], + "history_out_path": [], + "range": None, + "primary": False, + "mode": "bfs", + "greedyness": 0.5, + } + + +def write(cfg): + with config_file.open("w", encoding="utf-8") as of: + yaml.dump(cfg._asdict(), of, default_flow_style=False) + + +def load(): + data = yaml.load(config_file.open(encoding="utf-8"), Loader=yaml.Loader) + if data is None: + data = make_config() + write(data) + + return namedtuple("Config", data)(**data) + + +# print("CFG:", yaml.load_config()) +# print(config_file, data_dir) +# exit(1) diff --git a/ed_lrr_gui/gui/__init__.py b/ed_lrr_gui/gui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ed_lrr_gui/gui/ed_lrr.py b/ed_lrr_gui/gui/ed_lrr.py new file mode 100644 index 0000000..70c41d8 --- /dev/null +++ b/ed_lrr_gui/gui/ed_lrr.py @@ -0,0 +1,350 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'D:\devel\rust\py_test\ed_lrr_gui\gui\ed_lrr.ui' +# +# Created by: PyQt5 UI code generator 5.13.0 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_ED_LRR(object): + def setupUi(self, ED_LRR): + ED_LRR.setObjectName("ED_LRR") + ED_LRR.setEnabled(True) + ED_LRR.resize(577, 500) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(ED_LRR.sizePolicy().hasHeightForWidth()) + ED_LRR.setSizePolicy(sizePolicy) + ED_LRR.setMinimumSize(QtCore.QSize(577, 500)) + ED_LRR.setMaximumSize(QtCore.QSize(577, 500)) + ED_LRR.setDocumentMode(False) + ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded) + self.centralwidget = QtWidgets.QWidget(ED_LRR) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout.setObjectName("verticalLayout") + self.tabs = QtWidgets.QTabWidget(self.centralwidget) + self.tabs.setEnabled(True) + self.tabs.setTabShape(QtWidgets.QTabWidget.Rounded) + self.tabs.setTabsClosable(False) + self.tabs.setTabBarAutoHide(False) + self.tabs.setObjectName("tabs") + self.tab_download = QtWidgets.QWidget() + self.tab_download.setObjectName("tab_download") + self.formLayout = QtWidgets.QFormLayout(self.tab_download) + self.formLayout.setObjectName("formLayout") + self.lbl_bodies_dl = QtWidgets.QLabel(self.tab_download) + self.lbl_bodies_dl.setObjectName("lbl_bodies_dl") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_dl) + self.lbl_systems_dl = QtWidgets.QLabel(self.tab_download) + self.lbl_systems_dl.setObjectName("lbl_systems_dl") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl) + self.inp_bodies_dl = QtWidgets.QComboBox(self.tab_download) + self.inp_bodies_dl.setEditable(True) + self.inp_bodies_dl.setObjectName("inp_bodies_dl") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl) + self.inp_systems_dl = QtWidgets.QComboBox(self.tab_download) + self.inp_systems_dl.setEditable(True) + self.inp_systems_dl.setObjectName("inp_systems_dl") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl) + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setObjectName("gridLayout") + self.inp_bodies_dest_dl = QtWidgets.QComboBox(self.tab_download) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth()) + self.inp_bodies_dest_dl.setSizePolicy(sizePolicy) + self.inp_bodies_dest_dl.setEditable(True) + self.inp_bodies_dest_dl.setObjectName("inp_bodies_dest_dl") + self.gridLayout.addWidget(self.inp_bodies_dest_dl, 0, 0, 1, 1) + self.btn_bodies_dest_browse_dl = QtWidgets.QPushButton(self.tab_download) + self.btn_bodies_dest_browse_dl.setObjectName("btn_bodies_dest_browse_dl") + self.gridLayout.addWidget(self.btn_bodies_dest_browse_dl, 0, 1, 1, 1) + self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gridLayout) + self.gridLayout_2 = QtWidgets.QGridLayout() + self.gridLayout_2.setObjectName("gridLayout_2") + self.btn_systems_dest_browse_dl = QtWidgets.QPushButton(self.tab_download) + self.btn_systems_dest_browse_dl.setObjectName("btn_systems_dest_browse_dl") + self.gridLayout_2.addWidget(self.btn_systems_dest_browse_dl, 0, 1, 1, 1) + self.inp_systems_dest_dl = QtWidgets.QComboBox(self.tab_download) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth()) + self.inp_systems_dest_dl.setSizePolicy(sizePolicy) + self.inp_systems_dest_dl.setEditable(True) + self.inp_systems_dest_dl.setObjectName("inp_systems_dest_dl") + self.gridLayout_2.addWidget(self.inp_systems_dest_dl, 0, 0, 1, 1) + self.formLayout.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_2) + self.btn_download = QtWidgets.QPushButton(self.tab_download) + self.btn_download.setObjectName("btn_download") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.btn_download) + self.label = QtWidgets.QLabel(self.tab_download) + self.label.setObjectName("label") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label) + self.label_2 = QtWidgets.QLabel(self.tab_download) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.tabs.addTab(self.tab_download, "") + self.tab_preprocess = QtWidgets.QWidget() + self.tab_preprocess.setObjectName("tab_preprocess") + self.formLayout_3 = QtWidgets.QFormLayout(self.tab_preprocess) + self.formLayout_3.setObjectName("formLayout_3") + self.lbl_bodies_pp = QtWidgets.QLabel(self.tab_preprocess) + self.lbl_bodies_pp.setObjectName("lbl_bodies_pp") + self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_pp) + self.gr_bodies_pp = QtWidgets.QGridLayout() + self.gr_bodies_pp.setObjectName("gr_bodies_pp") + self.btn_bodies_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) + self.btn_bodies_browse_pp.setObjectName("btn_bodies_browse_pp") + self.gr_bodies_pp.addWidget(self.btn_bodies_browse_pp, 0, 1, 1, 1) + self.inp_bodies_pp = QtWidgets.QComboBox(self.tab_preprocess) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.inp_bodies_pp.sizePolicy().hasHeightForWidth()) + self.inp_bodies_pp.setSizePolicy(sizePolicy) + self.inp_bodies_pp.setEditable(True) + self.inp_bodies_pp.setObjectName("inp_bodies_pp") + self.gr_bodies_pp.addWidget(self.inp_bodies_pp, 0, 0, 1, 1) + self.formLayout_3.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp) + self.lbl_systems_pp = QtWidgets.QLabel(self.tab_preprocess) + self.lbl_systems_pp.setObjectName("lbl_systems_pp") + self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_pp) + self.gr_systems_pp = QtWidgets.QGridLayout() + self.gr_systems_pp.setObjectName("gr_systems_pp") + self.btn_systems_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) + self.btn_systems_browse_pp.setObjectName("btn_systems_browse_pp") + self.gr_systems_pp.addWidget(self.btn_systems_browse_pp, 0, 1, 1, 1) + self.inp_systems_pp = QtWidgets.QComboBox(self.tab_preprocess) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.inp_systems_pp.sizePolicy().hasHeightForWidth()) + self.inp_systems_pp.setSizePolicy(sizePolicy) + self.inp_systems_pp.setEditable(True) + self.inp_systems_pp.setObjectName("inp_systems_pp") + self.gr_systems_pp.addWidget(self.inp_systems_pp, 0, 0, 1, 1) + self.formLayout_3.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp) + self.lbl_out_pp = QtWidgets.QLabel(self.tab_preprocess) + self.lbl_out_pp.setObjectName("lbl_out_pp") + self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_out_pp) + self.gr_out_grid_pp = QtWidgets.QGridLayout() + self.gr_out_grid_pp.setObjectName("gr_out_grid_pp") + self.btn_out_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btn_out_browse_pp.sizePolicy().hasHeightForWidth()) + self.btn_out_browse_pp.setSizePolicy(sizePolicy) + self.btn_out_browse_pp.setObjectName("btn_out_browse_pp") + self.gr_out_grid_pp.addWidget(self.btn_out_browse_pp, 0, 1, 1, 1) + self.inp_out_pp = QtWidgets.QComboBox(self.tab_preprocess) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.inp_out_pp.sizePolicy().hasHeightForWidth()) + self.inp_out_pp.setSizePolicy(sizePolicy) + self.inp_out_pp.setEditable(True) + self.inp_out_pp.setObjectName("inp_out_pp") + self.gr_out_grid_pp.addWidget(self.inp_out_pp, 0, 0, 1, 1) + self.formLayout_3.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp) + self.btn_preprocess = QtWidgets.QPushButton(self.tab_preprocess) + self.btn_preprocess.setObjectName("btn_preprocess") + self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.btn_preprocess) + self.tabs.addTab(self.tab_preprocess, "") + self.tab_route = QtWidgets.QWidget() + self.tab_route.setObjectName("tab_route") + self.formLayout_2 = QtWidgets.QFormLayout(self.tab_route) + self.formLayout_2.setObjectName("formLayout_2") + self.lbl_sys_lst = QtWidgets.QLabel(self.tab_route) + self.lbl_sys_lst.setObjectName("lbl_sys_lst") + self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_sys_lst) + self.gr_sys = QtWidgets.QGridLayout() + self.gr_sys.setObjectName("gr_sys") + self.btn_sys_lst_browse = QtWidgets.QPushButton(self.tab_route) + self.btn_sys_lst_browse.setObjectName("btn_sys_lst_browse") + self.gr_sys.addWidget(self.btn_sys_lst_browse, 0, 1, 1, 1) + self.inp_sys_lst = QtWidgets.QComboBox(self.tab_route) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.inp_sys_lst.sizePolicy().hasHeightForWidth()) + self.inp_sys_lst.setSizePolicy(sizePolicy) + self.inp_sys_lst.setEditable(True) + self.inp_sys_lst.setObjectName("inp_sys_lst") + self.gr_sys.addWidget(self.inp_sys_lst, 0, 0, 1, 1) + self.formLayout_2.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_sys) + self.btn_add = QtWidgets.QPushButton(self.tab_route) + self.btn_add.setObjectName("btn_add") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.btn_add) + self.inp_sys = QtWidgets.QLineEdit(self.tab_route) + self.inp_sys.setObjectName("inp_sys") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_sys) + self.btn_rm = QtWidgets.QPushButton(self.tab_route) + self.btn_rm.setObjectName("btn_rm") + self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.btn_rm) + self.gr_mode = QtWidgets.QGridLayout() + self.gr_mode.setObjectName("gr_mode") + self.rd_comp = QtWidgets.QRadioButton(self.tab_route) + self.rd_comp.setChecked(True) + self.rd_comp.setObjectName("rd_comp") + self.gr_mode.addWidget(self.rd_comp, 0, 1, 1, 1) + self.rd_precomp = QtWidgets.QRadioButton(self.tab_route) + self.rd_precomp.setObjectName("rd_precomp") + self.gr_mode.addWidget(self.rd_precomp, 0, 2, 1, 1) + self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode) + self.btn_permute = QtWidgets.QPushButton(self.tab_route) + self.btn_permute.setObjectName("btn_permute") + self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute) + self.chk_permute_keep = QtWidgets.QCheckBox(self.tab_route) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chk_permute_keep.sizePolicy().hasHeightForWidth()) + self.chk_permute_keep.setSizePolicy(sizePolicy) + self.chk_permute_keep.setTristate(True) + self.chk_permute_keep.setObjectName("chk_permute_keep") + self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.chk_permute_keep) + self.lst_sys = QtWidgets.QTreeWidget(self.tab_route) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lst_sys.sizePolicy().hasHeightForWidth()) + self.lst_sys.setSizePolicy(sizePolicy) + self.lst_sys.setMinimumSize(QtCore.QSize(0, 0)) + self.lst_sys.setDragEnabled(True) + self.lst_sys.setDragDropOverwriteMode(False) + self.lst_sys.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) + self.lst_sys.setDefaultDropAction(QtCore.Qt.MoveAction) + self.lst_sys.setAlternatingRowColors(True) + self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.lst_sys.setObjectName("lst_sys") + self.lst_sys.headerItem().setText(0, "1") + self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.SpanningRole, self.lst_sys) + self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route) + self.sb_range.setObjectName("sb_range") + self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.sb_range) + self.lbl_range = QtWidgets.QLabel(self.tab_route) + self.lbl_range.setObjectName("lbl_range") + self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.lbl_range) + self.gr_opts = QtWidgets.QGridLayout() + self.gr_opts.setObjectName("gr_opts") + self.cmb_mode = QtWidgets.QComboBox(self.tab_route) + self.cmb_mode.setObjectName("cmb_mode") + self.cmb_mode.addItem("") + self.cmb_mode.addItem("") + self.cmb_mode.addItem("") + self.gr_opts.addWidget(self.cmb_mode, 0, 2, 1, 1) + self.lbl_greedyness = QtWidgets.QLabel(self.tab_route) + self.lbl_greedyness.setEnabled(True) + self.lbl_greedyness.setObjectName("lbl_greedyness") + self.gr_opts.addWidget(self.lbl_greedyness, 1, 1, 1, 1) + self.chk_primary = QtWidgets.QCheckBox(self.tab_route) + self.chk_primary.setObjectName("chk_primary") + self.gr_opts.addWidget(self.chk_primary, 0, 3, 1, 1) + self.sld_greedyness = QtWidgets.QSlider(self.tab_route) + self.sld_greedyness.setMaximum(100) + self.sld_greedyness.setPageStep(10) + self.sld_greedyness.setProperty("value", 50) + self.sld_greedyness.setOrientation(QtCore.Qt.Horizontal) + self.sld_greedyness.setTickPosition(QtWidgets.QSlider.TicksBelow) + self.sld_greedyness.setTickInterval(10) + self.sld_greedyness.setObjectName("sld_greedyness") + self.gr_opts.addWidget(self.sld_greedyness, 1, 2, 1, 2) + self.lbl_mode = QtWidgets.QLabel(self.tab_route) + self.lbl_mode.setObjectName("lbl_mode") + self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1) + self.formLayout_2.setLayout(7, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) + self.btn_go = QtWidgets.QPushButton(self.tab_route) + self.btn_go.setFlat(False) + self.btn_go.setObjectName("btn_go") + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btn_go) + self.tabs.addTab(self.tab_route, "") + self.tab_log = QtWidgets.QWidget() + self.tab_log.setObjectName("tab_log") + self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_log) + self.gridLayout_3.setObjectName("gridLayout_3") + self.txt_log = QtWidgets.QTextEdit(self.tab_log) + self.txt_log.setEnabled(True) + self.txt_log.setFrameShadow(QtWidgets.QFrame.Sunken) + self.txt_log.setLineWidth(1) + self.txt_log.setReadOnly(True) + self.txt_log.setAcceptRichText(False) + self.txt_log.setObjectName("txt_log") + self.gridLayout_3.addWidget(self.txt_log, 0, 0, 1, 1) + self.tabs.addTab(self.tab_log, "") + self.verticalLayout.addWidget(self.tabs) + ED_LRR.setCentralWidget(self.centralwidget) + self.menu = QtWidgets.QMenuBar(ED_LRR) + self.menu.setGeometry(QtCore.QRect(0, 0, 577, 21)) + self.menu.setObjectName("menu") + self.menu_file = QtWidgets.QMenu(self.menu) + self.menu_file.setObjectName("menu_file") + ED_LRR.setMenuBar(self.menu) + self.bar_status = QtWidgets.QStatusBar(ED_LRR) + self.bar_status.setObjectName("bar_status") + ED_LRR.setStatusBar(self.bar_status) + self.menu_act_quit = QtWidgets.QAction(ED_LRR) + self.menu_act_quit.setObjectName("menu_act_quit") + self.menu_file.addAction(self.menu_act_quit) + self.menu.addAction(self.menu_file.menuAction()) + + self.retranslateUi(ED_LRR) + self.tabs.setCurrentIndex(2) + QtCore.QMetaObject.connectSlotsByName(ED_LRR) + ED_LRR.setTabOrder(self.rd_comp, self.cmb_mode) + ED_LRR.setTabOrder(self.cmb_mode, self.chk_primary) + ED_LRR.setTabOrder(self.chk_primary, self.sld_greedyness) + ED_LRR.setTabOrder(self.sld_greedyness, self.rd_precomp) + + def retranslateUi(self, ED_LRR): + _translate = QtCore.QCoreApplication.translate + ED_LRR.setWindowTitle(_translate("ED_LRR", "Elite: Dangerous Long Range Route Plotter")) + self.lbl_bodies_dl.setText(_translate("ED_LRR", "bodies.json")) + self.lbl_systems_dl.setText(_translate("ED_LRR", "systemsWithCoordinates.json")) + self.inp_bodies_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/bodies.json")) + self.inp_systems_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/systemsWithCoordinates.json")) + self.btn_bodies_dest_browse_dl.setText(_translate("ED_LRR", "...")) + self.btn_systems_dest_browse_dl.setText(_translate("ED_LRR", "...")) + self.btn_download.setText(_translate("ED_LRR", "Download")) + self.label.setText(_translate("ED_LRR", "Download path")) + self.label_2.setText(_translate("ED_LRR", "Download path")) + self.tabs.setTabText(self.tabs.indexOf(self.tab_download), _translate("ED_LRR", "Download")) + self.lbl_bodies_pp.setText(_translate("ED_LRR", "bodies.json")) + self.btn_bodies_browse_pp.setText(_translate("ED_LRR", "...")) + self.lbl_systems_pp.setText(_translate("ED_LRR", "systemsWithCoordinates.json")) + self.btn_systems_browse_pp.setText(_translate("ED_LRR", "...")) + self.lbl_out_pp.setText(_translate("ED_LRR", "Output")) + self.btn_out_browse_pp.setText(_translate("ED_LRR", "...")) + self.btn_preprocess.setText(_translate("ED_LRR", "Preprocess")) + self.tabs.setTabText(self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess")) + self.lbl_sys_lst.setText(_translate("ED_LRR", "System List")) + self.btn_sys_lst_browse.setText(_translate("ED_LRR", "...")) + self.btn_add.setText(_translate("ED_LRR", "Search+Add")) + self.btn_rm.setText(_translate("ED_LRR", "Remove")) + self.rd_comp.setText(_translate("ED_LRR", "Compute Route")) + self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph")) + self.btn_permute.setText(_translate("ED_LRR", "Permute")) + self.chk_permute_keep.setText(_translate("ED_LRR", "Keep endpoints (No, first only, yes)")) + self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)")) + self.cmb_mode.setCurrentText(_translate("ED_LRR", "Breadth-First Search")) + self.cmb_mode.setItemText(0, _translate("ED_LRR", "Breadth-First Search")) + self.cmb_mode.setItemText(1, _translate("ED_LRR", "Greedy-Search")) + self.cmb_mode.setItemText(2, _translate("ED_LRR", "A*-Search")) + self.lbl_greedyness.setText(_translate("ED_LRR", "Greedyness Factor")) + self.chk_primary.setText(_translate("ED_LRR", "Primary Stars Only")) + self.lbl_mode.setText(_translate("ED_LRR", "Mode")) + self.btn_go.setText(_translate("ED_LRR", "GO!")) + self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) + self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")) + self.menu_file.setTitle(_translate("ED_LRR", "File")) + self.menu_act_quit.setText(_translate("ED_LRR", "Quit")) + self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q")) diff --git a/ed_lrr_gui/gui/ed_lrr.ui b/ed_lrr_gui/gui/ed_lrr.ui new file mode 100644 index 0000000..24cb6be --- /dev/null +++ b/ed_lrr_gui/gui/ed_lrr.ui @@ -0,0 +1,584 @@ + + + ED_LRR + + + true + + + + 0 + 0 + 577 + 500 + + + + + 0 + 0 + + + + + 577 + 500 + + + + + 577 + 500 + + + + Elite: Dangerous Long Range Route Plotter + + + false + + + QTabWidget::Rounded + + + + + + + true + + + QTabWidget::Rounded + + + 2 + + + false + + + false + + + + Download + + + + + + bodies.json + + + + + + + systemsWithCoordinates.json + + + + + + + true + + + https://www.edsm.net/dump/bodies.json + + + + + + + true + + + https://www.edsm.net/dump/systemsWithCoordinates.json + + + + + + + + + + 0 + 0 + + + + true + + + + + + + ... + + + + + + + + + + + ... + + + + + + + + 0 + 0 + + + + true + + + + + + + + + Download + + + + + + + Download path + + + + + + + Download path + + + + + + + + Preprocess + + + + + + bodies.json + + + + + + + + + ... + + + + + + + + 0 + 0 + + + + true + + + + + + + + + systemsWithCoordinates.json + + + + + + + + + ... + + + + + + + + 0 + 0 + + + + true + + + + + + + + + Output + + + + + + + + + + 0 + 0 + + + + ... + + + + + + + + 0 + 0 + + + + true + + + + + + + + + Preprocess + + + + + + + + Route + + + + + + System List + + + + + + + + + ... + + + + + + + + 0 + 0 + + + + true + + + + + + + + + Search+Add + + + + + + + + + + Remove + + + + + + + + + Compute Route + + + true + + + + + + + Precompute Graph + + + + + + + + + Permute + + + + + + + + 0 + 0 + + + + Keep endpoints (No, first only, yes) + + + true + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + false + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + + 1 + + + + + + + + + + + Jump Range (Ly) + + + + + + + + + Breadth-First Search + + + + Breadth-First Search + + + + + Greedy-Search + + + + + A*-Search + + + + + + + + true + + + Greedyness Factor + + + + + + + Primary Stars Only + + + + + + + 100 + + + 10 + + + 50 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 10 + + + + + + + Mode + + + + + + + + + GO! + + + false + + + + + + + + Log + + + + + + true + + + QFrame::Sunken + + + 1 + + + true + + + false + + + + + + + + + + + + + 0 + 0 + 577 + 21 + + + + + File + + + + + + + + + Quit + + + Ctrl+Q + + + + + rd_comp + cmb_mode + chk_primary + sld_greedyness + rd_precomp + + + + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2b6e07f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools", "wheel", "setuptools-rust"] \ No newline at end of file diff --git a/rust/.cargo/config b/rust/.cargo/config new file mode 100644 index 0000000..f0b7483 --- /dev/null +++ b/rust/.cargo/config @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "target-cpu=native"] \ No newline at end of file diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..84eb592 --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,2091 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "aho-corasick" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arrayvec" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bincode" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bstr" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "c2-chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clicolors-control" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "console" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cookie" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cookie_store" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ctor" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "digest" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dtoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ed_lrr" +version = "0.1.0" +dependencies = [ + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "encode_unicode" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "encoding_rs" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "error-chain" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "flate2" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-cpupool" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ghost" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "h2" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http-body" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "humantime" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper" +version = "0.12.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-tls" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "indexmap" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "indicatif" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "inventory" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "inventory-impl" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "iovec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lock_api" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mashup" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mashup-impl" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memoffset" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "mime" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mime_guess" +version = "2.0.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide_c_api" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "native-tls" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.23 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "number_prefix" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "opaque-debug" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl" +version = "0.10.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl-sys" +version = "0.9.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "owning_ref" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pdqselect" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "permutohedron" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "phf" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_codegen" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_generator" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_shared" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ppv-lite86" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-hack" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-hack-impl" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "publicsuffix" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3-derive-backend" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3cls" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-automata" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "reqwest" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rstar" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "schannel" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "security-framework" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_urlencoded" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "siphasher" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "smallvec" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "spin" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "string" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "structopt" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termios" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-buf" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "try-lock" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "try_from" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ucd-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicase" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-segmentation" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vcpkg" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "want" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "18b50f5258d1a9ad8396d2d345827875de4261b158124d4c819d9b351454fae5" +"checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" +"checksum bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc0572e02f76cb335f309b19e0a0d585b4f62788f7d26de2a13a836a637385f" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" +"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" +"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" +"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" +"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" +"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" +"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed" +"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8" +"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" +"checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" +"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" +"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" +"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)" = "6481fff8269772d4463253ca83c788104a7305cb3fb9136bc651a6211e46e03f" +"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" +"checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922" +"checksum inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a877ae8bce77402d5e9ed870730939e097aad827b2a932b361958fa9d6e75aa" +"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b" +"checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" +"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" +"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" +"checksum miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b6c3756d66cf286314d5f7ebe74886188a9a92f5eee68b06f31ac2b4f314c99d" +"checksum miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5b78ca5446dd9fe0dab00e058731b6b08a8c1d2b9cdb8efb10876e24e9ae2494" +"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" +"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum openssl 0.10.23 (registry+https://github.com/rust-lang/crates.io-index)" = "97c140cbb82f3b3468193dd14c1b88def39f341f68257f8a7fe8ed9ed3f628a5" +"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +"checksum openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)" = "75bdd6dbbb4958d38e47a1d2348847ad1eb4dc205dc5d37473ae504391865acc" +"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" +"checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" +"checksum phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" +"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" +"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" +"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" +"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" +"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d" +"checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086" +"checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186" +"checksum pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c494f8161f5b73096cc50f00fbb90fe670f476cde5e59c1decff39b546d54f40" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" +"checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86" +"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "00eb63f212df0e358b427f0f40aa13aaea010b470be642ad422bcbca2feff2e4" +"checksum rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd08ae4f9661517777346592956ea6cdbba2895a28037af7daa600382f4b4001" +"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" +"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b" +"checksum serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "ef45eb79d6463b22f5f9e16d283798b7c0175ba6050bc25c1a946c122727fe7b" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" +"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +"checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" +"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" +"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" +"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" +"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac" +"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" +"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" +"checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19" +"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" +"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" +"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" +"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..132a70d --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "ed_lrr" +version = "0.1.0" +authors = ["Daniel Seiller "] +edition = "2018" +repository = "https://gitlab.com/Earthnuker/ed_lrr.git" +license = "WTFPL" + + +[lib] +crate-type = ["cdylib"] + +[profile.release] +# debug=true + +[dependencies] +csv = "1.1.1" +serde = "1.0.94" +serde_derive = "1.0.94" +rstar = {version="0.4.0"} +humantime = "1.2.0" +structopt = "0.2.18" +permutohedron = "0.2.4" +serde_json = "1.0.40" +indicatif = "0.11.0" +fnv = "1.0.6" +bincode = "1.1.4" +sha3 = "0.8.2" +byteorder = "1.3.2" +reqwest = "0.9.18" + +[dependencies.pyo3] +version = "0.7.0" +features = ["extension-module"] diff --git a/rust/src/common.rs b/rust/src/common.rs new file mode 100644 index 0000000..922aafd --- /dev/null +++ b/rust/src/common.rs @@ -0,0 +1,38 @@ +use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SystemSerde { + pub id: u32, + pub star_type: String, + pub system: String, + pub body: String, + pub mult: f32, + pub distance: u32, + pub x: f32, + pub y: f32, + pub z: f32, +} + +impl SystemSerde { + pub fn build(&self) -> System { + System { + id: self.id, + star_type: self.star_type.clone(), + system: self.system.clone(), + body: self.body.clone(), + mult: self.mult, + distance: self.distance, + pos: [self.x, self.y, self.z], + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct System { + pub id: u32, + pub star_type: String, + pub system: String, + pub body: String, + pub mult: f32, + pub distance: u32, + pub pos: [f32; 3], +} diff --git a/rust/src/download.rs b/rust/src/download.rs new file mode 100644 index 0000000..57ceaa8 --- /dev/null +++ b/rust/src/download.rs @@ -0,0 +1,63 @@ +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use std::fs::File; +use std::io; +use std::path::PathBuf; +use structopt::StructOpt; + +#[derive(Debug, StructOpt, Clone)] +pub struct DownloadOpts { + #[structopt( + long = "bodies", + default_value = "https://www.edsm.net/dump/bodies.json" + )] + /// Url to bodies.json + bodies_url: String, + #[structopt( + long = "systems", + default_value = "https://www.edsm.net/dump/systemsWithCoordinates.json" + )] + /// Url to systemsWithCoordinates.json + systems_url: String, +} + +fn fetch_url(url: &str, prog_bar: &ProgressBar) -> std::io::Result<()> { + let outfile = url.split('/').last().unwrap(); + let template = format!("{} {}", "[{elapsed_precise}] {binary_bytes}", outfile); + prog_bar.set_style(ProgressStyle::default_bar().template(&template)); + + let client = reqwest::Client::builder().gzip(true).build().unwrap(); + let resp = client.get(url).send().unwrap(); + let target_path = PathBuf::from(format!("dumps/{}", outfile)); + if target_path.exists() { + eprintln!("Error: Target {} exists!", outfile); + return Ok(()); + } + let mut target = File::create(target_path)?; + io::copy(&mut prog_bar.wrap_read(resp), &mut target).unwrap(); + prog_bar.finish(); + Ok(()) +} + +pub fn download(opts: DownloadOpts) -> std::io::Result<()> { + let mut threads = Vec::new(); + let m = MultiProgress::new(); + { + let opts = opts.clone(); + let pb = m.add(ProgressBar::new(0)); + threads.push(std::thread::spawn(move || { + fetch_url(&opts.bodies_url, &pb).unwrap(); + })); + }; + { + let opts = opts.clone(); + let pb = m.add(ProgressBar::new(0)); + threads.push(std::thread::spawn(move || { + fetch_url(&opts.systems_url, &pb).unwrap(); + })); + } + m.join_and_clear().unwrap(); + for th in threads { + th.join().unwrap(); + } + Ok(()) +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 0000000..3d65b7d --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,66 @@ +mod common; +mod download; +mod preprocess; +mod route; +use std::collections::HashMap; +use pyo3::prelude::*; +use pyo3::types::PyDict; +use std::path::PathBuf; + +#[pymodule] +pub fn _ed_lrr(py: Python, m: &PyModule) -> PyResult<()> { + /// Test + #[pyfn(m,"test")] + fn test(py:Python,o:PyObject) -> PyResult<()> { + println!("OBJ: {:?}",o); + return Ok(()); + } + + /// download(systems_url,systems_file, bodies_url, bodies_file, callback) + /// -- + /// + /// Download bodies.json and systemsWithCoordinates.json + #[pyfn(m, "download")] + fn download(py: Python, systems_url: String, systems_file: String, bodies_url:String,bodies_file:String,callback: PyObject) -> PyResult { + let state = PyDict::new(py); + state.set_item("systems_url", systems_url)?; + state.set_item("systems_file", systems_file)?; + state.set_item("bodies_url", bodies_url)?; + state.set_item("bodies_file", bodies_file)?; + state.set_item("callback", callback)?; + return Ok(state.to_object(py)); + } + + /// preprocess(infile_systems, infile_bodies, outfile, callback) + /// -- + /// + /// Preprocess bodies.json and systemsWithCoordinates.json into stars.csv + #[pyfn(m, "preprocess")] + fn preprocess(py: Python, infile_systems: String, infile_bodies: String, outfile:String,callback: PyObject) -> PyResult { + let state = PyDict::new(py); + state.set_item("infile_systems", infile_systems)?; + state.set_item("infile_bodies", infile_bodies)?; + state.set_item("outfile", outfile)?; + state.set_item("callback", callback)?; + return Ok(state.to_object(py)); + } + + /// route(infile, source, dest, range, mode, greedyness, precomp, callback) + /// -- + /// + /// Compute a Route using the suplied parameters + #[pyfn(m, "route")] + fn route(py: Python, infile: String, source: String, dest:String, range: f32, mode: String,greedyness: Option, precomp: Option,callback: PyObject) -> PyResult { + let state = PyDict::new(py); + state.set_item("infile", infile)?; + state.set_item("source", source)?; + state.set_item("dest", dest)?; + state.set_item("range", range)?; + state.set_item("mode", mode)?; + state.set_item("greedyness", greedyness)?; + state.set_item("precomp", precomp)?; + state.set_item("callback", callback)?; + return Ok(state.to_object(py)); + } + Ok(()) +} \ No newline at end of file diff --git a/rust/src/preprocess.rs b/rust/src/preprocess.rs new file mode 100644 index 0000000..c564ea8 --- /dev/null +++ b/rust/src/preprocess.rs @@ -0,0 +1,220 @@ +use crate::common::SystemSerde; +use fnv::FnvHashMap; +use humantime::format_duration; +use indicatif::{ProgressBar, ProgressStyle}; +use serde::Deserialize; +use serde_json::Result; +use std::fs::File; +use std::io::Seek; +use std::io::{BufRead, BufReader, BufWriter, SeekFrom}; +use std::path::PathBuf; +use std::str; +use std::time::Instant; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +pub struct PreprocessOpts { + #[structopt(short, long = "bodies", default_value = "dumps/bodies.json")] + /// Path to bodies.json + pub bodies: PathBuf, + #[structopt( + short, + long = "systems", + default_value = "dumps/systemsWithCoordinates.json" + )] + /// Path to systemsWithCoordinates.json + pub systems: PathBuf, + #[structopt(default_value = "stars")] + /// outfile prefix + pub prefix: String, +} + +#[derive(Debug, Deserialize)] +#[allow(non_snake_case)] +struct Body { + name: String, + subType: String, + #[serde(rename = "type")] + body_type: String, + systemId: i32, + systemId64: i64, + #[serde(rename = "distanceToArrival")] + distance: u32, +} + +#[derive(Debug, Deserialize)] +struct Coords { + x: f32, + y: f32, + z: f32, +} + +#[derive(Debug, Deserialize)] +struct System { + id: i32, + id64: i64, + name: String, + coords: Coords, + date: String, +} + +#[derive(Debug, StructOpt)] +#[structopt( + name = "ed_lrr_pp", + about = "Preprocessor for Elite: Dangerous Long-Range Router", + rename_all = "snake_case" +)] +/// Preprocess data for ed_lrr +struct Opt { + #[structopt(short, long = "bodies")] + /// Path to bodies.json + bodies: PathBuf, + #[structopt(short, long = "systems")] + /// Path to systemsWithCoordinates.json + systems: PathBuf, + #[structopt(default_value = "stars")] + /// outfile prefix + prefix: String, +} + +fn get_mult(star_type: &str) -> f32 { + if star_type.contains("White Dwarf") { + return 1.5; + } + if star_type.contains("Neutron") { + return 4.0; + } + 1.0 +} + +fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std::io::Result<()> { + let mut cnt = 0; + let mut buffer = String::new(); + let t_start = Instant::now(); + let fh = File::open(path)?; + let prog_bar = ProgressBar::new(fh.metadata()?.len()); + prog_bar.set_style( + ProgressStyle::default_bar() + .template( + "[{elapsed_precise}/{eta_precise}]{spinner} [{wide_bar}] {binary_bytes}/{binary_total_bytes} ({percent}%)", + ) + .progress_chars("#9876543210 ") + .tick_chars("/-\\|"), + ); + prog_bar.set_draw_delta(1024 * 1024); + let mut reader = BufReader::new(fh); + println!("Loading {} ...", path.to_str().unwrap()); + while let Ok(n) = reader.read_line(&mut buffer) { + if n == 0 { + break; + } + buffer = buffer.trim_end().trim_end_matches(|c| c == ',').to_string(); + if !buffer.is_empty() { + func(&buffer); + } + prog_bar.set_position(reader.seek(SeekFrom::Current(0)).unwrap()); + cnt += 1; + buffer.clear(); + } + prog_bar.finish_and_clear(); + println!( + "Processed {} lines in {} ...", + cnt, + format_duration(t_start.elapsed()) + ); + Ok(()) +} + +fn process_systems(path: &PathBuf) -> FnvHashMap { + let mut ret = FnvHashMap::default(); + process(path, &mut |line| { + let sys_res: Result = serde_json::from_str(&line); + if let Ok(sys) = sys_res { + ret.insert(sys.id, sys); + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); + } + }) + .unwrap(); + ret +} + +fn build_index(path: &PathBuf) -> std::io::Result<()> { + let mut wtr = BufWriter::new(File::create(path.with_extension("idx"))?); + let mut idx: Vec = Vec::new(); + let mut records = (csv::Reader::from_path(path)?).into_deserialize::(); + loop { + idx.push(records.reader().position().byte()); + if records.next().is_none() { + break; + } + } + bincode::serialize_into(&mut wtr, &idx).unwrap(); + Ok(()) +} + +fn process_bodies( + path: &PathBuf, + out_prefix: &str, + systems: &mut FnvHashMap, +) -> std::io::Result<()> { + let out_path = PathBuf::from(format!("{}.csv", out_prefix)); + println!( + "Processing {} into {} ...", + path.to_str().unwrap(), + out_path.to_str().unwrap(), + ); + let mut n: u32 = 0; + let mut wtr = csv::Writer::from_path(out_path)?; + process(path, &mut |line| { + if !line.contains("Star") { + return; + } + let body_res: Result = serde_json::from_str(&line); + if let Ok(body) = body_res { + if !body.body_type.contains("Star") { + return; + } + if let Some(sys) = systems.get(&body.systemId) { + let sub_type = body.subType; + let mult = get_mult(&sub_type); + let sys_name = sys.name.clone(); + let rec = SystemSerde { + id: n, + star_type: sub_type, + system: sys_name, + body: body.name, + mult, + distance: body.distance, + x: sys.coords.x, + y: sys.coords.y, + z: sys.coords.z, + }; + wtr.serialize(rec).unwrap(); + n += 1; + }; + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); + } + }) + .unwrap(); + println!("Total Systems: {}", n); + systems.clear(); + Ok(()) +} + +pub fn preprocess_files(opts: PreprocessOpts) -> std::io::Result<()> { + let out_path = PathBuf::from(format!("{}.csv", &opts.prefix)); + if !out_path.exists() { + let mut systems = process_systems(&opts.systems); + process_bodies(&opts.bodies, &opts.prefix, &mut systems)?; + } else { + println!( + "File '{}' exists, not overwriting it", + out_path.to_str().unwrap() + ); + } + println!("Building index..."); + println!("Index result: {:?}", build_index(&out_path)); + Ok(()) +} diff --git a/rust/src/route.rs b/rust/src/route.rs new file mode 100644 index 0000000..dd11596 --- /dev/null +++ b/rust/src/route.rs @@ -0,0 +1,879 @@ +use core::cmp::Ordering; +use csv::StringRecord; +use fnv::{FnvHashMap, FnvHashSet}; +use humantime::format_duration; +use permutohedron::LexicalPermutation; +use rstar::{PointDistance, RTree, RTreeObject, AABB}; +use sha3::{Digest, Sha3_256}; +use std::collections::VecDeque; +use std::fs::File; +use std::hash::{Hash, Hasher}; +use std::io::Seek; +use std::io::{BufRead, BufReader, BufWriter, Write}; +use std::path::PathBuf; +use std::str::FromStr; +use std::time::Instant; +use structopt::StructOpt; + +use crate::common::{System, SystemSerde}; + +#[derive(Debug)] +pub struct SearchState { + pub mode: String, + pub depth: usize, + pub queue_size: usize, + pub d_rem: f64, + pub prc_done: f64, + pub n_seen: usize, + pub prc_seen: f64 +} + + +#[derive(Debug)] +pub struct RouteOpts { + pub range: Option, + pub file_path: PathBuf, + pub precomp_file: Option, + pub precompute: bool, + pub permute: bool, + pub primary: bool, + pub full_permute: bool, + pub factor: Option, + pub mode: Mode, + pub systems: Vec, +} + +#[derive(Debug)] +pub enum Mode { + BFS, + Greedy, + AStar, +} + +impl FromStr for Mode { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "bfs" => Ok(Mode::BFS), + "greedy" => Ok(Mode::Greedy), + "astar" => Ok(Mode::AStar), + _ => Err("Invalid Mode".to_string()), + } + } +} + +fn dist2(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + let dx = p1[0] - p2[0]; + let dy = p1[1] - p2[1]; + let dz = p1[2] - p2[2]; + + dx * dx + dy * dy + dz * dz +} + +fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + dist2(p1, p2).sqrt() +} + +fn fcmp(a: f32, b: f32) -> Ordering { + match (a, b) { + (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, + (x, _) if x.is_nan() => Ordering::Greater, + (_, y) if y.is_nan() => Ordering::Less, + (..) => a.partial_cmp(&b).unwrap(), + } +} + +impl System { + pub fn dist2(&self, p: &[f32; 3]) -> f32 { + dist2(&self.pos, p) + } + pub fn distp(&self, p: &System) -> f32 { + dist(&self.pos, &p.pos) + } + pub fn distp2(&self, p: &System) -> f32 { + self.dist2(&p.pos) + } +} +impl PartialEq for System { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for System {} + +impl Hash for System { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl RTreeObject for System { + type Envelope = AABB<[f32; 3]>; + + fn envelope(&self) -> Self::Envelope { + AABB::from_point(self.pos) + } +} + +impl PointDistance for System { + fn distance_2(&self, point: &[f32; 3]) -> f32 { + self.dist2(&point) + } +} + +fn hash_file(path: &PathBuf) -> Vec { + let mut hash_reader = BufReader::new(File::open(path).unwrap()); + let mut hasher = Sha3_256::new(); + std::io::copy(&mut hash_reader, &mut hasher).unwrap(); + hasher.result().iter().copied().collect() +} + +struct LineCache { + cache: Vec, + file: BufReader, + header: Option, +} + +impl LineCache { + pub fn new(path: &PathBuf) -> Option { + let idx_path = path.with_extension("idx"); + let t_load = Instant::now(); + println!("Loading Index from {}", idx_path.to_str().unwrap()); + let cache = + bincode::deserialize_from(&mut BufReader::new(File::open(idx_path).ok()?)).ok()?; + let mut reader = BufReader::new(File::open(path).ok()?); + let header = Self::read_record(&mut reader); + let ret = Self { + file: reader, + cache, + header, + }; + println!("Done in {}!", format_duration(t_load.elapsed())); + Some(ret) + } + fn read_record(reader: &mut BufReader) -> Option { + let mut line = String::new(); + reader.read_line(&mut line).ok()?; + let v: Vec<_> = line.trim_end().split(',').collect(); + let rec = StringRecord::from(v); + Some(rec) + } + pub fn get(&mut self, id: u32) -> Option { + let pos = self.cache[id as usize]; + self.file.seek(std::io::SeekFrom::Start(pos)).unwrap(); + let rec = Self::read_record(&mut self.file).unwrap(); + let sys: SystemSerde = rec.deserialize(self.header.as_ref()).unwrap(); + Some(sys.build()) + } +} + +pub struct Router { + tree: RTree, + scoopable: FnvHashSet, + pub route_tree: Option>, + cache: Option, + range: f32, + primary_only: bool, + path: PathBuf, + callback: Box ()>, +} + +impl Router { + pub fn new(path: &PathBuf, range: f32, primary_only: bool,callback: Box ()>) -> Self { + let mut scoopable = FnvHashSet::default(); + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + println!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + let t_load = Instant::now(); + println!("Loading {}...", path.to_str().unwrap()); + let systems: Vec = reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| { + if primary_only { + sys.distance == 0 + } else { + true + } + }) + .map(|sys| { + if sys.mult > 1.0f32 { + scoopable.insert(sys.id); + } else { + for c in "KGBFOAM".chars() { + if sys.star_type.starts_with(c) { + scoopable.insert(sys.id); + break; + } + } + } + sys.build() + }) + .collect(); + println!("Building RTree..."); + let ret = Self { + tree: RTree::bulk_load(systems), + scoopable, + route_tree: None, + range, + primary_only, + cache: LineCache::new(path), + path: path.clone(), + callback: callback, + }; + println!( + "{} Systems loaded in {}", + ret.tree.size(), + format_duration(t_load.elapsed()) + ); + ret + } + + pub fn from_file(filename: &PathBuf) -> (PathBuf, Self) { + let t_load = Instant::now(); + let mut reader = BufReader::new(File::open(&filename).unwrap()); + println!("Loading {}", filename.to_str().unwrap()); + let (primary, range, file_hash, path, route_tree): ( + bool, + f32, + Vec, + String, + FnvHashMap, + ) = bincode::deserialize_from(&mut reader).unwrap(); + let path = PathBuf::from(path); + println!("Done in {}!", format_duration(t_load.elapsed())); + if hash_file(&path) != file_hash { + panic!("File hash mismatch!") + } + let cache = LineCache::new(&path); + ( + path.clone(), + Self { + tree: RTree::default(), + scoopable: FnvHashSet::default(), + route_tree: Some(route_tree), + range, + cache, + primary_only: primary, + path, + callback: Box::new(|s| {}), + }, + ) + } + + fn closest(&self, point: &[f32; 3]) -> &System { + self.tree.nearest_neighbor(point).unwrap() + } + fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { + self.tree.locate_within_distance(*center, radius * radius) + } + + fn neighbours(&self, sys: &System, r: f32) -> impl Iterator { + self.points_in_sphere(&sys.pos, sys.mult * r) + } + + fn valid(&self, sys: &System) -> bool { + self.scoopable.contains(&sys.id) + } + + pub fn best_name_multiroute( + &self, + waypoints: &[String], + range: f32, + full: bool, + mode: Mode, + factor: f32, + ) -> Vec { + let mut best_score: f32 = std::f32::MAX; + let mut waypoints = waypoints.to_owned(); + let mut best_permutation_waypoints = waypoints.to_owned(); + let first = waypoints.first().cloned(); + let last = waypoints.last().cloned(); + let t_start = Instant::now(); + println!("Finding best permutation of hops..."); + while waypoints.prev_permutation() {} + loop { + let c_first = waypoints.first().cloned(); + let c_last = waypoints.last().cloned(); + if full || ((c_first == first) && (c_last == last)) { + let mut total_d = 0.0; + for pair in waypoints.windows(2) { + match pair { + [src, dst] => { + let (mut src, dst) = + (self.name_to_systems(&src), self.name_to_systems(&dst)); + src.sort_by_key(|&p| (p.mult * 10.0) as u8); + let src = src.last().unwrap(); + let dst = dst.last().unwrap(); + total_d += src.distp2(dst); + } + _ => panic!("Invalid routing parameters!"), + } + } + if total_d < best_score { + best_score = total_d; + best_permutation_waypoints = waypoints.to_owned(); + } + } + if !waypoints.next_permutation() { + break; + } + } + + println!("Done in {}!", format_duration(t_start.elapsed())); + println!("Best permutation: {:?}", best_permutation_waypoints); + self.name_multiroute(&best_permutation_waypoints, range, mode, factor) + } + + pub fn name_multiroute( + &self, + waypoints: &[String], + range: f32, + mode: Mode, + factor: f32, + ) -> Vec { + let mut coords = Vec::new(); + for p_name in waypoints { + let mut p_l = self.name_to_systems(p_name); + p_l.sort_by_key(|&p| (p.mult * 10.0) as u8); + let p = p_l.last().unwrap(); + coords.push((p_name, p.pos)); + } + self.multiroute(coords.as_slice(), range, mode, factor) + } + pub fn multiroute( + &self, + waypoints: &[(&String, [f32; 3])], + range: f32, + mode: Mode, + factor: f32, + ) -> Vec { + let mut route: Vec = Vec::new(); + for pair in waypoints.windows(2) { + match *pair { + [src, dst] => { + let block = match mode { + Mode::BFS => self.route_bfs(&src, &dst, range), + Mode::Greedy => self.route_greedy(&src, &dst, range), + Mode::AStar => self.route_astar(&src, &dst, range, factor), + }; + if route.is_empty() { + for sys in block.iter() { + route.push(sys.clone()); + } + } else { + for sys in block.iter().skip(1) { + route.push(sys.clone()); + } + } + } + _ => panic!("Invalid routing parameters!"), + } + } + route + } + + fn name_to_systems(&self, name: &str) -> Vec<&System> { + for sys in &self.tree { + if sys.system == name { + return self.neighbours(&sys, 0.0).collect(); + } + } + eprintln!("System not found: \"{}\"", name); + std::process::exit(1); + } + + pub fn route_astar( + &self, + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), + range: f32, + factor: f32, + ) -> Vec { + if factor == 0.0 { + return self.route_bfs(src, dst, range); + } + println!("Running A-Star with greedy factor of {}", factor); + let (src_name, src) = src; + let (dst_name, dst) = dst; + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + { + let d = dist(src, dst); + println!("Plotting route from {} to {}...", src_name, dst_name); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut found = false; + let mut maxd = 0; + let mut queue: Vec<(usize, usize, &System)> = Vec::new(); + queue.push(( + 0, // depth + (start_sys.distp(goal_sys) / range) as usize, // h + &start_sys, + )); + seen.insert(start_sys.id); + + while !(queue.is_empty() || found) { + while let Some((depth, _, sys)) = queue.pop() { + if depth > maxd { + maxd = depth; + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + } + if sys.id == goal_sys.id { + found = true; + break; + } + queue.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys); + let d_g = (nb.distp(goal_sys) / range) as usize; + (depth + 1, d_g, nb) + }), + ); + queue.sort_by(|b, a| { + let (a_0, a_1) = (a.0 as f32, a.1 as f32); + let (b_0, b_1) = (b.0 as f32, b.1 as f32); + let v_a = a_0 + a_1 * factor; + let v_b = b_0 + b_1 * factor; + fcmp(v_a, v_b) + }); + // queue.reverse(); + } + } + println!(); + + println!(); + if !found { + eprintln!("No route from {} to {} found!", src_name, dst_name); + return Vec::new(); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, + None => { + break; + } + } + } + v.reverse(); + v + } + + pub fn route_greedy( + &self, + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), + range: f32, + ) -> Vec { + println!("Running Greedy-Search"); + let (src_name, src) = src; + let (dst_name, dst) = dst; + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + { + let d = dist(src, dst); + println!("Plotting route from {} to {}...", src_name, dst_name); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", + range, + d, + d / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut found = false; + let mut maxd = 0; + let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); + queue.push((-goal_sys.mult, start_sys.distp2(goal_sys), 0, &start_sys)); + seen.insert(start_sys.id); + while !(queue.is_empty() || found) { + while let Some((_, _, depth, sys)) = queue.pop() { + if depth > maxd { + maxd = depth; + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + } + if sys.id == goal_sys.id { + found = true; + break; + } + queue.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys); + (-nb.mult, nb.distp2(goal_sys), depth + 1, nb) + }), + ); + queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); + queue.reverse(); + } + } + println!(); + println!(); + if !found { + eprintln!("No route from {} to {} found!", src_name, dst_name); + return Vec::new(); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, + None => { + break; + } + } + } + v.reverse(); + v + } + + pub fn precompute(&mut self, src: &str) { + let mut sys_l = self.name_to_systems(src); + sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8); + let sys = sys_l.last().unwrap(); + println!("Precomputing routes starting at {} ...", sys.system); + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut depth = 0; + let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); + queue.push_front((0, &sys)); + seen.insert(sys.id); + while !queue.is_empty() { + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + while let Some((d, sys)) = queue.pop_front() { + queue_next.extend( + self.neighbours(&sys, self.range) + // .filter(|&nb| self.valid(nb)) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys.id); + (d + 1, nb) + }), + ); + } + std::mem::swap(&mut queue, &mut queue_next); + depth += 1; + } + self.route_tree = Some(prev); + let ofn = format!( + "{}_{}{}.router", + src.replace("*", "").replace(" ", "_"), + self.range, + if self.primary_only { "_primary" } else { "" } + ); + println!("\nSaving to {}", ofn); + let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); + // (range, path, route_tree) + let data = ( + self.primary_only, + self.range, + hash_file(&self.path), + String::from(self.path.to_str().unwrap()), + self.route_tree.as_ref().unwrap(), + ); + bincode::serialize_into(&mut out_fh, &data).unwrap(); + } + + fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> FnvHashMap { + println!("Processing {}", path.to_str().unwrap()); + let mut ret = FnvHashMap::default(); + if let Some(c) = &mut self.cache.as_mut() { + let mut missing = false; + for id in ids { + match c.get(*id) { + Some(sys) => { + ret.insert(*id, sys); + } + None => { + println!("ID {} not found in cache", id); + missing = true; + break; + } + } + } + if !missing { + return ret; + } + } + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + println!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| ids.contains(&sys.id)) + .map(|sys| { + ret.insert(sys.id, sys.build()); + }) + .last() + .unwrap_or_else(|| { + eprintln!("Error: No systems matching {:?} found!", ids); + std::process::exit(1); + }); + ret + } + + fn get_system_by_name(path: &PathBuf, name: &str) -> System { + let mut reader = csv::ReaderBuilder::new() + .from_path(path) + .unwrap_or_else(|e| { + eprintln!("Error opening {}: {}", path.to_str().unwrap(), e); + std::process::exit(1); + }); + let sys = reader + .deserialize::() + .map(|res| res.unwrap()) + .find(|sys| sys.system == name) + .unwrap_or_else(|| { + eprintln!("Error: System '{}' not found!", name); + std::process::exit(1); + }); + sys.build() + } + + pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Vec { + let prev = self.route_tree.as_ref().unwrap(); + let dst = Self::get_system_by_name(&systems_path, dst); + if !prev.contains_key(&dst.id) { + eprintln!("System-ID {} not found", dst.id); + std::process::exit(1); + }; + let mut v_ids: Vec = Vec::new(); + let mut v: Vec = Vec::new(); + let mut curr_sys: u32 = dst.id; + loop { + v_ids.push(curr_sys); + match prev.get(&curr_sys) { + Some(sys_id) => curr_sys = *sys_id, + None => { + break; + } + } + } + v_ids.reverse(); + let id_map = self.get_systems_by_ids(&systems_path, &v_ids); + for sys_id in v_ids { + let sys = id_map.get(&sys_id).unwrap(); + v.push(sys.clone()) + } + v + } + + pub fn route_bfs( + &self, + src: &(&String, [f32; 3]), + dst: &(&String, [f32; 3]), + range: f32, + ) -> Vec { + println!("Running BFS"); + let (src_name, src) = src; + let (dst_name, dst) = dst; + let start_sys = self.closest(src); + let goal_sys = self.closest(dst); + let d_total = dist(src, dst); + { + println!("Plotting route from {} to {}...", src_name, dst_name); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", + range, + d_total, + d_total / range + ); + } + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let t_start = Instant::now(); + let mut depth = 0; + let mut found = false; + let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); + let mut d_rem = dist2(&start_sys.pos, &goal_sys.pos); + queue.push_front((0, &start_sys)); + seen.insert(start_sys.id); + while !(queue.is_empty() || found) { + print!( + "[{}] {:.02}% | Depth: {}, Queue: {}, Seen: {} ({:.02}%), Remaining Distance: {} \r", + format_duration(t_start.elapsed()), + (((d_total-d_rem.sqrt())*100f32)/d_total), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total, + d_rem.sqrt() + ); + std::io::stdout().flush().unwrap(); + while let Some((d, sys)) = queue.pop_front() { + if sys.id == goal_sys.id { + found = true; + break; + } + queue_next.extend( + self.neighbours(&sys, range) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys); + let dist = dist2(&nb.pos, &goal_sys.pos); + if dist < d_rem { + d_rem = dist; + } + (d + 1, nb) + }), + ); + } + std::mem::swap(&mut queue, &mut queue_next); + depth += 1; + } + println!(); + println!(); + if !found { + eprintln!("No route from {} to {} found!", src_name, dst_name); + return Vec::new(); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys; + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = *sys, + None => { + break; + } + } + } + v.reverse(); + v + } +} +pub fn route(opts: RouteOpts) -> std::io::Result<()> { + if opts.systems.is_empty() { + if opts.precomp_file.is_some() { + eprintln!("Error: Please specify exatly one system"); + } else if opts.precompute { + eprintln!("Error: Please specify at least one system"); + } else { + eprintln!("Error: Please specify at least two systems"); + } + std::process::exit(1); + } + let mut path = opts.file_path; + let mut router: Router = if opts.precomp_file.is_some() { + let ret = Router::from_file(&opts.precomp_file.clone().unwrap()); + path = ret.0; + ret.1 + } else { + Router::new(&path, opts.range.unwrap(), opts.primary, Box::new(|state| { + println!("State: {:?}",state); + })) + }; + if opts.precompute { + for sys in opts.systems { + router.route_tree = None; + router.precompute(&sys); + } + std::process::exit(0); + } + let t_route = Instant::now(); + let route = if router.route_tree.is_some() { + router.route_to(opts.systems.first().unwrap(), &path) + } else if opts.permute || opts.full_permute { + router.best_name_multiroute( + &opts.systems, + opts.range.unwrap(), + opts.full_permute, + opts.mode, + opts.factor.unwrap_or(1.0), + ) + } else { + router.name_multiroute( + &opts.systems, + opts.range.unwrap(), + opts.mode, + opts.factor.unwrap_or(1.0), + ) + }; + println!("Route computed in {}\n", format_duration(t_route.elapsed())); + if route.is_empty() { + eprintln!("No route found!"); + return Ok(()); + } + let mut total: f32 = 0.0; + for (sys1, sys2) in route.iter().zip(route.iter().skip(1)) { + let dist = sys1.distp(sys2); + total += dist; + println!( + "{} ({}) [{}] ({},{},{}) [{} Ls]: {:.2} Ly", + sys1.body, + sys1.system, + sys1.star_type, + sys1.pos[0], + sys1.pos[1], + sys1.pos[2], + sys1.distance, + dist + ); + } + let sys = route.iter().last().unwrap(); + println!( + "{} ({}) [{}] ({},{},{}) [{} Ls]: {:.2} Ly", + sys.body, sys.system, sys.star_type, sys.pos[0], sys.pos[1], sys.pos[2], sys.distance, 0.0 + ); + println!("Total: {:.2} Ly ({} Jumps)", total, route.len()); + Ok(()) +} diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..f6bccfe --- /dev/null +++ b/setup.py @@ -0,0 +1,23 @@ +from setuptools import setup +from setuptools_rust import Binding, RustExtension, Strip + +setup( + name="ed_lrr_gui", + version="0.1.0", + author="Daniel Seiller", + author_email="earthnuker@gmail.com", + url="none yet", + rust_extensions=[ + RustExtension( + "_ed_lrr", + path="rust/Cargo.toml", + binding=Binding.PyO3, + strip=Strip.All, + native=True, + ) + ], + packages=["ed_lrr_gui"], + entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, + install_requires=["PyQt5", "appdirs", "PyYAML"], + zip_safe=False, +) From ec3972b06cd903711952363ce42dcaed191f8f0e Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 22 Jul 2019 01:55:38 +0200 Subject: [PATCH 18/72] feat(GUI): Add Download functionality, update Rust code, update Python code - Add Download functionality to GUI - Update rust code for use with GUI - Add callbacks to rust code - Add python modules for routing and download --- .gitignore | 7 +- README.md | 6 +- ed_lrr_gui/__main__.py | 184 +++++- ed_lrr_gui/gui/ed_lrr.py | 65 +- ed_lrr_gui/gui/ed_lrr.ui | 136 ++++- ed_lrr_gui/preprocess.py | 45 ++ ed_lrr_gui/router.py | 51 ++ rust/Cargo.lock | 1233 +------------------------------------- rust/Cargo.toml | 9 +- rust/src/common.rs | 1 + rust/src/download.rs | 63 -- rust/src/lib.rs | 135 +++-- rust/src/preprocess.rs | 101 +--- rust/src/route.rs | 422 ++++++------- setup.py | 3 +- test_gui.bat | 1 + 16 files changed, 775 insertions(+), 1687 deletions(-) create mode 100644 ed_lrr_gui/preprocess.py create mode 100644 ed_lrr_gui/router.py delete mode 100644 rust/src/download.rs create mode 100644 test_gui.bat diff --git a/.gitignore b/.gitignore index 86707f4..f8b9d2b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,11 @@ *.tmp *.idx .vscode/** +*.pyd build.bat test.bat -__pycache__ \ No newline at end of file +__pycache__ +DL +*.egg-info +pip-wheel-metadata +rust/target/* \ No newline at end of file diff --git a/README.md b/README.md index 299b692..3afaad9 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,6 @@ rs_gui_test conda create -n ed_lrr_gui_env python=3 conda activate ed_lrr_gui_env python build_gui.py -python build_gui.py -python build_gui.py pip install setuptools_rust pip install . python setup.py build @@ -39,5 +37,5 @@ cd .. ``` # TODO -- refactor ed_lrr to use callbacks -- integrate callbacks into the GUI \ No newline at end of file +- integrate callbacks into the GUI: WIP + - QTimer pulls from queue updates UI (every 100ms) \ No newline at end of file diff --git a/ed_lrr_gui/__main__.py b/ed_lrr_gui/__main__.py index 7f83a54..71c6b13 100644 --- a/ed_lrr_gui/__main__.py +++ b/ed_lrr_gui/__main__.py @@ -1,4 +1,7 @@ import sys +import os +import requests as RQ +from datetime import datetime, timedelta from PyQt5.QtCore import QThread, pyqtSignal, Qt from PyQt5.QtWidgets import ( QMainWindow, @@ -7,23 +10,71 @@ from PyQt5.QtWidgets import ( QProgressDialog, QTreeWidgetItem, ) +from urllib.request import Request, urlopen +import gzip from PyQt5.QtGui import QPalette, QColor import ed_lrr_gui import ed_lrr_gui.config as cfg from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR -import os -from datetime import datetime - -# print(ed_lrr_gui.test({"a": 1, "b": 2})) -# exit(1) +import multiprocessing as MP -class Progressdialog(QProgressDialog): +def sizeof_fmt(num, suffix="B"): + for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: + if abs(num) < 1024.0: + return "{:.02f}{}{}".format(num, unit, suffix) + num /= 1024.0 + return "{:.02f}{}{}".format(num, "Yi", suffix) + + +def t_round(dt): + return dt - dt % timedelta(seconds=1) + + +class ProgressDialog(QProgressDialog): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setWindowModality(Qt.WindowModal) +class DownloadThread(QThread): + progress = pyqtSignal("PyQt_PyObject") + + def __init__(self, systems_url, systems_file, bodies_url, bodies_file): + super().__init__() + self.systems_url = systems_url + self.systems_file = systems_file + self.bodies_url = bodies_url + self.bodies_file = bodies_file + self.running = True + + def __del__(self): + self.wait() + + def stop(self): + self.running = False + + def run(self): + jobs = [ + (self.systems_url, self.systems_file), + (self.bodies_url, self.bodies_file), + ] + for url, dest in jobs: + outfile = url.split("/")[-1] + size = RQ.head(url, headers={"Accept-Encoding": "None"}) + size.raise_for_status() + size = int(size.headers.get("Content-Length", 0)) + with open(dest, "wb") as of: + resp = RQ.get(url, stream=True) + for chunk in resp.iter_content(1024 * 1024): + of.write(chunk) + self.progress.emit( + {"done": of.tell(), "size": size, "outfile": outfile} + ) + if not self.running: + return + + class App(QApplication): def __init__(self): super().__init__(sys.argv) @@ -60,7 +111,9 @@ class App(QApplication): class ED_LRR(Ui_ED_LRR): - pbar_thread = None + dl_thread = None + diag_prog = None + dl_started = None def __init__(self): super().__init__() @@ -118,27 +171,29 @@ class ED_LRR(Ui_ED_LRR): if self.rd_comp.isChecked(): comp_mode = "Compute Route" self.btn_add.setText("Search+Add") - self.lst_sys.setEnabled(True) - self.btn_rm.setEnabled(True) - self.cmb_mode.setEnabled(True) - mode = self.cmb_mode.currentText() - self.set_route_mode(mode) if self.rd_precomp.isChecked(): comp_mode = "Precompute Graph" self.btn_add.setText("Select") - self.lst_sys.setEnabled(False) - self.btn_rm.setEnabled(False) - self.lbl_greedyness.setEnabled(False) - self.sld_greedyness.setEnabled(False) - self.cmb_mode.setEnabled(False) + self.log("COMP_MODE", comp_mode) + self.lst_sys.setEnabled(self.rd_comp.isChecked()) + self.btn_rm.setEnabled(self.rd_comp.isChecked()) + self.cmb_mode.setEnabled(self.rd_comp.isChecked()) + self.btn_permute.setEnabled(self.rd_comp.isChecked()) + self.lbl_keep.setEnabled(self.rd_comp.isChecked()) + self.lbl_mode.setEnabled(self.rd_comp.isChecked()) + self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked()) + self.chk_permute_keep_last.setEnabled(self.rd_comp.isChecked()) + self.set_route_mode(self.rd_precomp.isChecked() or None) - def set_route_mode(self, mode): + def set_route_mode(self, mode=None): + if mode == None: + mode = self.cmb_mode.currentText() self.lbl_greedyness.setEnabled(mode == "A*-Search") self.sld_greedyness.setEnabled(mode == "A*-Search") + self.log("ROUTE_MODE", mode) def set_greedyness(self, value): - val = value / 100 - self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(val)) + self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100)) def sys_to_dict(self, n): header = [ @@ -153,21 +208,30 @@ class ED_LRR(Ui_ED_LRR): def run(self): settings = {} - settings["permute"] = [None, False, True][self.chk_permute_keep.checkState()] + settings["permute"] = ( + self.chk_permute_keep_first.checkState(), + self.chk_permute_keep_last.checkState(), + ) settings["range"] = self.sb_range.value() settings["systems"] = [ self.sys_to_dict(i) for i in range(self.lst_sys.topLevelItemCount()) ] print(settings) - # progress = Progressdialog("TEST\nBLAH", "Cancel", 0, 0, self.main_window) - # progress.setWindowTitle("Computing Route") - # progress.setFixedSize(400, 100) - # progress.setRange(0, 0) - # progress.show() + progress = ProgressDialog( + "(Not actually computing)", "Cancel", 0, 0, self.main_window + ) + progress.setWindowTitle("Computing Route") + progress.setFixedSize(400, 100) + progress.setRange(0, 0) + progress.show() def add_system(self): n = self.lst_sys.topLevelItemCount() + 1 - item = QTreeWidgetItem(self.lst_sys, ["A" + str(n), "B" + str(n)]) + name = self.inp_sys.text() + item = QTreeWidgetItem( + self.lst_sys, [str(n) + ". Name: " + name, "Type: " + name[::-1]] + ) + item.sys_id = "SYS_ID_HERE" item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) def remove_system(self): @@ -175,7 +239,66 @@ class ED_LRR(Ui_ED_LRR): for item in self.lst_sys.selectedItems(): root.removeChild(item) + def dl_canceled(self): + if self.dl_thread: + print("Cancel!") + try: + self.dl_thread.progress.disconnect() + except TypeError: + pass + self.dl_thread.stop() + self.dl_thread.wait() + self.diag_prog.close() + self.dl_thread = None + self.diag_prog = None + self.dl_started = None + + def handle_progress(self, args): + filename = os.path.split(args["outfile"])[-1] + if self.diag_prog is None: + self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) + if self.dl_thread: + self.diag_prog.canceled.connect(self.dl_canceled) + self.diag_prog.show() + t_elapsed = datetime.today() - self.dl_started + rate = args["done"] / t_elapsed.total_seconds() + remaining = (args["size"] - args["done"]) / rate + rate = round(rate, 2) + # print(rate, remaining) + try: + t_rem = timedelta(seconds=remaining) + except OverflowError: + t_rem = "-" + msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( + filename, + sizeof_fmt(args["done"]), + sizeof_fmt(args["size"]), + sizeof_fmt(rate), + t_round(t_elapsed), + t_round(t_rem), + ) + self.diag_prog.setLabelText(msg) + self.diag_prog.setWindowTitle("Downloading EDSM Dumps") + self.diag_prog.setValue((args["done"] * 1000) // args["size"]) + + def run_download(self): + if self.dl_thread: + return + self.dl_started = datetime.today() + self.dl_thread = DownloadThread( + self.inp_systems_dl.currentText(), + self.inp_systems_dest_dl.currentText(), + self.inp_bodies_dl.currentText(), + self.inp_bodies_dest_dl.currentText(), + ) + self.dl_thread.progress.connect(self.handle_progress) + self.dl_thread.start() + print(".") + def setup_signals(self): + self.btn_download.clicked.connect(self.run_download) + self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json") + self.inp_bodies_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\b.json") self.set_greedyness(self.sld_greedyness.value()) self.cmb_mode.currentTextChanged.connect(self.set_route_mode) self.rd_comp.toggled.connect(self.set_comp_mode) @@ -203,7 +326,6 @@ class ED_LRR(Ui_ED_LRR): self.btn_systems_dest_browse_dl.clicked.connect( lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file) ) - self.menu_act_quit.triggered.connect(self.app.quit) def handle_close(self): cfg.write(self.config) @@ -216,11 +338,10 @@ class ED_LRR(Ui_ED_LRR): self.app = app self.setup_signals() self.lst_sys.setHeaderLabels(["Name", "Type"]) + self.set_route_mode() def main(): - import sys - app = App() MainWindow = QMainWindow() ui = ED_LRR() @@ -228,8 +349,9 @@ def main(): MainWindow.show() ret = app.exec_() ui.handle_close() - sys.exit(ret) + exit(ret) if __name__ == "__main__": + MP.freeze_support() main() diff --git a/ed_lrr_gui/gui/ed_lrr.py b/ed_lrr_gui/gui/ed_lrr.py index 70c41d8..76ba5f8 100644 --- a/ed_lrr_gui/gui/ed_lrr.py +++ b/ed_lrr_gui/gui/ed_lrr.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'D:\devel\rust\py_test\ed_lrr_gui\gui\ed_lrr.ui' +# Form implementation generated from reading ui file 'D:\devel\rust\ed_lrr_gui\ed_lrr_gui\gui\ed_lrr.ui' # # Created by: PyQt5 UI code generator 5.13.0 # @@ -22,6 +22,7 @@ class Ui_ED_LRR(object): ED_LRR.setSizePolicy(sizePolicy) ED_LRR.setMinimumSize(QtCore.QSize(577, 500)) ED_LRR.setMaximumSize(QtCore.QSize(577, 500)) + ED_LRR.setStyleSheet("") ED_LRR.setDocumentMode(False) ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded) self.centralwidget = QtWidgets.QWidget(ED_LRR) @@ -30,7 +31,10 @@ class Ui_ED_LRR(object): self.verticalLayout.setObjectName("verticalLayout") self.tabs = QtWidgets.QTabWidget(self.centralwidget) self.tabs.setEnabled(True) + self.tabs.setAutoFillBackground(False) + self.tabs.setTabPosition(QtWidgets.QTabWidget.North) self.tabs.setTabShape(QtWidgets.QTabWidget.Rounded) + self.tabs.setElideMode(QtCore.Qt.ElideNone) self.tabs.setTabsClosable(False) self.tabs.setTabBarAutoHide(False) self.tabs.setObjectName("tabs") @@ -46,10 +50,12 @@ class Ui_ED_LRR(object): self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl) self.inp_bodies_dl = QtWidgets.QComboBox(self.tab_download) self.inp_bodies_dl.setEditable(True) + self.inp_bodies_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) self.inp_bodies_dl.setObjectName("inp_bodies_dl") self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl) self.inp_systems_dl = QtWidgets.QComboBox(self.tab_download) self.inp_systems_dl.setEditable(True) + self.inp_systems_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) self.inp_systems_dl.setObjectName("inp_systems_dl") self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl) self.gridLayout = QtWidgets.QGridLayout() @@ -61,6 +67,7 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth()) self.inp_bodies_dest_dl.setSizePolicy(sizePolicy) self.inp_bodies_dest_dl.setEditable(True) + self.inp_bodies_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) self.inp_bodies_dest_dl.setObjectName("inp_bodies_dest_dl") self.gridLayout.addWidget(self.inp_bodies_dest_dl, 0, 0, 1, 1) self.btn_bodies_dest_browse_dl = QtWidgets.QPushButton(self.tab_download) @@ -79,6 +86,7 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth()) self.inp_systems_dest_dl.setSizePolicy(sizePolicy) self.inp_systems_dest_dl.setEditable(True) + self.inp_systems_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) self.inp_systems_dest_dl.setObjectName("inp_systems_dest_dl") self.gridLayout_2.addWidget(self.inp_systems_dest_dl, 0, 0, 1, 1) self.formLayout.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_2) @@ -111,6 +119,7 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.inp_bodies_pp.sizePolicy().hasHeightForWidth()) self.inp_bodies_pp.setSizePolicy(sizePolicy) self.inp_bodies_pp.setEditable(True) + self.inp_bodies_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) self.inp_bodies_pp.setObjectName("inp_bodies_pp") self.gr_bodies_pp.addWidget(self.inp_bodies_pp, 0, 0, 1, 1) self.formLayout_3.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp) @@ -129,6 +138,7 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.inp_systems_pp.sizePolicy().hasHeightForWidth()) self.inp_systems_pp.setSizePolicy(sizePolicy) self.inp_systems_pp.setEditable(True) + self.inp_systems_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) self.inp_systems_pp.setObjectName("inp_systems_pp") self.gr_systems_pp.addWidget(self.inp_systems_pp, 0, 0, 1, 1) self.formLayout_3.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp) @@ -152,6 +162,7 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.inp_out_pp.sizePolicy().hasHeightForWidth()) self.inp_out_pp.setSizePolicy(sizePolicy) self.inp_out_pp.setEditable(True) + self.inp_out_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) self.inp_out_pp.setObjectName("inp_out_pp") self.gr_out_grid_pp.addWidget(self.inp_out_pp, 0, 0, 1, 1) self.formLayout_3.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp) @@ -178,6 +189,9 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.inp_sys_lst.sizePolicy().hasHeightForWidth()) self.inp_sys_lst.setSizePolicy(sizePolicy) self.inp_sys_lst.setEditable(True) + self.inp_sys_lst.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) + self.inp_sys_lst.setFrame(True) + self.inp_sys_lst.setModelColumn(0) self.inp_sys_lst.setObjectName("inp_sys_lst") self.gr_sys.addWidget(self.inp_sys_lst, 0, 0, 1, 1) self.formLayout_2.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_sys) @@ -203,15 +217,6 @@ class Ui_ED_LRR(object): self.btn_permute = QtWidgets.QPushButton(self.tab_route) self.btn_permute.setObjectName("btn_permute") self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute) - self.chk_permute_keep = QtWidgets.QCheckBox(self.tab_route) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.chk_permute_keep.sizePolicy().hasHeightForWidth()) - self.chk_permute_keep.setSizePolicy(sizePolicy) - self.chk_permute_keep.setTristate(True) - self.chk_permute_keep.setObjectName("chk_permute_keep") - self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.chk_permute_keep) self.lst_sys = QtWidgets.QTreeWidget(self.tab_route) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -226,15 +231,16 @@ class Ui_ED_LRR(object): self.lst_sys.setAlternatingRowColors(True) self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.lst_sys.setHeaderHidden(True) self.lst_sys.setObjectName("lst_sys") self.lst_sys.headerItem().setText(0, "1") - self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.SpanningRole, self.lst_sys) + self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.SpanningRole, self.lst_sys) self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route) self.sb_range.setObjectName("sb_range") - self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.sb_range) + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.sb_range) self.lbl_range = QtWidgets.QLabel(self.tab_route) self.lbl_range.setObjectName("lbl_range") - self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.lbl_range) + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.lbl_range) self.gr_opts = QtWidgets.QGridLayout() self.gr_opts.setObjectName("gr_opts") self.cmb_mode = QtWidgets.QComboBox(self.tab_route) @@ -262,11 +268,34 @@ class Ui_ED_LRR(object): self.lbl_mode = QtWidgets.QLabel(self.tab_route) self.lbl_mode.setObjectName("lbl_mode") self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1) - self.formLayout_2.setLayout(7, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) + self.formLayout_2.setLayout(9, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) self.btn_go = QtWidgets.QPushButton(self.tab_route) self.btn_go.setFlat(False) self.btn_go.setObjectName("btn_go") - self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btn_go) + self.formLayout_2.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.btn_go) + self.gridLayout_4 = QtWidgets.QGridLayout() + self.gridLayout_4.setObjectName("gridLayout_4") + self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route) + self.chk_permute_keep_last.setObjectName("chk_permute_keep_last") + self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 2, 1, 1) + self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chk_permute_keep_first.sizePolicy().hasHeightForWidth()) + self.chk_permute_keep_first.setSizePolicy(sizePolicy) + self.chk_permute_keep_first.setTristate(False) + self.chk_permute_keep_first.setObjectName("chk_permute_keep_first") + self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 1, 1, 1) + self.lbl_keep = QtWidgets.QLabel(self.tab_route) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth()) + self.lbl_keep.setSizePolicy(sizePolicy) + self.lbl_keep.setObjectName("lbl_keep") + self.gridLayout_4.addWidget(self.lbl_keep, 0, 0, 1, 1) + self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4) self.tabs.addTab(self.tab_route, "") self.tab_log = QtWidgets.QWidget() self.tab_log.setObjectName("tab_log") @@ -299,6 +328,7 @@ class Ui_ED_LRR(object): self.retranslateUi(ED_LRR) self.tabs.setCurrentIndex(2) + self.menu_act_quit.triggered.connect(ED_LRR.close) QtCore.QMetaObject.connectSlotsByName(ED_LRR) ED_LRR.setTabOrder(self.rd_comp, self.cmb_mode) ED_LRR.setTabOrder(self.cmb_mode, self.chk_primary) @@ -329,11 +359,11 @@ class Ui_ED_LRR(object): self.lbl_sys_lst.setText(_translate("ED_LRR", "System List")) self.btn_sys_lst_browse.setText(_translate("ED_LRR", "...")) self.btn_add.setText(_translate("ED_LRR", "Search+Add")) + self.inp_sys.setPlaceholderText(_translate("ED_LRR", "System Name")) self.btn_rm.setText(_translate("ED_LRR", "Remove")) self.rd_comp.setText(_translate("ED_LRR", "Compute Route")) self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph")) self.btn_permute.setText(_translate("ED_LRR", "Permute")) - self.chk_permute_keep.setText(_translate("ED_LRR", "Keep endpoints (No, first only, yes)")) self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)")) self.cmb_mode.setCurrentText(_translate("ED_LRR", "Breadth-First Search")) self.cmb_mode.setItemText(0, _translate("ED_LRR", "Breadth-First Search")) @@ -343,6 +373,9 @@ class Ui_ED_LRR(object): self.chk_primary.setText(_translate("ED_LRR", "Primary Stars Only")) self.lbl_mode.setText(_translate("ED_LRR", "Mode")) self.btn_go.setText(_translate("ED_LRR", "GO!")) + self.chk_permute_keep_last.setText(_translate("ED_LRR", "Last")) + self.chk_permute_keep_first.setText(_translate("ED_LRR", "First")) + self.lbl_keep.setText(_translate("ED_LRR", "Keep Endpoints:")) self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")) self.menu_file.setTitle(_translate("ED_LRR", "File")) diff --git a/ed_lrr_gui/gui/ed_lrr.ui b/ed_lrr_gui/gui/ed_lrr.ui index 24cb6be..7034a30 100644 --- a/ed_lrr_gui/gui/ed_lrr.ui +++ b/ed_lrr_gui/gui/ed_lrr.ui @@ -34,6 +34,9 @@ Elite: Dangerous Long Range Route Plotter + + + false @@ -47,12 +50,21 @@ true + + false + + + QTabWidget::North + QTabWidget::Rounded 2 + + Qt::ElideNone + false @@ -86,6 +98,9 @@ https://www.edsm.net/dump/bodies.json + + QComboBox::InsertAtTop + @@ -96,6 +111,9 @@ https://www.edsm.net/dump/systemsWithCoordinates.json + + QComboBox::InsertAtTop + @@ -111,6 +129,9 @@ true + + QComboBox::InsertAtTop + @@ -142,6 +163,9 @@ true + + QComboBox::InsertAtTop + @@ -201,6 +225,9 @@ true + + QComboBox::InsertAtTop + @@ -232,6 +259,9 @@ true + + QComboBox::InsertAtTop + @@ -269,6 +299,9 @@ true + + QComboBox::InsertAtTop + @@ -314,6 +347,15 @@ true + + QComboBox::InsertAtTop + + + true + + + 0 + @@ -326,7 +368,11 @@ - + + + System Name + + @@ -363,23 +409,7 @@ - - - - - 0 - 0 - - - - Keep endpoints (No, first only, yes) - - - true - - - - + @@ -414,6 +444,9 @@ QAbstractItemView::SelectRows + + true + 1 @@ -421,17 +454,17 @@ - + - + Jump Range (Ly) - + @@ -503,7 +536,7 @@ - + GO! @@ -513,6 +546,46 @@ + + + + + + Last + + + + + + + + 0 + 0 + + + + First + + + false + + + + + + + + 0 + 0 + + + + Keep Endpoints: + + + + + @@ -580,5 +653,22 @@ rd_precomp - + + + menu_act_quit + triggered() + ED_LRR + close() + + + -1 + -1 + + + 288 + 249 + + + + diff --git a/ed_lrr_gui/preprocess.py b/ed_lrr_gui/preprocess.py new file mode 100644 index 0000000..b7c8675 --- /dev/null +++ b/ed_lrr_gui/preprocess.py @@ -0,0 +1,45 @@ +from multiprocessing import Process, Queue, freeze_support +import queue +from datetime import datetime, timedelta +import _ed_lrr +from collections import namedtuple + + +class Preprocessor(Process): + def __init__(self, *args, **kwargs): + super().__init__() + self.state = {} + self.queue = Queue() + self.daemon = True + self.args = args + self.kwargs = kwargs + self.kwargs["callback"] = self.callback + self.start() + + def __iter__(self): + while self.is_alive(): + try: + self.state.update(self.queue.get(True, 0.5)) + yield self.state + except queue.Empty: + pass + while not self.queue.empty(): + self.state.update(self.queue.get(True, 0.5)) + yield self.state + + def callback(self, state): + self.queue.put({"status": state}) + + def run(self): + _ed_lrr.preprocess(*self.args, **self.kwargs) + + +if __name__ == "__main__": + freeze_support() + r = Preprocessor( + r"D:\devel\rust\ED_LRR\dumps\systemsWithCoordinates.json", + r"D:\devel\rust\ED_LRR\dumps\bodies.json", + r"D:\devel\rust\ED_LRR\stars.csv", + ) + for i, e in enumerate(r): + print(e) diff --git a/ed_lrr_gui/router.py b/ed_lrr_gui/router.py new file mode 100644 index 0000000..773f939 --- /dev/null +++ b/ed_lrr_gui/router.py @@ -0,0 +1,51 @@ +from multiprocessing import Process, Queue, freeze_support +import queue +from datetime import datetime, timedelta +import _ed_lrr +from collections import namedtuple + + +class Router(Process): + def __init__(self, *args, **kwargs): + super().__init__() + self.state = {} + self.queue = Queue() + self.daemon = True + self.args = args + self.kwargs = kwargs + self.kwargs["callback"] = self.callback + self.start() + + def __iter__(self): + while self.is_alive(): + try: + self.state.update(self.queue.get(True, 0.5)) + yield self.state + except queue.Empty: + pass + while not self.queue.empty(): + self.state.update(self.queue.get(True, 0.5)) + yield self.state + + def callback(self, state): + self.queue.put({"status": state}) + + def run(self): + route = _ed_lrr.route(*self.args, **self.kwargs) + self.queue.put({"return": route}) + + +if __name__ == "__main__": + freeze_support() + r = Router( + ["Ix", "Beagle Point"], + 48, + "BFS", + False, + False, + None, + None, + r"D:\devel\rust\ED_LRR\stars.csv", + ) + for e in r: + print(e) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 84eb592..d65855d 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,10 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "aho-corasick" version = "0.7.3" @@ -13,22 +8,6 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayvec" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "atty" version = "0.2.11" @@ -44,34 +23,6 @@ name = "autocfg" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "backtrace" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bincode" version = "1.1.4" @@ -127,49 +78,11 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "c2-chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "clap" -version = "2.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clicolors-control" version = "1.0.0" @@ -206,93 +119,6 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cookie" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cookie_store" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation-sys" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crc32fast" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "csv" version = "1.1.1" @@ -330,11 +156,6 @@ dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "dtoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "ed_lrr" version = "0.1.0" @@ -347,13 +168,10 @@ dependencies = [ "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)", "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -366,104 +184,16 @@ name = "encode_unicode" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "encoding_rs" -version = "0.8.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "error-chain" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "generic-array" version = "0.12.3" @@ -472,15 +202,6 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "getrandom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ghost" version = "0.1.0" @@ -491,57 +212,6 @@ dependencies = [ "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "h2" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "http" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "http-body" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "httparse" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "humantime" version = "1.2.0" @@ -550,62 +220,6 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hyper" -version = "0.12.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper-tls" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "indexmap" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "indicatif" version = "0.11.0" @@ -638,15 +252,6 @@ dependencies = [ "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "iovec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itertools" version = "0.8.0" @@ -665,37 +270,16 @@ name = "keccak" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "libc" version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lock_api" version = "0.2.0" @@ -704,14 +288,6 @@ dependencies = [ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "mashup" version = "0.1.9" @@ -730,11 +306,6 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "memchr" version = "2.2.0" @@ -743,109 +314,6 @@ dependencies = [ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memoffset" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "mime" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime_guess" -version = "2.0.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide_c_api" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "native-tls" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.23 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "num-traits" version = "0.2.8" @@ -854,14 +322,6 @@ dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num_cpus" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "number_prefix" version = "0.2.8" @@ -880,53 +340,6 @@ name = "opaque-debug" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "openssl" -version = "0.10.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl-probe" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "openssl-sys" -version = "0.9.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "owning_ref" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot" version = "0.8.0" @@ -937,18 +350,6 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot_core" version = "0.5.0" @@ -969,61 +370,11 @@ name = "pdqselect" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "permutohedron" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "phf" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_codegen" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_generator" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_shared" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pkg-config" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ppv-lite86" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc-macro-hack" version = "0.4.1" @@ -1045,18 +396,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "publicsuffix" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pyo3" version = "0.7.0" @@ -1124,18 +463,6 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_chacha" version = "0.1.1" @@ -1145,16 +472,6 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_chacha" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_core" version = "0.3.1" @@ -1168,14 +485,6 @@ name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "rand_core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_hc" version = "0.1.0" @@ -1184,14 +493,6 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_isaac" version = "0.1.1" @@ -1289,46 +590,6 @@ dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "remove_dir_all" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "reqwest" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rstar" version = "0.4.0" @@ -1339,11 +600,6 @@ dependencies = [ "pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc-demangle" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc_version" version = "0.2.3" @@ -1357,44 +613,11 @@ name = "ryu" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "schannel" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "security-framework" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "security-framework-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "semver" version = "0.9.0" @@ -1413,12 +636,12 @@ name = "serde" version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.95 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1436,17 +659,6 @@ dependencies = [ "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "serde_urlencoded" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "sha3" version = "0.8.2" @@ -1459,16 +671,6 @@ dependencies = [ "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "siphasher" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "smallvec" version = "0.6.10" @@ -1479,44 +681,6 @@ name = "spin" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "stable_deref_trait" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "string" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "structopt" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "structopt-derive" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.15.39" @@ -1527,30 +691,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "synstructure" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempfile" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "termion" version = "1.5.3" @@ -1570,14 +710,6 @@ dependencies = [ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread_local" version = "0.3.6" @@ -1586,152 +718,6 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "time" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-buf" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-sync" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "try-lock" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "try_from" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "typenum" version = "1.10.0" @@ -1742,43 +728,6 @@ name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicase" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-segmentation" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-width" version = "0.1.5" @@ -1789,59 +738,16 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "utf8-ranges" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "uuid" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "vcpkg" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "vec_map" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "want" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi" version = "0.3.7" @@ -1851,11 +757,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1866,25 +767,10 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "18b50f5258d1a9ad8396d2d345827875de4261b158124d4c819d9b351454fae5" -"checksum backtrace-sys 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5b3a000b9c543553af61bc01cbfc403b04b5caa9e421033866f2e98061eb3e61" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" @@ -1892,123 +778,54 @@ dependencies = [ "checksum bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc0572e02f76cb335f309b19e0a0d585b4f62788f7d26de2a13a836a637385f" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" -"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" -"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" -"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" -"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" -"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed" -"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" -"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" "checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" -"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" -"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum hyper 0.12.31 (registry+https://github.com/rust-lang/crates.io-index)" = "6481fff8269772d4463253ca83c788104a7305cb3fb9136bc651a6211e46e03f" -"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" "checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922" "checksum inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a877ae8bce77402d5e9ed870730939e097aad827b2a932b361958fa9d6e75aa" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" -"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b" "checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" -"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" -"checksum miniz_oxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b6c3756d66cf286314d5f7ebe74886188a9a92f5eee68b06f31ac2b4f314c99d" -"checksum miniz_oxide_c_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5b78ca5446dd9fe0dab00e058731b6b08a8c1d2b9cdb8efb10876e24e9ae2494" -"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" -"checksum openssl 0.10.23 (registry+https://github.com/rust-lang/crates.io-index)" = "97c140cbb82f3b3468193dd14c1b88def39f341f68257f8a7fe8ed9ed3f628a5" -"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)" = "75bdd6dbbb4958d38e47a1d2348847ad1eb4dc205dc5d37473ae504391865acc" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" -"checksum phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" -"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" -"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" -"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" -"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d" "checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086" "checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186" "checksum pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c494f8161f5b73096cc50f00fbb90fe670f476cde5e59c1decff39b546d54f40" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" @@ -2020,72 +837,28 @@ dependencies = [ "checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" "checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86" "checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "00eb63f212df0e358b427f0f40aa13aaea010b470be642ad422bcbca2feff2e4" "checksum rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd08ae4f9661517777346592956ea6cdbba2895a28037af7daa600382f4b4001" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" -"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b" -"checksum serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "ef45eb79d6463b22f5f9e16d283798b7c0175ba6050bc25c1a946c122727fe7b" +"checksum serde_derive 1.0.95 (registry+https://github.com/rust-lang/crates.io-index)" = "5ea8eb91549d859275aef70c58bb30bd62ce50e5eb1a52d32b1b6886e02f7bce" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" -"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" "checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" -"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" -"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac" -"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" -"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" -"checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7" -"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19" -"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" -"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" -"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" -"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 132a70d..d97be65 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,15 +11,13 @@ license = "WTFPL" crate-type = ["cdylib"] [profile.release] -# debug=true +debug=true [dependencies] csv = "1.1.1" -serde = "1.0.94" -serde_derive = "1.0.94" -rstar = {version="0.4.0"} +serde = { version = "1.0", features = ["derive"] } +rstar = "0.4.0" humantime = "1.2.0" -structopt = "0.2.18" permutohedron = "0.2.4" serde_json = "1.0.40" indicatif = "0.11.0" @@ -27,7 +25,6 @@ fnv = "1.0.6" bincode = "1.1.4" sha3 = "0.8.2" byteorder = "1.3.2" -reqwest = "0.9.18" [dependencies.pyo3] version = "0.7.0" diff --git a/rust/src/common.rs b/rust/src/common.rs index 922aafd..6e563f4 100644 --- a/rust/src/common.rs +++ b/rust/src/common.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SystemSerde { pub id: u32, diff --git a/rust/src/download.rs b/rust/src/download.rs deleted file mode 100644 index 57ceaa8..0000000 --- a/rust/src/download.rs +++ /dev/null @@ -1,63 +0,0 @@ -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use std::fs::File; -use std::io; -use std::path::PathBuf; -use structopt::StructOpt; - -#[derive(Debug, StructOpt, Clone)] -pub struct DownloadOpts { - #[structopt( - long = "bodies", - default_value = "https://www.edsm.net/dump/bodies.json" - )] - /// Url to bodies.json - bodies_url: String, - #[structopt( - long = "systems", - default_value = "https://www.edsm.net/dump/systemsWithCoordinates.json" - )] - /// Url to systemsWithCoordinates.json - systems_url: String, -} - -fn fetch_url(url: &str, prog_bar: &ProgressBar) -> std::io::Result<()> { - let outfile = url.split('/').last().unwrap(); - let template = format!("{} {}", "[{elapsed_precise}] {binary_bytes}", outfile); - prog_bar.set_style(ProgressStyle::default_bar().template(&template)); - - let client = reqwest::Client::builder().gzip(true).build().unwrap(); - let resp = client.get(url).send().unwrap(); - let target_path = PathBuf::from(format!("dumps/{}", outfile)); - if target_path.exists() { - eprintln!("Error: Target {} exists!", outfile); - return Ok(()); - } - let mut target = File::create(target_path)?; - io::copy(&mut prog_bar.wrap_read(resp), &mut target).unwrap(); - prog_bar.finish(); - Ok(()) -} - -pub fn download(opts: DownloadOpts) -> std::io::Result<()> { - let mut threads = Vec::new(); - let m = MultiProgress::new(); - { - let opts = opts.clone(); - let pb = m.add(ProgressBar::new(0)); - threads.push(std::thread::spawn(move || { - fetch_url(&opts.bodies_url, &pb).unwrap(); - })); - }; - { - let opts = opts.clone(); - let pb = m.add(ProgressBar::new(0)); - threads.push(std::thread::spawn(move || { - fetch_url(&opts.systems_url, &pb).unwrap(); - })); - } - m.join_and_clear().unwrap(); - for th in threads { - th.join().unwrap(); - } - Ok(()) -} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 3d65b7d..fdc0fb4 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,56 +1,120 @@ mod common; -mod download; mod preprocess; mod route; -use std::collections::HashMap; use pyo3::prelude::*; -use pyo3::types::PyDict; +use pyo3::types::{PyDict,PyList}; +use pyo3::exceptions::*; use std::path::PathBuf; #[pymodule] -pub fn _ed_lrr(py: Python, m: &PyModule) -> PyResult<()> { - /// Test - #[pyfn(m,"test")] - fn test(py:Python,o:PyObject) -> PyResult<()> { - println!("OBJ: {:?}",o); - return Ok(()); - } +pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { - /// download(systems_url,systems_file, bodies_url, bodies_file, callback) - /// -- - /// - /// Download bodies.json and systemsWithCoordinates.json - #[pyfn(m, "download")] - fn download(py: Python, systems_url: String, systems_file: String, bodies_url:String,bodies_file:String,callback: PyObject) -> PyResult { - let state = PyDict::new(py); - state.set_item("systems_url", systems_url)?; - state.set_item("systems_file", systems_file)?; - state.set_item("bodies_url", bodies_url)?; - state.set_item("bodies_file", bodies_file)?; - state.set_item("callback", callback)?; - return Ok(state.to_object(py)); - } - /// preprocess(infile_systems, infile_bodies, outfile, callback) - /// -- + /// -- /// /// Preprocess bodies.json and systemsWithCoordinates.json into stars.csv #[pyfn(m, "preprocess")] - fn preprocess(py: Python, infile_systems: String, infile_bodies: String, outfile:String,callback: PyObject) -> PyResult { + fn ed_lrr_preprocess( + py: Python<'static>, + infile_systems: String, + infile_bodies: String, + outfile: String, + callback: PyObject, + ) -> PyResult { + use preprocess::*; let state = PyDict::new(py); - state.set_item("infile_systems", infile_systems)?; - state.set_item("infile_bodies", infile_bodies)?; - state.set_item("outfile", outfile)?; - state.set_item("callback", callback)?; + let state_dict = PyDict::new(py); + callback.call(py,(state_dict,),None).unwrap(); + let callback_wrapped = move |state: &PreprocessState| { + // println!("SEND: {:?}",state); + state_dict.set_item("file",state.file.clone())?; + state_dict.set_item("total",state.total)?; + state_dict.set_item("done",state.done)?; + callback.call(py,(state_dict,),None) + }; + preprocess_files(&PathBuf::from(infile_bodies), &PathBuf::from(infile_systems), &PathBuf::from(outfile), Box::new(callback_wrapped)).unwrap(); return Ok(state.to_object(py)); } - /// route(infile, source, dest, range, mode, greedyness, precomp, callback) + /// route(infile, hops, range, mode,primary, greedyness, precomp, callback) /// -- /// /// Compute a Route using the suplied parameters #[pyfn(m, "route")] - fn route(py: Python, infile: String, source: String, dest:String, range: f32, mode: String,greedyness: Option, precomp: Option,callback: PyObject) -> PyResult { + fn route( + py: Python<'static>, + hops: Vec, + range: f32, + mode: String, + primary: bool, + permute: bool, + greedyness: Option, + precomp: Option, + path: String, + callback: PyObject, + ) -> PyResult { + use route::*; + // TODO: Verify Parameters + let mode = match Mode::parse(&mode) { + Ok(val) => val, + Err(e) => { + return Err(PyErr::new::(e)); + } + }; + let state_dict = PyDict::new(py); + callback.call(py,(state_dict,),None).unwrap(); + let callback_wrapped = move |state: &SearchState| { + println!("SEND: {:?}",state); + state_dict.set_item("mode",state.mode.clone())?; + state_dict.set_item("system",state.system.clone())?; + state_dict.set_item("body",state.body.clone())?; + state_dict.set_item("depth",state.depth)?; + state_dict.set_item("queue_size",state.queue_size)?; + state_dict.set_item("d_rem",state.d_rem)?; + state_dict.set_item("d_total",state.d_total)?; + state_dict.set_item("prc_done",state.prc_done)?; + state_dict.set_item("n_seen",state.n_seen)?; + state_dict.set_item("prc_seen",state.prc_seen)?; + callback.call(py,(state_dict,),None) + }; + let opts=RouteOpts{ + systems:hops, + range:Some(range), + file_path: PathBuf::from(path), + precomp_file: precomp.map(PathBuf::from), + callback: Box::new(callback_wrapped), + mode, + factor: greedyness, + precompute: false, + permute: permute, + keep_first: true, + keep_last: true, + primary + }; + let none=().to_object(py); + match route(opts) { + Ok(Some(route)) => { + let hops=route.iter().map(|hop| { + let pos=PyList::new(py,hop.pos.iter()); + let elem=PyDict::new(py); + elem.set_item("star_type",hop.star_type.clone()).unwrap(); + elem.set_item("system",hop.system.clone()).unwrap(); + elem.set_item("body",hop.body.clone()).unwrap(); + elem.set_item("distance",hop.distance).unwrap(); + elem.set_item("pos",pos).unwrap(); + return elem; + }); + let lst=PyList::new(py,hops); + return Ok(lst.to_object(py)); + } + Ok(None) => { + return Ok(none); + }, + Err(e) => { + return Err(PyErr::new::(e)); + } + }; + /* let state = PyDict::new(py); state.set_item("infile", infile)?; state.set_item("source", source)?; @@ -60,7 +124,8 @@ pub fn _ed_lrr(py: Python, m: &PyModule) -> PyResult<()> { state.set_item("greedyness", greedyness)?; state.set_item("precomp", precomp)?; state.set_item("callback", callback)?; - return Ok(state.to_object(py)); + return callback.call(py,(state.to_object(py),),None); + */ } Ok(()) -} \ No newline at end of file +} diff --git a/rust/src/preprocess.rs b/rust/src/preprocess.rs index c564ea8..83464b3 100644 --- a/rust/src/preprocess.rs +++ b/rust/src/preprocess.rs @@ -1,33 +1,14 @@ use crate::common::SystemSerde; use fnv::FnvHashMap; -use humantime::format_duration; -use indicatif::{ProgressBar, ProgressStyle}; use serde::Deserialize; use serde_json::Result; use std::fs::File; use std::io::Seek; use std::io::{BufRead, BufReader, BufWriter, SeekFrom}; use std::path::PathBuf; -use std::str; use std::time::Instant; -use structopt::StructOpt; - -#[derive(Debug, StructOpt)] -pub struct PreprocessOpts { - #[structopt(short, long = "bodies", default_value = "dumps/bodies.json")] - /// Path to bodies.json - pub bodies: PathBuf, - #[structopt( - short, - long = "systems", - default_value = "dumps/systemsWithCoordinates.json" - )] - /// Path to systemsWithCoordinates.json - pub systems: PathBuf, - #[structopt(default_value = "stars")] - /// outfile prefix - pub prefix: String, -} +use std::str; +use pyo3::prelude::*; #[derive(Debug, Deserialize)] #[allow(non_snake_case)] @@ -58,25 +39,15 @@ struct System { date: String, } -#[derive(Debug, StructOpt)] -#[structopt( - name = "ed_lrr_pp", - about = "Preprocessor for Elite: Dangerous Long-Range Router", - rename_all = "snake_case" -)] -/// Preprocess data for ed_lrr -struct Opt { - #[structopt(short, long = "bodies")] - /// Path to bodies.json - bodies: PathBuf, - #[structopt(short, long = "systems")] - /// Path to systemsWithCoordinates.json - systems: PathBuf, - #[structopt(default_value = "stars")] - /// outfile prefix - prefix: String, +#[derive(Debug)] +pub struct PreprocessState { + pub file: String, + pub total: u64, + pub done: u64, + pub count: usize, } + fn get_mult(star_type: &str) -> f32 { if star_type.contains("White Dwarf") { return 1.5; @@ -87,22 +58,18 @@ fn get_mult(star_type: &str) -> f32 { 1.0 } -fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std::io::Result<()> { - let mut cnt = 0; +fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> (),callback: &Box PyResult>) -> std::io::Result<()> { let mut buffer = String::new(); - let t_start = Instant::now(); let fh = File::open(path)?; - let prog_bar = ProgressBar::new(fh.metadata()?.len()); - prog_bar.set_style( - ProgressStyle::default_bar() - .template( - "[{elapsed_precise}/{eta_precise}]{spinner} [{wide_bar}] {binary_bytes}/{binary_total_bytes} ({percent}%)", - ) - .progress_chars("#9876543210 ") - .tick_chars("/-\\|"), - ); - prog_bar.set_draw_delta(1024 * 1024); + let total_size= fh.metadata()?.len(); + let mut t_last=Instant::now(); let mut reader = BufReader::new(fh); + let mut state=PreprocessState { + file: path.to_str().unwrap().to_owned(), + total: total_size, + done: 0, + count: 0 + }; println!("Loading {} ...", path.to_str().unwrap()); while let Ok(n) = reader.read_line(&mut buffer) { if n == 0 { @@ -112,20 +79,19 @@ fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> ()) -> std:: if !buffer.is_empty() { func(&buffer); } - prog_bar.set_position(reader.seek(SeekFrom::Current(0)).unwrap()); - cnt += 1; + let pos=reader.seek(SeekFrom::Current(0)).unwrap(); + state.done=pos; + state.count += 1; + if (t_last.elapsed().as_millis()>100) { + callback(&state)?; + t_last=Instant::now(); + } buffer.clear(); } - prog_bar.finish_and_clear(); - println!( - "Processed {} lines in {} ...", - cnt, - format_duration(t_start.elapsed()) - ); Ok(()) } -fn process_systems(path: &PathBuf) -> FnvHashMap { +fn process_systems(path: &PathBuf,callback: &Box PyResult> ) -> FnvHashMap { let mut ret = FnvHashMap::default(); process(path, &mut |line| { let sys_res: Result = serde_json::from_str(&line); @@ -134,7 +100,7 @@ fn process_systems(path: &PathBuf) -> FnvHashMap { } else { eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); } - }) + },callback) .unwrap(); ret } @@ -155,10 +121,10 @@ fn build_index(path: &PathBuf) -> std::io::Result<()> { fn process_bodies( path: &PathBuf, - out_prefix: &str, + out_path: &PathBuf, systems: &mut FnvHashMap, + callback: &Box PyResult>, ) -> std::io::Result<()> { - let out_path = PathBuf::from(format!("{}.csv", out_prefix)); println!( "Processing {} into {} ...", path.to_str().unwrap(), @@ -196,18 +162,17 @@ fn process_bodies( } else { eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); } - }) + },callback) .unwrap(); println!("Total Systems: {}", n); systems.clear(); Ok(()) } -pub fn preprocess_files(opts: PreprocessOpts) -> std::io::Result<()> { - let out_path = PathBuf::from(format!("{}.csv", &opts.prefix)); +pub fn preprocess_files(bodies: &PathBuf,systems:&PathBuf,out_path:&PathBuf,callback: Box PyResult>) -> std::io::Result<()> { if !out_path.exists() { - let mut systems = process_systems(&opts.systems); - process_bodies(&opts.bodies, &opts.prefix, &mut systems)?; + let mut systems = process_systems(systems,&callback); + process_bodies(bodies, out_path, &mut systems,&callback)?; } else { println!( "File '{}' exists, not overwriting it", diff --git a/rust/src/route.rs b/rust/src/route.rs index dd11596..d206501 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -11,25 +11,25 @@ use std::hash::{Hash, Hasher}; use std::io::Seek; use std::io::{BufRead, BufReader, BufWriter, Write}; use std::path::PathBuf; -use std::str::FromStr; use std::time::Instant; -use structopt::StructOpt; - +use pyo3::prelude::*; use crate::common::{System, SystemSerde}; #[derive(Debug)] pub struct SearchState { pub mode: String, + pub system: String, + pub body: String, pub depth: usize, pub queue_size: usize, - pub d_rem: f64, - pub prc_done: f64, + pub d_rem: f32, + pub d_total: f32, + pub prc_done: f32, pub n_seen: usize, - pub prc_seen: f64 + pub prc_seen: f32 } -#[derive(Debug)] pub struct RouteOpts { pub range: Option, pub file_path: PathBuf, @@ -37,10 +37,12 @@ pub struct RouteOpts { pub precompute: bool, pub permute: bool, pub primary: bool, - pub full_permute: bool, + pub keep_first: bool, + pub keep_last: bool, pub factor: Option, pub mode: Mode, pub systems: Vec, + pub callback: Box PyResult> } #[derive(Debug)] @@ -50,10 +52,10 @@ pub enum Mode { AStar, } -impl FromStr for Mode { - type Err = String; - fn from_str(s: &str) -> Result { - match s { +impl Mode { + pub fn parse(s: &str) -> Result { + let s=s.to_lowercase(); + match s.as_ref() { "bfs" => Ok(Mode::BFS), "greedy" => Ok(Mode::Greedy), "astar" => Ok(Mode::AStar), @@ -138,8 +140,6 @@ struct LineCache { impl LineCache { pub fn new(path: &PathBuf) -> Option { let idx_path = path.with_extension("idx"); - let t_load = Instant::now(); - println!("Loading Index from {}", idx_path.to_str().unwrap()); let cache = bincode::deserialize_from(&mut BufReader::new(File::open(idx_path).ok()?)).ok()?; let mut reader = BufReader::new(File::open(path).ok()?); @@ -149,7 +149,6 @@ impl LineCache { cache, header, }; - println!("Done in {}!", format_duration(t_load.elapsed())); Some(ret) } fn read_record(reader: &mut BufReader) -> Option { @@ -176,19 +175,18 @@ pub struct Router { range: f32, primary_only: bool, path: PathBuf, - callback: Box ()>, + callback: Box PyResult> } impl Router { - pub fn new(path: &PathBuf, range: f32, primary_only: bool,callback: Box ()>) -> Self { + pub fn new(path: &PathBuf, range: f32, primary_only: bool,callback: Box PyResult>) -> Result { let mut scoopable = FnvHashSet::default(); - let mut reader = csv::ReaderBuilder::new() - .from_path(path) - .unwrap_or_else(|e| { - println!("Error opening {}: {}", path.to_str().unwrap(), e); - std::process::exit(1); - }); - let t_load = Instant::now(); + let mut reader = match csv::ReaderBuilder::new().from_path(path) { + Ok(rdr) => rdr, + Err(e) => { + return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); + } + }; println!("Loading {}...", path.to_str().unwrap()); let systems: Vec = reader .deserialize::() @@ -214,7 +212,6 @@ impl Router { sys.build() }) .collect(); - println!("Building RTree..."); let ret = Self { tree: RTree::bulk_load(systems), scoopable, @@ -225,18 +222,11 @@ impl Router { path: path.clone(), callback: callback, }; - println!( - "{} Systems loaded in {}", - ret.tree.size(), - format_duration(t_load.elapsed()) - ); - ret + Ok(ret) } - pub fn from_file(filename: &PathBuf) -> (PathBuf, Self) { - let t_load = Instant::now(); + pub fn from_file(filename: &PathBuf,callback: Box PyResult>) -> Result<(PathBuf, Self),String> { let mut reader = BufReader::new(File::open(&filename).unwrap()); - println!("Loading {}", filename.to_str().unwrap()); let (primary, range, file_hash, path, route_tree): ( bool, f32, @@ -245,12 +235,11 @@ impl Router { FnvHashMap, ) = bincode::deserialize_from(&mut reader).unwrap(); let path = PathBuf::from(path); - println!("Done in {}!", format_duration(t_load.elapsed())); if hash_file(&path) != file_hash { - panic!("File hash mismatch!") + return Err("File hash mismatch!".to_string()); } let cache = LineCache::new(&path); - ( + Ok(( path.clone(), Self { tree: RTree::default(), @@ -260,9 +249,9 @@ impl Router { cache, primary_only: primary, path, - callback: Box::new(|s| {}), + callback }, - ) + )) } fn closest(&self, point: &[f32; 3]) -> &System { @@ -284,34 +273,34 @@ impl Router { &self, waypoints: &[String], range: f32, - full: bool, + keep: (bool,bool), mode: Mode, factor: f32, - ) -> Vec { + ) -> Result,String> { let mut best_score: f32 = std::f32::MAX; let mut waypoints = waypoints.to_owned(); let mut best_permutation_waypoints = waypoints.to_owned(); let first = waypoints.first().cloned(); let last = waypoints.last().cloned(); - let t_start = Instant::now(); println!("Finding best permutation of hops..."); while waypoints.prev_permutation() {} loop { let c_first = waypoints.first().cloned(); let c_last = waypoints.last().cloned(); - if full || ((c_first == first) && (c_last == last)) { + let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last==last)); + if valid { let mut total_d = 0.0; for pair in waypoints.windows(2) { match pair { [src, dst] => { let (mut src, dst) = - (self.name_to_systems(&src), self.name_to_systems(&dst)); + (self.name_to_systems(&src)?, self.name_to_systems(&dst)?); src.sort_by_key(|&p| (p.mult * 10.0) as u8); let src = src.last().unwrap(); let dst = dst.last().unwrap(); total_d += src.distp2(dst); } - _ => panic!("Invalid routing parameters!"), + _ => return Err("Invalid routing parameters!".to_string()), } } if total_d < best_score { @@ -323,8 +312,6 @@ impl Router { break; } } - - println!("Done in {}!", format_duration(t_start.elapsed())); println!("Best permutation: {:?}", best_permutation_waypoints); self.name_multiroute(&best_permutation_waypoints, range, mode, factor) } @@ -335,10 +322,10 @@ impl Router { range: f32, mode: Mode, factor: f32, - ) -> Vec { + ) -> Result,String> { let mut coords = Vec::new(); for p_name in waypoints { - let mut p_l = self.name_to_systems(p_name); + let mut p_l = self.name_to_systems(p_name)?; p_l.sort_by_key(|&p| (p.mult * 10.0) as u8); let p = p_l.last().unwrap(); coords.push((p_name, p.pos)); @@ -351,15 +338,15 @@ impl Router { range: f32, mode: Mode, factor: f32, - ) -> Vec { + ) -> Result,String> { let mut route: Vec = Vec::new(); for pair in waypoints.windows(2) { match *pair { [src, dst] => { let block = match mode { - Mode::BFS => self.route_bfs(&src, &dst, range), - Mode::Greedy => self.route_greedy(&src, &dst, range), - Mode::AStar => self.route_astar(&src, &dst, range, factor), + Mode::BFS => self.route_bfs(&src, &dst, range)?, + Mode::Greedy => self.route_greedy(&src, &dst, range)?, + Mode::AStar => self.route_astar(&src, &dst, range, factor)?, }; if route.is_empty() { for sys in block.iter() { @@ -371,20 +358,19 @@ impl Router { } } } - _ => panic!("Invalid routing parameters!"), + _ => return Err("Invalid routing parameters!".to_string()), } } - route + Ok(route) } - fn name_to_systems(&self, name: &str) -> Vec<&System> { + fn name_to_systems(&self, name: &str) -> Result,String> { for sys in &self.tree { if sys.system == name { - return self.neighbours(&sys, 0.0).collect(); + return Ok(self.neighbours(&sys, 0.0).collect()); } } - eprintln!("System not found: \"{}\"", name); - std::process::exit(1); + Err(format!("System not found: \"{}\"", name)) } pub fn route_astar( @@ -393,29 +379,33 @@ impl Router { dst: &(&String, [f32; 3]), range: f32, factor: f32, - ) -> Vec { + ) -> Result,String> { if factor == 0.0 { return self.route_bfs(src, dst, range); } - println!("Running A-Star with greedy factor of {}", factor); let (src_name, src) = src; let (dst_name, dst) = dst; let start_sys = self.closest(src); let goal_sys = self.closest(dst); - { - let d = dist(src, dst); - println!("Plotting route from {} to {}...", src_name, dst_name); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", - range, - d, - d / range - ); - } + let d_total = dist(&start_sys.pos,&goal_sys.pos); + let mut d_rem=d_total; + + let mut state=SearchState { + mode:"A-Star".into(), + depth:0, + queue_size:0, + d_rem: d_total, + d_total: d_total, + prc_done: 0.0, + n_seen:0, + prc_seen: 0.0, + body: start_sys.body.clone(), + system: start_sys.system.clone() + }; let total = self.tree.size() as f32; + let t_start = Instant::now(); let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); let mut found = false; let mut maxd = 0; let mut queue: Vec<(usize, usize, &System)> = Vec::new(); @@ -425,11 +415,24 @@ impl Router { &start_sys, )); seen.insert(start_sys.id); - while !(queue.is_empty() || found) { while let Some((depth, _, sys)) = queue.pop() { - if depth > maxd { - maxd = depth; + if (depth+1) > maxd { + maxd = depth+1; + state.depth=depth; + state.queue_size=queue.len(); + state.prc_done=((d_total-d_rem)*100f32) / d_total; + state.d_rem=d_rem; + state.n_seen=seen.len(); + state.prc_seen=((seen.len()*100) as f32) / total; + state.body=sys.body.clone(); + state.system=sys.system.clone(); + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + return Err(format!("{:?}",e).to_string()); + } + }; print!( "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", format_duration(t_start.elapsed()), @@ -451,6 +454,10 @@ impl Router { .map(|nb| { prev.insert(nb.id, sys); let d_g = (nb.distp(goal_sys) / range) as usize; + let dist = dist(&nb.pos, &goal_sys.pos); + if dist < d_rem { + d_rem = dist; + } (depth + 1, d_g, nb) }), ); @@ -468,8 +475,7 @@ impl Router { println!(); if !found { - eprintln!("No route from {} to {} found!", src_name, dst_name); - return Vec::new(); + return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string()); } let mut v: Vec = Vec::new(); let mut curr_sys = goal_sys; @@ -483,7 +489,7 @@ impl Router { } } v.reverse(); - v + Ok(v) } pub fn route_greedy( @@ -491,26 +497,28 @@ impl Router { src: &(&String, [f32; 3]), dst: &(&String, [f32; 3]), range: f32, - ) -> Vec { - println!("Running Greedy-Search"); + ) -> Result,String> { let (src_name, src) = src; let (dst_name, dst) = dst; let start_sys = self.closest(src); let goal_sys = self.closest(dst); - { - let d = dist(src, dst); - println!("Plotting route from {} to {}...", src_name, dst_name); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Theoretical Jumps: {}", - range, - d, - d / range - ); - } + let d_total = dist(&start_sys.pos, &goal_sys.pos); + let mut d_rem=d_total; + let mut state=SearchState { + mode:"Greedy".into(), + depth:0, + queue_size:0, + d_rem: d_total, + d_total: d_total, + prc_done: 0.0, + n_seen:0, + prc_seen: 0.0, + body:start_sys.body.clone(), + system:start_sys.system.clone(), + }; let total = self.tree.size() as f32; let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); let mut found = false; let mut maxd = 0; let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); @@ -518,17 +526,22 @@ impl Router { seen.insert(start_sys.id); while !(queue.is_empty() || found) { while let Some((_, _, depth, sys)) = queue.pop() { - if depth > maxd { - maxd = depth; - print!( - "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", - format_duration(t_start.elapsed()), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total - ); - std::io::stdout().flush().unwrap(); + if (depth+1) > maxd { + state.depth=depth; + state.queue_size=queue.len(); + state.prc_done=((d_total-d_rem)*100f32) / d_total; + state.d_rem=d_rem; + state.n_seen=seen.len(); + state.prc_seen=((seen.len()*100) as f32) / total; + state.body=sys.body.clone(); + state.system=sys.system.clone(); + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + return Err(format!("{:?}",e).to_string()); + } + }; + maxd = depth+1; } if sys.id == goal_sys.id { found = true; @@ -540,6 +553,10 @@ impl Router { .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); + let dist = dist(&nb.pos, &goal_sys.pos); + if dist < d_rem { + d_rem = dist; + } (-nb.mult, nb.distp2(goal_sys), depth + 1, nb) }), ); @@ -547,11 +564,8 @@ impl Router { queue.reverse(); } } - println!(); - println!(); if !found { - eprintln!("No route from {} to {} found!", src_name, dst_name); - return Vec::new(); + return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string()); } let mut v: Vec = Vec::new(); let mut curr_sys = goal_sys; @@ -565,18 +579,17 @@ impl Router { } } v.reverse(); - v + Ok(v) } - pub fn precompute(&mut self, src: &str) { - let mut sys_l = self.name_to_systems(src); + pub fn precompute(&mut self, src: &str) -> Result<(),String> { + let mut sys_l = self.name_to_systems(src)?; sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8); let sys = sys_l.last().unwrap(); - println!("Precomputing routes starting at {} ...", sys.system); let total = self.tree.size() as f32; + let t_start = Instant::now(); let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); let mut depth = 0; let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); @@ -613,9 +626,7 @@ impl Router { self.range, if self.primary_only { "_primary" } else { "" } ); - println!("\nSaving to {}", ofn); let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); - // (range, path, route_tree) let data = ( self.primary_only, self.range, @@ -623,11 +634,13 @@ impl Router { String::from(self.path.to_str().unwrap()), self.route_tree.as_ref().unwrap(), ); - bincode::serialize_into(&mut out_fh, &data).unwrap(); + return match bincode::serialize_into(&mut out_fh, &data) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Error: {}",e).to_string()) + }; } - fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> FnvHashMap { - println!("Processing {}", path.to_str().unwrap()); + fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> Result,String> { let mut ret = FnvHashMap::default(); if let Some(c) = &mut self.cache.as_mut() { let mut missing = false; @@ -637,22 +650,22 @@ impl Router { ret.insert(*id, sys); } None => { - println!("ID {} not found in cache", id); missing = true; break; } } } if !missing { - return ret; + return Ok(ret); } } - let mut reader = csv::ReaderBuilder::new() - .from_path(path) - .unwrap_or_else(|e| { - println!("Error opening {}: {}", path.to_str().unwrap(), e); - std::process::exit(1); - }); + let mut reader = match csv::ReaderBuilder::new() + .from_path(path) { + Ok(reader) => reader, + Err(e) => { + return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e)); + } + }; reader .deserialize::() .map(|res| res.unwrap()) @@ -660,15 +673,12 @@ impl Router { .map(|sys| { ret.insert(sys.id, sys.build()); }) - .last() - .unwrap_or_else(|| { - eprintln!("Error: No systems matching {:?} found!", ids); - std::process::exit(1); - }); - ret + .count(); + Ok(ret) } - fn get_system_by_name(path: &PathBuf, name: &str) -> System { + fn get_system_by_name(path: &PathBuf, name: &str) -> Result { + // TODO: Fuzzy search (https://github.com/andylokandy/simsearch-rs) let mut reader = csv::ReaderBuilder::new() .from_path(path) .unwrap_or_else(|e| { @@ -678,20 +688,18 @@ impl Router { let sys = reader .deserialize::() .map(|res| res.unwrap()) - .find(|sys| sys.system == name) - .unwrap_or_else(|| { - eprintln!("Error: System '{}' not found!", name); - std::process::exit(1); - }); - sys.build() + .find(|sys| sys.system == name); + match sys { + Some(system) => Ok(system.build()), + None => Err(format!("System {} not found!",name).to_string()) + } } - pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Vec { + pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Result,String> { let prev = self.route_tree.as_ref().unwrap(); - let dst = Self::get_system_by_name(&systems_path, dst); + let dst = Self::get_system_by_name(&systems_path, dst)?; if !prev.contains_key(&dst.id) { - eprintln!("System-ID {} not found", dst.id); - std::process::exit(1); + return Err(format!("System-ID {} not found", dst.id).to_string()); }; let mut v_ids: Vec = Vec::new(); let mut v: Vec = Vec::new(); @@ -706,12 +714,17 @@ impl Router { } } v_ids.reverse(); - let id_map = self.get_systems_by_ids(&systems_path, &v_ids); + let id_map = self.get_systems_by_ids(&systems_path, &v_ids)?; for sys_id in v_ids { - let sys = id_map.get(&sys_id).unwrap(); + let sys = match id_map.get(&sys_id) { + Some(sys) => sys, + None => { + return Err(format!("System-ID {} not found!",sys_id)); + } + }; v.push(sys.clone()) } - v + Ok(v) } pub fn route_bfs( @@ -719,13 +732,25 @@ impl Router { src: &(&String, [f32; 3]), dst: &(&String, [f32; 3]), range: f32, - ) -> Vec { + ) -> Result,String> { println!("Running BFS"); let (src_name, src) = src; let (dst_name, dst) = dst; let start_sys = self.closest(src); let goal_sys = self.closest(dst); - let d_total = dist(src, dst); + let d_total = dist(&start_sys.pos, &goal_sys.pos); + let mut state=SearchState { + mode:"BFS".into(), + depth:0, + queue_size:0, + d_rem: d_total, + d_total: d_total, + prc_done: 0.0, + n_seen:0, + prc_seen: 0.0, + system: start_sys.system.clone(), + body: start_sys.body.clone() + }; { println!("Plotting route from {} to {}...", src_name, dst_name); println!( @@ -738,26 +763,31 @@ impl Router { let total = self.tree.size() as f32; let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); - let t_start = Instant::now(); let mut depth = 0; let mut found = false; let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); - let mut d_rem = dist2(&start_sys.pos, &goal_sys.pos); + let mut d_rem = dist(&start_sys.pos, &goal_sys.pos); queue.push_front((0, &start_sys)); seen.insert(start_sys.id); while !(queue.is_empty() || found) { - print!( - "[{}] {:.02}% | Depth: {}, Queue: {}, Seen: {} ({:.02}%), Remaining Distance: {} \r", - format_duration(t_start.elapsed()), - (((d_total-d_rem.sqrt())*100f32)/d_total), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total, - d_rem.sqrt() - ); - std::io::stdout().flush().unwrap(); + state.depth=depth; + state.queue_size=queue.len(); + state.prc_done=((d_total-d_rem)*100f32) / d_total; + state.d_rem=d_rem; + state.n_seen=seen.len(); + state.prc_seen=((seen.len()*100) as f32) / total; + { + let s=queue.get(0).unwrap().1; + state.system=s.system.clone(); + state.body=s.body.clone(); + } + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + return Err(format!("{:?}",e).to_string()); + } + }; while let Some((d, sys)) = queue.pop_front() { if sys.id == goal_sys.id { found = true; @@ -769,7 +799,7 @@ impl Router { .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); - let dist = dist2(&nb.pos, &goal_sys.pos); + let dist = dist(&nb.pos, &goal_sys.pos); if dist < d_rem { d_rem = dist; } @@ -783,8 +813,7 @@ impl Router { println!(); println!(); if !found { - eprintln!("No route from {} to {} found!", src_name, dst_name); - return Vec::new(); + return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string()); } let mut v: Vec = Vec::new(); let mut curr_sys = goal_sys; @@ -798,82 +827,57 @@ impl Router { } } v.reverse(); - v + Ok(v) } } -pub fn route(opts: RouteOpts) -> std::io::Result<()> { +pub fn route(opts: RouteOpts) -> Result>,String> { + if opts.systems.is_empty() { - if opts.precomp_file.is_some() { - eprintln!("Error: Please specify exatly one system"); + return if opts.precomp_file.is_some() { + Err("Error: Please specify exatly one system".to_string()) } else if opts.precompute { - eprintln!("Error: Please specify at least one system"); + Err("Error: Please specify at least one system".to_string()) } else { - eprintln!("Error: Please specify at least two systems"); + Err("Error: Please specify at least two systems".to_string()) } - std::process::exit(1); } let mut path = opts.file_path; let mut router: Router = if opts.precomp_file.is_some() { - let ret = Router::from_file(&opts.precomp_file.clone().unwrap()); - path = ret.0; - ret.1 + let (path_,ret) = Router::from_file(&opts.precomp_file.clone().unwrap(),Box::new(opts.callback))?; + path=path_; + ret + } else if opts.range.is_some() { + Router::new(&path, opts.range.unwrap(), opts.primary, Box::new(opts.callback))? } else { - Router::new(&path, opts.range.unwrap(), opts.primary, Box::new(|state| { - println!("State: {:?}",state); - })) + return Err("Please specify a jump range!".to_string()); }; if opts.precompute { for sys in opts.systems { router.route_tree = None; - router.precompute(&sys); + router.precompute(&sys)?; } - std::process::exit(0); + return Ok(None) } - let t_route = Instant::now(); let route = if router.route_tree.is_some() { - router.route_to(opts.systems.first().unwrap(), &path) - } else if opts.permute || opts.full_permute { + router.route_to(opts.systems.first().unwrap(), &path)? + } else if opts.permute { router.best_name_multiroute( &opts.systems, opts.range.unwrap(), - opts.full_permute, + (opts.keep_first,opts.keep_last), opts.mode, opts.factor.unwrap_or(1.0), - ) + )? } else { router.name_multiroute( &opts.systems, opts.range.unwrap(), opts.mode, opts.factor.unwrap_or(1.0), - ) + )? }; - println!("Route computed in {}\n", format_duration(t_route.elapsed())); if route.is_empty() { - eprintln!("No route found!"); - return Ok(()); + return Err("No route found!".to_string()) } - let mut total: f32 = 0.0; - for (sys1, sys2) in route.iter().zip(route.iter().skip(1)) { - let dist = sys1.distp(sys2); - total += dist; - println!( - "{} ({}) [{}] ({},{},{}) [{} Ls]: {:.2} Ly", - sys1.body, - sys1.system, - sys1.star_type, - sys1.pos[0], - sys1.pos[1], - sys1.pos[2], - sys1.distance, - dist - ); - } - let sys = route.iter().last().unwrap(); - println!( - "{} ({}) [{}] ({},{},{}) [{} Ls]: {:.2} Ly", - sys.body, sys.system, sys.star_type, sys.pos[0], sys.pos[1], sys.pos[2], sys.distance, 0.0 - ); - println!("Total: {:.2} Ly ({} Jumps)", total, route.len()); - Ok(()) + return Ok(Some(route)); } diff --git a/setup.py b/setup.py index f6bccfe..6211685 100644 --- a/setup.py +++ b/setup.py @@ -18,6 +18,7 @@ setup( ], packages=["ed_lrr_gui"], entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, - install_requires=["PyQt5", "appdirs", "PyYAML"], + install_requires=["PyQt5", "appdirs", "PyYAML", "requests", "python-dateutil"], + include_package_data=True, zip_safe=False, ) diff --git a/test_gui.bat b/test_gui.bat new file mode 100644 index 0000000..74e1f6e --- /dev/null +++ b/test_gui.bat @@ -0,0 +1 @@ +python build_gui.py && ed_lrr_gui \ No newline at end of file From c290d5eb1223e2db92205c31d28c12614ec2d91a Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 00:05:44 +0200 Subject: [PATCH 19/72] feat(GUI): Implement route plotting and fuzzy search Implement route plotting in GUI Use batch fuzzy search to find systems search all systems at once after adding added some error checking --- .chglog/CHANGELOG.tpl.md | 40 +++ .chglog/config.yml | 13 + .gitignore | 15 +- MANIFEST.in | 3 +- build.bat | 11 + ed_lrr_gui/__init__.py | 2 + ed_lrr_gui/__main__.py | 313 +++++++++++++++++++---- ed_lrr_gui/gui/ed_lrr.py | 92 +++++++ ed_lrr_gui/gui/ed_lrr.ui | 105 ++++++++ ed_lrr_gui/preprocess.py | 15 +- ed_lrr_gui/router.py | 12 - rust/Cargo.lock | 88 ++++++- rust/Cargo.toml | 5 +- rust/src/common.rs | 14 + rust/src/lib.rs | 188 +++++++++----- rust/src/route.rs | 537 ++++++++++++++++++++++----------------- setup.py | 9 +- test.bat | 4 + 18 files changed, 1075 insertions(+), 391 deletions(-) create mode 100644 .chglog/CHANGELOG.tpl.md create mode 100644 .chglog/config.yml create mode 100644 build.bat create mode 100644 test.bat diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100644 index 0000000..1f731b6 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,40 @@ +{{ if .Versions -}} + +## [Unreleased] + +{{ if .Unreleased.CommitGroups -}} +{{ range .Unreleased.CommitGroups -}} +{{ range .Commits -}} +- {{ .Header }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{ range .Versions }} + +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} +{{ range .CommitGroups -}} +{{ range .Commits -}} +- {{ .Header }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{- if .Versions }} +[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD +{{ range .Versions -}} +{{ if .Tag.Previous -}} +[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} +{{ end -}} +{{ end -}} +{{ end -}} \ No newline at end of file diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100644 index 0000000..65dde53 --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,13 @@ +style: gitlab +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://gitlab.com/Earthnuker/ed_lrr +options: + header: + pattern: "^(.*)$" + pattern_maps: + - Subject + notes: + keywords: + - BREAKING CHANGE \ No newline at end of file diff --git a/.gitignore b/.gitignore index f8b9d2b..cfec1c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,14 @@ -/target -/dist -/build +rust/target **/*.rs.bk *.tmp *.idx .vscode/** +*.csv +*.router +plot.py +*.tmp +*.idx *.pyd -build.bat -test.bat __pycache__ -DL *.egg-info -pip-wheel-metadata -rust/target/* \ No newline at end of file +build diff --git a/MANIFEST.in b/MANIFEST.in index 900cc3b..fe1501c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ -include rust/Cargo.toml +include rust/Cargo.toml +include rust/.cargo/config recursive-include rust/src * \ No newline at end of file diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..9487f53 --- /dev/null +++ b/build.bat @@ -0,0 +1,11 @@ +rm -rf build dist *.egg-info exe +python build_gui.py +pip uninstall -y ed_lrr_gui +pip install -I . setuptools_rust +python setup.py build +python setup.py bdist_wheel +python setup.py sdist +mkdir exe +cd exe +pyinstaller --noupx --noconsole --key="ED_LRR_GUI" --name ED_LRR_GUI ..\ed_lrr_gui\__main__.py +cd .. \ No newline at end of file diff --git a/ed_lrr_gui/__init__.py b/ed_lrr_gui/__init__.py index 2d1a9d6..9bce23f 100644 --- a/ed_lrr_gui/__init__.py +++ b/ed_lrr_gui/__init__.py @@ -1,2 +1,4 @@ from _ed_lrr import * from . import gui +from .router import Router +from .preprocess import Preprocessor diff --git a/ed_lrr_gui/__main__.py b/ed_lrr_gui/__main__.py index 71c6b13..c03221f 100644 --- a/ed_lrr_gui/__main__.py +++ b/ed_lrr_gui/__main__.py @@ -2,21 +2,28 @@ import sys import os import requests as RQ from datetime import datetime, timedelta -from PyQt5.QtCore import QThread, pyqtSignal, Qt +from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt, QObject from PyQt5.QtWidgets import ( QMainWindow, QApplication, QFileDialog, QProgressDialog, QTreeWidgetItem, + QAction, + QMessageBox, ) from urllib.request import Request, urlopen import gzip +import pathlib from PyQt5.QtGui import QPalette, QColor import ed_lrr_gui import ed_lrr_gui.config as cfg from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR +from ed_lrr_gui import Router, Preprocessor import multiprocessing as MP +import queue +import csv +import _ed_lrr def sizeof_fmt(num, suffix="B"): @@ -37,6 +44,85 @@ class ProgressDialog(QProgressDialog): self.setWindowModality(Qt.WindowModal) +class Job(QObject): + progress = pyqtSignal("PyQt_PyObject") + + def __init__(self, app, cls, *args, build_progress=None, **kwargs): + super().__init__() + self.job = cls(*args, **kwargs) + self.timer = QTimer(app) + self.app = app + self.timer.timeout.connect(self.interval) + self.timer.start(100) + self.last_val = None + self.build_progress = build_progress + self.progress_dialog = None + self.state = {} + + def start(self): + """ + if self.diag_prog is None: + self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) + if self.dl_thread: + self.diag_prog.canceled.connect(self.dl_canceled) + self.diag_prog.show() + t_elapsed = datetime.today() - self.dl_started + rate = args["done"] / t_elapsed.total_seconds() + remaining = (args["size"] - args["done"]) / rate + rate = round(rate, 2) + # print(rate, remaining) + try: + t_rem = timedelta(seconds=remaining) + except OverflowError: + t_rem = "-" + msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( + filename, + sizeof_fmt(args["done"]), + sizeof_fmt(args["size"]), + sizeof_fmt(rate), + t_round(t_elapsed), + t_round(t_rem), + ) + self.diag_prog.setLabelText(msg) + self.diag_prog.setWindowTitle("Downloading EDSM Dumps") + self.diag_prog.setValue((args["done"] * 1000) // args["size"]) + """ + self.started = datetime.today() + if self.build_progress: + self.progress_dialog = ProgressDialog("", "Cancel", 0, 1000, self.app) + self.progress_dialog.canceled.connect(self.cancel) + self.progress_dialog.show() + self.progress.connect(self.__build_progress) + else: + self.progress.connect( + lambda *args, **kwargs: print("PROGRESS:", *args, **kwargs) + ) + return self.job.start() + + def __build_progress(self, *args, **kwargs): + kwargs["self"] = self + return self.build_progress(*args, **kwargs) + + def cancel(self): + self.job.terminate() + self.job = None + + def done(self): + return (self.job.is_alive() == False) and (self.job.queue.empty()) + + def interval(self): + while True: + try: + res = self.job.queue.get(True, 0.1) + except queue.Empty: + return + if res == self.last_val: + continue + self.state.update(res) + self.progress.emit(self.state) + self.last_val = res + + class DownloadThread(QThread): progress = pyqtSignal("PyQt_PyObject") @@ -79,45 +165,65 @@ class App(QApplication): def __init__(self): super().__init__(sys.argv) self.setStyle("Fusion") - self.set_pallete() + self.setup_styles() - def set_pallete(self): - colors = { - "Window": QColor(53, 53, 53), - "WindowText": Qt.white, - "Base": QColor(15, 15, 15), - "AlternateBase": QColor(53, 53, 53), - "ToolTipBase": Qt.white, - "ToolTipText": Qt.white, - "Text": Qt.white, - "Button": QColor(53, 53, 53), - "ButtonText": Qt.white, - "BrightText": Qt.red, - "Highlight": QColor(255, 128, 0), - "HighlightedText": Qt.black, + def set_style(self, style): + print("LOAD:", style) + self.setPalette(self.styles[style]) + + def setup_styles(self): + self.styles = {} + styles = { + "Dark": { + "Window": QColor(53, 53, 53), + "WindowText": Qt.white, + "Base": QColor(15, 15, 15), + "AlternateBase": QColor(53, 53, 53), + "ToolTipBase": Qt.white, + "ToolTipText": Qt.white, + "Text": Qt.white, + "Button": QColor(53, 53, 53), + "ButtonText": Qt.white, + "BrightText": Qt.red, + "Highlight": QColor(255, 128, 0), + "HighlightedText": Qt.black, + } } - palette = QPalette() - for entry, color in colors.items(): - palette.setColor(getattr(QPalette, entry), color) - if color == Qt.darkGray: - palette.setColor( - QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) - ) - else: - palette.setColor( - QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray - ) - self.setPalette(palette) + for style, colors in styles.items(): + palette = QPalette() + for entry, color in colors.items(): + palette.setColor(getattr(QPalette, entry), color) + if color == Qt.darkGray: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) + ) + else: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray + ) + self.styles[style] = palette + self.styles["Light"] = self.style().standardPalette() class ED_LRR(Ui_ED_LRR): dl_thread = None diag_prog = None dl_started = None + system_found = pyqtSignal("PyQt_PyObject") def __init__(self): super().__init__() self.config = cfg.load() + self.jobs = {} + + def start_job(self, cls, *args, **kwargs): + print("START JOB:", cls, args, kwargs) + name = cls.__name__ + if name in self.jobs and self.jobs[name].done(): + del self.jobs[name] + if not name in self.jobs: + self.jobs[name] = Job(self.app, cls, *args, **kwargs) + self.jobs[name].start() def get_open_file(self, filetypes, callback=None): fileName, _ = QFileDialog.getOpenFileName( @@ -148,6 +254,8 @@ class ED_LRR(Ui_ED_LRR): self.config.history_out_path.append(path) self.inp_sys_lst.addItem(path) self.inp_out_pp.addItem(path) + self.inp_sys_lst.setCurrentText(path) + self.inp_out_pp.setCurrentText(path) def set_bodies_file(self, path): if path not in self.config.history_bodies_path: @@ -170,7 +278,7 @@ class ED_LRR(Ui_ED_LRR): def set_comp_mode(self, _): if self.rd_comp.isChecked(): comp_mode = "Compute Route" - self.btn_add.setText("Search+Add") + self.btn_add.setText("Add") if self.rd_precomp.isChecked(): comp_mode = "Precompute Graph" self.btn_add.setText("Select") @@ -178,7 +286,7 @@ class ED_LRR(Ui_ED_LRR): self.lst_sys.setEnabled(self.rd_comp.isChecked()) self.btn_rm.setEnabled(self.rd_comp.isChecked()) self.cmb_mode.setEnabled(self.rd_comp.isChecked()) - self.btn_permute.setEnabled(self.rd_comp.isChecked()) + self.chk_permute.setEnabled(self.rd_comp.isChecked()) self.lbl_keep.setEnabled(self.rd_comp.isChecked()) self.lbl_mode.setEnabled(self.rd_comp.isChecked()) self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked()) @@ -190,11 +298,17 @@ class ED_LRR(Ui_ED_LRR): mode = self.cmb_mode.currentText() self.lbl_greedyness.setEnabled(mode == "A*-Search") self.sld_greedyness.setEnabled(mode == "A*-Search") - self.log("ROUTE_MODE", mode) def set_greedyness(self, value): self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100)) + @property + def systems(self): + ret = [] + for n in range(self.lst_sys.topLevelItemCount()): + ret.append(self.sys_to_dict(n)) + return ret + def sys_to_dict(self, n): header = [ self.lst_sys.headerItem().data(c, 0) @@ -204,34 +318,108 @@ class ED_LRR(Ui_ED_LRR): self.lst_sys.topLevelItem(n).data(c, 0) for c in range(self.lst_sys.topLevelItem(n).columnCount()) ] - return dict(zip(header, system)) + ret = dict(zip(header, system)) + ret["id"] = getattr(self.lst_sys.topLevelItem(n), "__id__", None) + ret.pop(None, None) + return ret + + def error(self, msg): + QMessageBox.critical(self.main_window, "ERROR!", msg) + + def get_sys_list(self): + if not self.inp_sys_lst.currentText(): + self.error("System list is required!") + return + path = pathlib.Path(self.inp_sys_lst.currentText()) + if not path.exists(): + self.error("System list does not exist, run download and preprocess first!") + return + return path def run(self): - settings = {} - settings["permute"] = ( - self.chk_permute_keep_first.checkState(), - self.chk_permute_keep_last.checkState(), + if not all(s["Type"] for s in self.systems): + self.error('Not all systens have been resolved, please click "Search All"') + return + print(self.systems) + systems = [str(s["id"]) for s in self.systems] + jump_range = self.sb_range.value() + mode = self.cmb_mode.currentText() + primary = self.chk_primary.isChecked() + keep_first = self.chk_permute_keep_first.isChecked() + keep_last = self.chk_permute_keep_last.isChecked() + permute = self.chk_permute.isChecked() + greedyness = ( + self.sld_greedyness.value() / 100 + if self.sld_greedyness.isEnabled() + else None ) - settings["range"] = self.sb_range.value() - settings["systems"] = [ - self.sys_to_dict(i) for i in range(self.lst_sys.topLevelItemCount()) - ] - print(settings) - progress = ProgressDialog( - "(Not actually computing)", "Cancel", 0, 0, self.main_window + path = self.get_sys_list() + if path is None: + return + precomp = path.with_suffix(".idx") + path = str(path) + if not precomp.exists(): + precomp = None + else: + precomp = str(precomp) + mode = { + "Breadth-First Search": "bfs", + "A*-Search": "astar", + "Greedy-Search": "greedy", + }[mode] + print( + systems, + jump_range, + mode, + primary, + permute, + (keep_first, keep_last), + greedyness, + path, + precomp, ) - progress.setWindowTitle("Computing Route") - progress.setFixedSize(400, 100) - progress.setRange(0, 0) - progress.show() + self.start_job( + Router, + systems, + jump_range, + 0.1, + mode, + primary, + permute, + keep_first, + keep_last, + greedyness, + precomp, + path, + ) + + def find_sys_by_names(self, names): + t_s = datetime.today() + if not self.get_sys_list(): + return None + ret = _ed_lrr.find_sys(names, self.inp_sys_lst.currentText()) + print("Took:", datetime.today() - t_s) + return ret + + def resolve_systems(self): + names = [] + for n in range(self.lst_sys.topLevelItemCount()): + names.append(self.sys_to_dict(n)["Name"]) + systems = self.find_sys_by_names(names) + if systems is None: + return + for i, name in enumerate(names): + _, system = systems[name] + self.lst_sys.topLevelItem(i).setData(0, 0, system["system"]) + self.lst_sys.topLevelItem(i).setData(1, 0, system["star_type"]) + self.lst_sys.topLevelItem(i).__id__ = system["id"] + # diff, item = self.find_sys_by_name(name) + # print("Found", (diff, item)) def add_system(self): - n = self.lst_sys.topLevelItemCount() + 1 name = self.inp_sys.text() - item = QTreeWidgetItem( - self.lst_sys, [str(n) + ". Name: " + name, "Type: " + name[::-1]] - ) - item.sys_id = "SYS_ID_HERE" + item = QTreeWidgetItem(self.lst_sys, [name, None]) + item.resolved = False item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) def remove_system(self): @@ -253,7 +441,7 @@ class ED_LRR(Ui_ED_LRR): self.diag_prog = None self.dl_started = None - def handle_progress(self, args): + def handle_dl_progress(self, args): filename = os.path.split(args["outfile"])[-1] if self.diag_prog is None: self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) @@ -291,10 +479,15 @@ class ED_LRR(Ui_ED_LRR): self.inp_bodies_dl.currentText(), self.inp_bodies_dest_dl.currentText(), ) - self.dl_thread.progress.connect(self.handle_progress) + self.dl_thread.progress.connect(self.handle_dl_progress) self.dl_thread.start() print(".") + def update_permute_chk(self, state): + self.chk_permute_keep_first.setEnabled(state) + self.chk_permute_keep_last.setEnabled(state) + self.lbl_keep.setEnabled(state) + def setup_signals(self): self.btn_download.clicked.connect(self.run_download) self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json") @@ -307,6 +500,8 @@ class ED_LRR(Ui_ED_LRR): self.btn_go.clicked.connect(self.run) self.btn_add.clicked.connect(self.add_system) self.btn_rm.clicked.connect(self.remove_system) + self.chk_permute.stateChanged.connect(self.update_permute_chk) + self.btn_search.clicked.connect(self.resolve_systems) self.btn_out_browse_pp.clicked.connect( lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) ) @@ -331,6 +526,14 @@ class ED_LRR(Ui_ED_LRR): cfg.write(self.config) print("BYEEEEEE!") + def setup_styles(self, win, app): + for name in app.styles: + action = QAction(app) + action.setObjectName("action_load_style_" + name) + action.setText(name) + action.triggered.connect(lambda _, name=name: app.set_style(name)) + self.menuStyle.addAction(action) + def setupUi(self, MainWindow, app): super().setupUi(MainWindow) self.update_dropdowns() @@ -339,6 +542,8 @@ class ED_LRR(Ui_ED_LRR): self.setup_signals() self.lst_sys.setHeaderLabels(["Name", "Type"]) self.set_route_mode() + self.update_permute_chk(self.chk_permute.isChecked()) + self.setup_styles(MainWindow, app) def main(): diff --git a/ed_lrr_gui/gui/ed_lrr.py b/ed_lrr_gui/gui/ed_lrr.py index 76ba5f8..721546f 100644 --- a/ed_lrr_gui/gui/ed_lrr.py +++ b/ed_lrr_gui/gui/ed_lrr.py @@ -26,6 +26,14 @@ class Ui_ED_LRR(object): ED_LRR.setDocumentMode(False) ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded) self.centralwidget = QtWidgets.QWidget(ED_LRR) +<<<<<<< Updated upstream +======= + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) + self.centralwidget.setSizePolicy(sizePolicy) +>>>>>>> Stashed changes self.centralwidget.setObjectName("centralwidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName("verticalLayout") @@ -214,9 +222,12 @@ class Ui_ED_LRR(object): self.rd_precomp.setObjectName("rd_precomp") self.gr_mode.addWidget(self.rd_precomp, 0, 2, 1, 1) self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode) +<<<<<<< Updated upstream self.btn_permute = QtWidgets.QPushButton(self.tab_route) self.btn_permute.setObjectName("btn_permute") self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute) +======= +>>>>>>> Stashed changes self.lst_sys = QtWidgets.QTreeWidget(self.tab_route) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -231,6 +242,7 @@ class Ui_ED_LRR(object): self.lst_sys.setAlternatingRowColors(True) self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) +<<<<<<< Updated upstream self.lst_sys.setHeaderHidden(True) self.lst_sys.setObjectName("lst_sys") self.lst_sys.headerItem().setText(0, "1") @@ -241,6 +253,19 @@ class Ui_ED_LRR(object): self.lbl_range = QtWidgets.QLabel(self.tab_route) self.lbl_range.setObjectName("lbl_range") self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.lbl_range) +======= + self.lst_sys.setHeaderHidden(False) + self.lst_sys.setObjectName("lst_sys") + self.lst_sys.headerItem().setText(0, "Name") + self.lst_sys.header().setVisible(False) + self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.SpanningRole, self.lst_sys) + self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route) + self.sb_range.setObjectName("sb_range") + self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.sb_range) + self.lbl_range = QtWidgets.QLabel(self.tab_route) + self.lbl_range.setObjectName("lbl_range") + self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.lbl_range) +>>>>>>> Stashed changes self.gr_opts = QtWidgets.QGridLayout() self.gr_opts.setObjectName("gr_opts") self.cmb_mode = QtWidgets.QComboBox(self.tab_route) @@ -268,16 +293,28 @@ class Ui_ED_LRR(object): self.lbl_mode = QtWidgets.QLabel(self.tab_route) self.lbl_mode.setObjectName("lbl_mode") self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1) +<<<<<<< Updated upstream self.formLayout_2.setLayout(9, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) self.btn_go = QtWidgets.QPushButton(self.tab_route) self.btn_go.setFlat(False) self.btn_go.setObjectName("btn_go") self.formLayout_2.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.btn_go) +======= + self.formLayout_2.setLayout(10, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) + self.btn_go = QtWidgets.QPushButton(self.tab_route) + self.btn_go.setFlat(False) + self.btn_go.setObjectName("btn_go") + self.formLayout_2.setWidget(11, QtWidgets.QFormLayout.LabelRole, self.btn_go) +>>>>>>> Stashed changes self.gridLayout_4 = QtWidgets.QGridLayout() self.gridLayout_4.setObjectName("gridLayout_4") self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route) self.chk_permute_keep_last.setObjectName("chk_permute_keep_last") +<<<<<<< Updated upstream self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 2, 1, 1) +======= + self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 3, 1, 1) +>>>>>>> Stashed changes self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -286,7 +323,11 @@ class Ui_ED_LRR(object): self.chk_permute_keep_first.setSizePolicy(sizePolicy) self.chk_permute_keep_first.setTristate(False) self.chk_permute_keep_first.setObjectName("chk_permute_keep_first") +<<<<<<< Updated upstream self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 1, 1, 1) +======= + self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 2, 1, 1) +>>>>>>> Stashed changes self.lbl_keep = QtWidgets.QLabel(self.tab_route) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -294,8 +335,19 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth()) self.lbl_keep.setSizePolicy(sizePolicy) self.lbl_keep.setObjectName("lbl_keep") +<<<<<<< Updated upstream self.gridLayout_4.addWidget(self.lbl_keep, 0, 0, 1, 1) self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4) +======= + self.gridLayout_4.addWidget(self.lbl_keep, 0, 1, 1, 1) + self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4) + self.chk_permute = QtWidgets.QCheckBox(self.tab_route) + self.chk_permute.setObjectName("chk_permute") + self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.chk_permute) + self.btn_search = QtWidgets.QPushButton(self.tab_route) + self.btn_search.setObjectName("btn_search") + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btn_search) +>>>>>>> Stashed changes self.tabs.addTab(self.tab_route, "") self.tab_log = QtWidgets.QWidget() self.tab_log.setObjectName("tab_log") @@ -317,14 +369,32 @@ class Ui_ED_LRR(object): self.menu.setObjectName("menu") self.menu_file = QtWidgets.QMenu(self.menu) self.menu_file.setObjectName("menu_file") +<<<<<<< Updated upstream +======= + self.menuWindow = QtWidgets.QMenu(self.menu) + self.menuWindow.setObjectName("menuWindow") + self.menuStyle = QtWidgets.QMenu(self.menuWindow) + self.menuStyle.setObjectName("menuStyle") +>>>>>>> Stashed changes ED_LRR.setMenuBar(self.menu) self.bar_status = QtWidgets.QStatusBar(ED_LRR) self.bar_status.setObjectName("bar_status") ED_LRR.setStatusBar(self.bar_status) self.menu_act_quit = QtWidgets.QAction(ED_LRR) self.menu_act_quit.setObjectName("menu_act_quit") +<<<<<<< Updated upstream self.menu_file.addAction(self.menu_act_quit) self.menu.addAction(self.menu_file.menuAction()) +======= + self.actionA = QtWidgets.QAction(ED_LRR) + self.actionA.setObjectName("actionA") + self.actionB = QtWidgets.QAction(ED_LRR) + self.actionB.setObjectName("actionB") + self.menu_file.addAction(self.menu_act_quit) + self.menuWindow.addAction(self.menuStyle.menuAction()) + self.menu.addAction(self.menu_file.menuAction()) + self.menu.addAction(self.menuWindow.menuAction()) +>>>>>>> Stashed changes self.retranslateUi(ED_LRR) self.tabs.setCurrentIndex(2) @@ -358,12 +428,20 @@ class Ui_ED_LRR(object): self.tabs.setTabText(self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess")) self.lbl_sys_lst.setText(_translate("ED_LRR", "System List")) self.btn_sys_lst_browse.setText(_translate("ED_LRR", "...")) +<<<<<<< Updated upstream self.btn_add.setText(_translate("ED_LRR", "Search+Add")) +======= + self.btn_add.setText(_translate("ED_LRR", "Add")) +>>>>>>> Stashed changes self.inp_sys.setPlaceholderText(_translate("ED_LRR", "System Name")) self.btn_rm.setText(_translate("ED_LRR", "Remove")) self.rd_comp.setText(_translate("ED_LRR", "Compute Route")) self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph")) +<<<<<<< Updated upstream self.btn_permute.setText(_translate("ED_LRR", "Permute")) +======= + self.lst_sys.headerItem().setText(1, _translate("ED_LRR", "Type")) +>>>>>>> Stashed changes self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)")) self.cmb_mode.setCurrentText(_translate("ED_LRR", "Breadth-First Search")) self.cmb_mode.setItemText(0, _translate("ED_LRR", "Breadth-First Search")) @@ -376,8 +454,22 @@ class Ui_ED_LRR(object): self.chk_permute_keep_last.setText(_translate("ED_LRR", "Last")) self.chk_permute_keep_first.setText(_translate("ED_LRR", "First")) self.lbl_keep.setText(_translate("ED_LRR", "Keep Endpoints:")) +<<<<<<< Updated upstream self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")) self.menu_file.setTitle(_translate("ED_LRR", "File")) self.menu_act_quit.setText(_translate("ED_LRR", "Quit")) self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q")) +======= + self.chk_permute.setText(_translate("ED_LRR", "Permute")) + self.btn_search.setText(_translate("ED_LRR", "Search All")) + self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) + self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")) + self.menu_file.setTitle(_translate("ED_LRR", "File")) + self.menuWindow.setTitle(_translate("ED_LRR", "Window")) + self.menuStyle.setTitle(_translate("ED_LRR", "Style")) + self.menu_act_quit.setText(_translate("ED_LRR", "Quit")) + self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q")) + self.actionA.setText(_translate("ED_LRR", "A")) + self.actionB.setText(_translate("ED_LRR", "B")) +>>>>>>> Stashed changes diff --git a/ed_lrr_gui/gui/ed_lrr.ui b/ed_lrr_gui/gui/ed_lrr.ui index 7034a30..4685221 100644 --- a/ed_lrr_gui/gui/ed_lrr.ui +++ b/ed_lrr_gui/gui/ed_lrr.ui @@ -44,6 +44,15 @@ QTabWidget::Rounded +<<<<<<< Updated upstream +======= + + + 0 + 0 + + +>>>>>>> Stashed changes @@ -363,7 +372,11 @@ +<<<<<<< Updated upstream Search+Add +======= + Add +>>>>>>> Stashed changes @@ -402,6 +415,7 @@ +<<<<<<< Updated upstream @@ -409,6 +423,8 @@ +======= +>>>>>>> Stashed changes @@ -445,26 +461,53 @@ QAbstractItemView::SelectRows +<<<<<<< Updated upstream true 1 +======= + false + + + false + + + + Name + + + + + Type +>>>>>>> Stashed changes +<<<<<<< Updated upstream +======= + + + + +>>>>>>> Stashed changes Jump Range (Ly) +<<<<<<< Updated upstream +======= + +>>>>>>> Stashed changes @@ -536,7 +579,11 @@ +<<<<<<< Updated upstream +======= + +>>>>>>> Stashed changes GO! @@ -548,14 +595,22 @@ +<<<<<<< Updated upstream +======= + +>>>>>>> Stashed changes Last +<<<<<<< Updated upstream +======= + +>>>>>>> Stashed changes @@ -571,7 +626,11 @@ +<<<<<<< Updated upstream +======= + +>>>>>>> Stashed changes @@ -586,6 +645,23 @@ +<<<<<<< Updated upstream +======= + + + + Permute + + + + + + + Search All + + + +>>>>>>> Stashed changes @@ -633,7 +709,23 @@ +<<<<<<< Updated upstream +======= + + + Window + + + + Style + + + + + + +>>>>>>> Stashed changes @@ -644,6 +736,19 @@ Ctrl+Q +<<<<<<< Updated upstream +======= + + + A + + + + + B + + +>>>>>>> Stashed changes rd_comp diff --git a/ed_lrr_gui/preprocess.py b/ed_lrr_gui/preprocess.py index b7c8675..f59b2b4 100644 --- a/ed_lrr_gui/preprocess.py +++ b/ed_lrr_gui/preprocess.py @@ -14,24 +14,13 @@ class Preprocessor(Process): self.args = args self.kwargs = kwargs self.kwargs["callback"] = self.callback - self.start() - - def __iter__(self): - while self.is_alive(): - try: - self.state.update(self.queue.get(True, 0.5)) - yield self.state - except queue.Empty: - pass - while not self.queue.empty(): - self.state.update(self.queue.get(True, 0.5)) - yield self.state def callback(self, state): self.queue.put({"status": state}) def run(self): - _ed_lrr.preprocess(*self.args, **self.kwargs) + res = _ed_lrr.preprocess(*self.args, **self.kwargs) + self.queue.put({"result": res}) if __name__ == "__main__": diff --git a/ed_lrr_gui/router.py b/ed_lrr_gui/router.py index 773f939..4e5bbfe 100644 --- a/ed_lrr_gui/router.py +++ b/ed_lrr_gui/router.py @@ -14,18 +14,6 @@ class Router(Process): self.args = args self.kwargs = kwargs self.kwargs["callback"] = self.callback - self.start() - - def __iter__(self): - while self.is_alive(): - try: - self.state.update(self.queue.get(True, 0.5)) - yield self.state - except queue.Empty: - pass - while not self.queue.empty(): - self.state.update(self.queue.get(True, 0.5)) - yield self.state def callback(self, state): self.queue.put({"status": state}) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index d65855d..4ef4323 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -168,10 +168,19 @@ dependencies = [ "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +<<<<<<< Updated upstream:rust/Cargo.lock "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +======= + "rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +>>>>>>> Stashed changes:Cargo.lock ] [[package]] @@ -205,6 +214,19 @@ dependencies = [ [[package]] name = "ghost" version = "0.1.0" +<<<<<<< Updated upstream:rust/Cargo.lock +======= +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "heck" +version = "0.3.1" +>>>>>>> Stashed changes:Cargo.lock source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -294,7 +316,11 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +<<<<<<< Updated upstream:rust/Cargo.lock "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +======= + "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +>>>>>>> Stashed changes:Cargo.lock ] [[package]] @@ -302,7 +328,11 @@ name = "mashup-impl" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ +<<<<<<< Updated upstream:rust/Cargo.lock "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +======= + "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +>>>>>>> Stashed changes:Cargo.lock "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -377,15 +407,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" +<<<<<<< Updated upstream:rust/Cargo.lock version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +======= +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +>>>>>>> Stashed changes:Cargo.lock ] [[package]] name = "proc-macro-hack-impl" +<<<<<<< Updated upstream:rust/Cargo.lock version = "0.4.1" +======= +version = "0.4.2" +>>>>>>> Stashed changes:Cargo.lock source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -592,7 +633,7 @@ dependencies = [ [[package]] name = "rstar" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -679,6 +720,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "spin" version = "0.5.0" +<<<<<<< Updated upstream:rust/Cargo.lock +======= +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "structopt" +version = "0.2.18" +>>>>>>> Stashed changes:Cargo.lock source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -748,6 +807,11 @@ name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.7" @@ -792,6 +856,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" +<<<<<<< Updated upstream:rust/Cargo.lock +======= +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +>>>>>>> Stashed changes:Cargo.lock "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" "checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922" @@ -813,8 +881,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" +<<<<<<< Updated upstream:rust/Cargo.lock "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" +======= +"checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" +"checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" +>>>>>>> Stashed changes:Cargo.lock "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086" "checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186" @@ -837,7 +910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" "checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86" "checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" -"checksum rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd08ae4f9661517777346592956ea6cdbba2895a28037af7daa600382f4b4001" +"checksum rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90bb34cd8efef7ed3ebfb29e713e51301c3e60fba37c3e9185a1afaf9ce643a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" @@ -849,6 +922,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" +<<<<<<< Updated upstream:rust/Cargo.lock +======= +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6" +"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +>>>>>>> Stashed changes:Cargo.lock "checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" "checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" @@ -858,6 +938,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" +<<<<<<< Updated upstream:rust/Cargo.lock +======= +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +>>>>>>> Stashed changes:Cargo.lock "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index d97be65..2a579f7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,12 +11,12 @@ license = "WTFPL" crate-type = ["cdylib"] [profile.release] -debug=true +#debug=true [dependencies] csv = "1.1.1" serde = { version = "1.0", features = ["derive"] } -rstar = "0.4.0" +rstar = "0.5.0" humantime = "1.2.0" permutohedron = "0.2.4" serde_json = "1.0.40" @@ -25,6 +25,7 @@ fnv = "1.0.6" bincode = "1.1.4" sha3 = "0.8.2" byteorder = "1.3.2" +strsim = "0.9.2" [dependencies.pyo3] version = "0.7.0" diff --git a/rust/src/common.rs b/rust/src/common.rs index 6e563f4..74d4d1f 100644 --- a/rust/src/common.rs +++ b/rust/src/common.rs @@ -27,6 +27,7 @@ impl SystemSerde { } } + #[derive(Debug, Clone, Deserialize, Serialize)] pub struct System { pub id: u32, @@ -37,3 +38,16 @@ pub struct System { pub distance: u32, pub pos: [f32; 3], } + +impl Ord for System { + fn cmp(&self, other: &Self) -> Ordering { + return self.id.cmp(&other.id); + } +} + +impl PartialOrd for System { + fn partial_cmp(&self, other: &Self) -> Option { + return Some(self.cmp(other)); + } +} + diff --git a/rust/src/lib.rs b/rust/src/lib.rs index fdc0fb4..ee39dd4 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,14 +1,43 @@ +extern crate strsim; mod common; mod preprocess; mod route; -use pyo3::prelude::*; -use pyo3::types::{PyDict,PyList}; +use std::collections::HashMap; use pyo3::exceptions::*; +use pyo3::prelude::*; +use pyo3::types::{PyDict, PyList}; use std::path::PathBuf; +use common::{System,SystemSerde}; + +fn find_matches(path:&PathBuf,names:Vec) -> Result)>,String> { + let mut best: HashMap)> = HashMap::new(); + for name in &names { + best.insert(name.to_string(),(0.0,None)); + }; + let mut reader = match csv::ReaderBuilder::new().from_path(path) { + Ok(rdr) => rdr, + Err(e) => { + return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); + } + }; + let systems=reader + .deserialize::(); + for sys in systems { + let sys=sys.unwrap(); + for name in &names { + best.entry(name.clone()).and_modify(|ent| { + let d1=strsim::normalized_levenshtein(&sys.system,&name); + if d1>ent.0 { + *ent=(d1,Some(sys.build())) + } + }); + } + } + return Ok(best); +} #[pymodule] pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { - /// preprocess(infile_systems, infile_bodies, outfile, callback) /// -- /// @@ -24,108 +53,139 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { use preprocess::*; let state = PyDict::new(py); let state_dict = PyDict::new(py); - callback.call(py,(state_dict,),None).unwrap(); + callback.call(py, (state_dict,), None).unwrap(); let callback_wrapped = move |state: &PreprocessState| { // println!("SEND: {:?}",state); - state_dict.set_item("file",state.file.clone())?; - state_dict.set_item("total",state.total)?; - state_dict.set_item("done",state.done)?; - callback.call(py,(state_dict,),None) + state_dict.set_item("file", state.file.clone())?; + state_dict.set_item("total", state.total)?; + state_dict.set_item("count", state.count)?; + state_dict.set_item("done", state.done)?; + state_dict.set_item("message", state.message.clone())?; + callback.call(py, (state_dict,), None) }; - preprocess_files(&PathBuf::from(infile_bodies), &PathBuf::from(infile_systems), &PathBuf::from(outfile), Box::new(callback_wrapped)).unwrap(); - return Ok(state.to_object(py)); + preprocess_files( + &PathBuf::from(infile_bodies), + &PathBuf::from(infile_systems), + &PathBuf::from(outfile), + Box::new(callback_wrapped), + ) + .unwrap(); + Ok(state.to_object(py)) } - /// route(infile, hops, range, mode,primary, greedyness, precomp, callback) + ///find_sys(sys_names,sys_list) + /// -- + /// + /// Find system by name + #[pyfn(m, "find_sys")] + fn find_sys(py:Python,sys_names:Vec,sys_list:String) -> PyResult { + let path=PathBuf::from(sys_list); + match find_matches(&path,sys_names) { + Ok(vals) => { + let ret=PyDict::new(py); + for (key,(diff,sys)) in vals { + let ret_dict=PyDict::new(py); + if let Some(val)= sys { + let pos = PyList::new(py, val.pos.iter()); + ret_dict.set_item("star_type", val.star_type.clone())?; + ret_dict.set_item("system", val.system.clone())?; + ret_dict.set_item("body", val.body.clone())?; + ret_dict.set_item("distance", val.distance)?; + ret_dict.set_item("pos", pos)?; + ret_dict.set_item("id", val.id)?; + ret.set_item(key,(diff,ret_dict).to_object(py))?; + } + } + return Ok(ret.to_object(py)); + }, + Err(e) => { + return Err(PyErr::new::(e)); + } + } + } + + /// route(infile, hops, range, radius_mult, mode,primary, greedyness, precomp, callback) /// -- /// /// Compute a Route using the suplied parameters #[pyfn(m, "route")] + #[allow(clippy::too_many_arguments)] fn route( py: Python<'static>, hops: Vec, range: f32, + radius_mult: f32, mode: String, primary: bool, permute: bool, + keep_first: bool, + keep_last: bool, greedyness: Option, precomp: Option, path: String, callback: PyObject, ) -> PyResult { use route::*; - // TODO: Verify Parameters let mode = match Mode::parse(&mode) { Ok(val) => val, Err(e) => { - return Err(PyErr::new::(e)); + return Err(PyErr::new::(e)); } }; let state_dict = PyDict::new(py); - callback.call(py,(state_dict,),None).unwrap(); + callback.call(py, (state_dict,), None).unwrap(); let callback_wrapped = move |state: &SearchState| { - println!("SEND: {:?}",state); - state_dict.set_item("mode",state.mode.clone())?; - state_dict.set_item("system",state.system.clone())?; - state_dict.set_item("body",state.body.clone())?; - state_dict.set_item("depth",state.depth)?; - state_dict.set_item("queue_size",state.queue_size)?; - state_dict.set_item("d_rem",state.d_rem)?; - state_dict.set_item("d_total",state.d_total)?; - state_dict.set_item("prc_done",state.prc_done)?; - state_dict.set_item("n_seen",state.n_seen)?; - state_dict.set_item("prc_seen",state.prc_seen)?; - callback.call(py,(state_dict,),None) + state_dict.set_item("mode", state.mode.clone())?; + state_dict.set_item("system", state.system.clone())?; + state_dict.set_item("body", state.body.clone())?; + state_dict.set_item("depth", state.depth)?; + state_dict.set_item("queue_size", state.queue_size)?; + state_dict.set_item("d_rem", state.d_rem)?; + state_dict.set_item("d_total", state.d_total)?; + state_dict.set_item("prc_done", state.prc_done)?; + state_dict.set_item("n_seen", state.n_seen)?; + state_dict.set_item("prc_seen", state.prc_seen)?; + callback.call(py, (state_dict,), None) }; - let opts=RouteOpts{ - systems:hops, - range:Some(range), + let mut systems=Vec::new(); + for sys in hops { + systems.push(route::SysEntry::parse(&sys)) + } + println!("SYSTEMS: {:?}",systems); + let opts = RouteOpts { + systems, + range: Some(range), file_path: PathBuf::from(path), precomp_file: precomp.map(PathBuf::from), callback: Box::new(callback_wrapped), mode, factor: greedyness, precompute: false, - permute: permute, - keep_first: true, - keep_last: true, - primary + permute, + keep_first, + keep_last, + primary, + radius_mult }; - let none=().to_object(py); + let none = ().to_object(py); match route(opts) { Ok(Some(route)) => { - let hops=route.iter().map(|hop| { - let pos=PyList::new(py,hop.pos.iter()); - let elem=PyDict::new(py); - elem.set_item("star_type",hop.star_type.clone()).unwrap(); - elem.set_item("system",hop.system.clone()).unwrap(); - elem.set_item("body",hop.body.clone()).unwrap(); - elem.set_item("distance",hop.distance).unwrap(); - elem.set_item("pos",pos).unwrap(); - return elem; + let hops = route.iter().map(|hop| { + let pos = PyList::new(py, hop.pos.iter()); + let elem = PyDict::new(py); + elem.set_item("star_type", hop.star_type.clone()).unwrap(); + elem.set_item("system", hop.system.clone()).unwrap(); + elem.set_item("body", hop.body.clone()).unwrap(); + elem.set_item("distance", hop.distance).unwrap(); + elem.set_item("pos", pos).unwrap(); + elem }); - let lst=PyList::new(py,hops); - return Ok(lst.to_object(py)); + let lst = PyList::new(py, hops); + Ok(lst.to_object(py)) } - Ok(None) => { - return Ok(none); - }, - Err(e) => { - return Err(PyErr::new::(e)); - } - }; - /* - let state = PyDict::new(py); - state.set_item("infile", infile)?; - state.set_item("source", source)?; - state.set_item("dest", dest)?; - state.set_item("range", range)?; - state.set_item("mode", mode)?; - state.set_item("greedyness", greedyness)?; - state.set_item("precomp", precomp)?; - state.set_item("callback", callback)?; - return callback.call(py,(state.to_object(py),),None); - */ + Ok(None) => Ok(none), + Err(e) => Err(PyErr::new::(e)), + } } Ok(()) } diff --git a/rust/src/route.rs b/rust/src/route.rs index d206501..9da946b 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -1,8 +1,10 @@ +use crate::common::{System, SystemSerde}; use core::cmp::Ordering; use csv::StringRecord; use fnv::{FnvHashMap, FnvHashSet}; use humantime::format_duration; use permutohedron::LexicalPermutation; +use pyo3::prelude::*; use rstar::{PointDistance, RTree, RTreeObject, AABB}; use sha3::{Digest, Sha3_256}; use std::collections::VecDeque; @@ -12,8 +14,6 @@ use std::io::Seek; use std::io::{BufRead, BufReader, BufWriter, Write}; use std::path::PathBuf; use std::time::Instant; -use pyo3::prelude::*; -use crate::common::{System, SystemSerde}; #[derive(Debug)] pub struct SearchState { @@ -26,9 +26,23 @@ pub struct SearchState { pub d_total: f32, pub prc_done: f32, pub n_seen: usize, - pub prc_seen: f32 + pub prc_seen: f32, } +#[derive(Debug, Clone)] +pub enum SysEntry { + ID(u32), + Name(String), +} + +impl SysEntry { + pub fn parse(s: &str) -> SysEntry { + match s.parse() { + Ok(n) => SysEntry::ID(n), + _ => SysEntry::Name(s.to_owned()), + } + } +} pub struct RouteOpts { pub range: Option, @@ -41,8 +55,9 @@ pub struct RouteOpts { pub keep_last: bool, pub factor: Option, pub mode: Mode, - pub systems: Vec, - pub callback: Box PyResult> + pub radius_mult: f32, + pub systems: Vec, + pub callback: Box PyResult>, } #[derive(Debug)] @@ -52,9 +67,9 @@ pub enum Mode { AStar, } -impl Mode { +impl Mode { pub fn parse(s: &str) -> Result { - let s=s.to_lowercase(); + let s = s.to_lowercase(); match s.as_ref() { "bfs" => Ok(Mode::BFS), "greedy" => Ok(Mode::Greedy), @@ -160,8 +175,8 @@ impl LineCache { } pub fn get(&mut self, id: u32) -> Option { let pos = self.cache[id as usize]; - self.file.seek(std::io::SeekFrom::Start(pos)).unwrap(); - let rec = Self::read_record(&mut self.file).unwrap(); + self.file.seek(std::io::SeekFrom::Start(pos)).ok()?; + let rec = Self::read_record(&mut self.file)?; let sys: SystemSerde = rec.deserialize(self.header.as_ref()).unwrap(); Some(sys.build()) } @@ -175,18 +190,26 @@ pub struct Router { range: f32, primary_only: bool, path: PathBuf, - callback: Box PyResult> + radius_mult: f32, + callback: Box PyResult>, } impl Router { - pub fn new(path: &PathBuf, range: f32, primary_only: bool,callback: Box PyResult>) -> Result { + pub fn new( + path: &PathBuf, + range: f32, + radius_mult: f32, + primary_only: bool, + callback: Box PyResult>, + ) -> Result { let mut scoopable = FnvHashSet::default(); let mut reader = match csv::ReaderBuilder::new().from_path(path) { Ok(rdr) => rdr, Err(e) => { - return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); + return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e)); } }; + let t_load = Instant::now(); println!("Loading {}...", path.to_str().unwrap()); let systems: Vec = reader .deserialize::() @@ -220,25 +243,54 @@ impl Router { primary_only, cache: LineCache::new(path), path: path.clone(), - callback: callback, + callback, + radius_mult, }; + println!( + "{} Systems loaded in {}", + ret.tree.size(), + format_duration(t_load.elapsed()) + ); Ok(ret) } - pub fn from_file(filename: &PathBuf,callback: Box PyResult>) -> Result<(PathBuf, Self),String> { - let mut reader = BufReader::new(File::open(&filename).unwrap()); + pub fn from_file( + filename: &PathBuf, + callback: Box PyResult>, + ) -> Result<(PathBuf, Self), String> { + let t_load = Instant::now(); + let mut reader = BufReader::new(match File::open(&filename) { + Ok(fh) => fh, + Err(e) => { + return Err(format!( + "Error opening file {}: {}", + filename.to_str().unwrap(), + e + )) + } + }); + println!("Loading {}", filename.to_str().unwrap()); let (primary, range, file_hash, path, route_tree): ( bool, f32, Vec, String, FnvHashMap, - ) = bincode::deserialize_from(&mut reader).unwrap(); + ) = match bincode::deserialize_from(&mut reader) { + Ok(res) => res, + Err(e) => { + return Err(format!( + "Error loading file {}: {}", + filename.to_str().unwrap(), + e + )) + } + }; let path = PathBuf::from(path); if hash_file(&path) != file_hash { return Err("File hash mismatch!".to_string()); } - let cache = LineCache::new(&path); + let cache = LineCache::new(&path).ok(); Ok(( path.clone(), Self { @@ -249,14 +301,12 @@ impl Router { cache, primary_only: primary, path, - callback + callback, + radius_mult: 0f32, }, )) } - fn closest(&self, point: &[f32; 3]) -> &System { - self.tree.nearest_neighbor(point).unwrap() - } fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { self.tree.locate_within_distance(*center, radius * radius) } @@ -265,18 +315,23 @@ impl Router { self.points_in_sphere(&sys.pos, sys.mult * r) } - fn valid(&self, sys: &System) -> bool { - self.scoopable.contains(&sys.id) + fn valid(&self, sys: &System, src: &System, dst: &System) -> bool { + let scoopable = self.scoopable.contains(&sys.id); + if self.radius_mult == 0.0 { + return scoopable; + } + let df = src.distp(dst); + return (sys.distp(src) + sys.distp(dst)) < (df * (1.0 + self.radius_mult)); } - pub fn best_name_multiroute( + pub fn best_multiroute( &self, - waypoints: &[String], + waypoints: &Vec, range: f32, - keep: (bool,bool), + keep: (bool, bool), mode: Mode, factor: f32, - ) -> Result,String> { + ) -> Result, String> { let mut best_score: f32 = std::f32::MAX; let mut waypoints = waypoints.to_owned(); let mut best_permutation_waypoints = waypoints.to_owned(); @@ -287,17 +342,12 @@ impl Router { loop { let c_first = waypoints.first().cloned(); let c_last = waypoints.last().cloned(); - let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last==last)); + let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last == last)); if valid { let mut total_d = 0.0; for pair in waypoints.windows(2) { match pair { [src, dst] => { - let (mut src, dst) = - (self.name_to_systems(&src)?, self.name_to_systems(&dst)?); - src.sort_by_key(|&p| (p.mult * 10.0) as u8); - let src = src.last().unwrap(); - let dst = dst.last().unwrap(); total_d += src.distp2(dst); } _ => return Err("Invalid routing parameters!".to_string()), @@ -313,35 +363,19 @@ impl Router { } } println!("Best permutation: {:?}", best_permutation_waypoints); - self.name_multiroute(&best_permutation_waypoints, range, mode, factor) + self.multiroute(&best_permutation_waypoints, range, mode, factor) } - pub fn name_multiroute( - &self, - waypoints: &[String], - range: f32, - mode: Mode, - factor: f32, - ) -> Result,String> { - let mut coords = Vec::new(); - for p_name in waypoints { - let mut p_l = self.name_to_systems(p_name)?; - p_l.sort_by_key(|&p| (p.mult * 10.0) as u8); - let p = p_l.last().unwrap(); - coords.push((p_name, p.pos)); - } - self.multiroute(coords.as_slice(), range, mode, factor) - } pub fn multiroute( &self, - waypoints: &[(&String, [f32; 3])], + waypoints: &Vec, range: f32, mode: Mode, factor: f32, - ) -> Result,String> { + ) -> Result, String> { let mut route: Vec = Vec::new(); for pair in waypoints.windows(2) { - match *pair { + match pair.clone() { [src, dst] => { let block = match mode { Mode::BFS => self.route_bfs(&src, &dst, range)?, @@ -358,56 +392,88 @@ impl Router { } } } - _ => return Err("Invalid routing parameters!".to_string()), + _ => { + return Err("Invalid routing parameters!".to_owned()); + } } } Ok(route) } - fn name_to_systems(&self, name: &str) -> Result,String> { + fn resolve_systems(&self, systems: &[SysEntry]) -> Result, String> { + let mut ret = Vec::new(); + let mut sys_by_id: FnvHashMap = FnvHashMap::default(); + let mut sys_by_name: FnvHashMap = FnvHashMap::default(); for sys in &self.tree { - if sys.system == name { - return Ok(self.neighbours(&sys, 0.0).collect()); + for ent in systems { + match ent { + SysEntry::ID(i) => { + let i = *i; + if sys.id == i { + sys_by_id.insert(i, sys); + } + } + SysEntry::Name(n) => { + if &sys.body == n || &sys.system == n { + sys_by_name.insert(n.to_string(), sys); + } + } + } } } - Err(format!("System not found: \"{}\"", name)) + for ent in systems { + match ent { + SysEntry::ID(i) => match sys_by_id.get(i) { + Some(sys) => ret.push(sys.clone().clone()), + None => { + return Err(format!("System: {:?} not found", ent)); + } + }, + SysEntry::Name(n) => match sys_by_name.get(n) { + Some(sys) => ret.push(sys.clone().clone()), + None => { + return Err(format!("System: {:?} not found", ent)); + } + }, + } + } + Ok(ret) } pub fn route_astar( &self, - src: &(&String, [f32; 3]), - dst: &(&String, [f32; 3]), + src: &System, + dst: &System, range: f32, factor: f32, - ) -> Result,String> { + ) -> Result, String> { if factor == 0.0 { return self.route_bfs(src, dst, range); } - let (src_name, src) = src; - let (dst_name, dst) = dst; - let start_sys = self.closest(src); - let goal_sys = self.closest(dst); - let d_total = dist(&start_sys.pos,&goal_sys.pos); - let mut d_rem=d_total; - - let mut state=SearchState { - mode:"A-Star".into(), - depth:0, - queue_size:0, + let src_name = src.system.clone(); + let dst_name = dst.system.clone(); + let start_sys = src; + let goal_sys = dst; + let d_total = dist(&start_sys.pos, &goal_sys.pos); + let mut d_rem = d_total; + + let mut state = SearchState { + mode: "A-Star".into(), + depth: 0, + queue_size: 0, d_rem: d_total, - d_total: d_total, + d_total, prc_done: 0.0, - n_seen:0, + n_seen: 0, prc_seen: 0.0, body: start_sys.body.clone(), - system: start_sys.system.clone() + system: start_sys.system.clone(), }; let total = self.tree.size() as f32; - let t_start = Instant::now(); + let mut t_last = Instant::now(); let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); let mut found = false; - let mut maxd = 0; let mut queue: Vec<(usize, usize, &System)> = Vec::new(); queue.push(( 0, // depth @@ -417,31 +483,22 @@ impl Router { seen.insert(start_sys.id); while !(queue.is_empty() || found) { while let Some((depth, _, sys)) = queue.pop() { - if (depth+1) > maxd { - maxd = depth+1; - state.depth=depth; - state.queue_size=queue.len(); - state.prc_done=((d_total-d_rem)*100f32) / d_total; - state.d_rem=d_rem; - state.n_seen=seen.len(); - state.prc_seen=((seen.len()*100) as f32) / total; - state.body=sys.body.clone(); - state.system=sys.system.clone(); + if t_last.elapsed().as_millis() > 100 { + t_last = Instant::now(); + state.depth = depth; + state.queue_size = queue.len(); + state.prc_done = ((d_total - d_rem) * 100f32) / d_total; + state.d_rem = d_rem; + state.n_seen = seen.len(); + state.prc_seen = ((seen.len() * 100) as f32) / total; + state.body = sys.body.clone(); + state.system = sys.system.clone(); match (self.callback)(&state) { Ok(_) => (), Err(e) => { - return Err(format!("{:?}",e).to_string()); + return Err(format!("{:?}", e).to_string()); } }; - print!( - "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", - format_duration(t_start.elapsed()), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total - ); - std::io::stdout().flush().unwrap(); } if sys.id == goal_sys.id { found = true; @@ -449,16 +506,15 @@ impl Router { } queue.extend( self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id))) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); - let d_g = (nb.distp(goal_sys) / range) as usize; - let dist = dist(&nb.pos, &goal_sys.pos); - if dist < d_rem { - d_rem = dist; + let d_g=nb.distp(goal_sys); + if d_g = Vec::new(); let mut curr_sys = goal_sys; @@ -494,54 +550,54 @@ impl Router { pub fn route_greedy( &self, - src: &(&String, [f32; 3]), - dst: &(&String, [f32; 3]), + src: &System, + dst: &System, range: f32, - ) -> Result,String> { - let (src_name, src) = src; - let (dst_name, dst) = dst; - let start_sys = self.closest(src); - let goal_sys = self.closest(dst); + ) -> Result, String> { + let src_name = src.system.clone(); + let dst_name = dst.system.clone(); + let start_sys = src; + let goal_sys = dst; let d_total = dist(&start_sys.pos, &goal_sys.pos); - let mut d_rem=d_total; - let mut state=SearchState { - mode:"Greedy".into(), - depth:0, - queue_size:0, + let mut d_rem = d_total; + let mut state = SearchState { + mode: "Greedy".into(), + depth: 0, + queue_size: 0, d_rem: d_total, - d_total: d_total, + d_total, prc_done: 0.0, - n_seen:0, + n_seen: 0, prc_seen: 0.0, - body:start_sys.body.clone(), - system:start_sys.system.clone(), + body: start_sys.body.clone(), + system: start_sys.system.clone(), }; let total = self.tree.size() as f32; + let mut t_last = Instant::now(); let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); let mut found = false; - let mut maxd = 0; let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); - queue.push((-goal_sys.mult, start_sys.distp2(goal_sys), 0, &start_sys)); + queue.push((-goal_sys.mult, start_sys.distp(goal_sys), 0, &start_sys)); seen.insert(start_sys.id); while !(queue.is_empty() || found) { while let Some((_, _, depth, sys)) = queue.pop() { - if (depth+1) > maxd { - state.depth=depth; - state.queue_size=queue.len(); - state.prc_done=((d_total-d_rem)*100f32) / d_total; - state.d_rem=d_rem; - state.n_seen=seen.len(); - state.prc_seen=((seen.len()*100) as f32) / total; - state.body=sys.body.clone(); - state.system=sys.system.clone(); + if t_last.elapsed().as_millis() > 100 { + t_last = Instant::now(); + state.depth = depth; + state.queue_size = queue.len(); + state.prc_done = ((d_total - d_rem) * 100f32) / d_total; + state.d_rem = d_rem; + state.n_seen = seen.len(); + state.prc_seen = ((seen.len() * 100) as f32) / total; + state.body = sys.body.clone(); + state.system = sys.system.clone(); match (self.callback)(&state) { Ok(_) => (), Err(e) => { - return Err(format!("{:?}",e).to_string()); + return Err(format!("{:?}", e).to_string()); } }; - maxd = depth+1; } if sys.id == goal_sys.id { found = true; @@ -549,15 +605,15 @@ impl Router { } queue.extend( self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id))) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); - let dist = dist(&nb.pos, &goal_sys.pos); - if dist < d_rem { - d_rem = dist; + let d_g=nb.distp(goal_sys); + if d_g = Vec::new(); let mut curr_sys = goal_sys; @@ -582,10 +638,7 @@ impl Router { Ok(v) } - pub fn precompute(&mut self, src: &str) -> Result<(),String> { - let mut sys_l = self.name_to_systems(src)?; - sys_l.sort_by_key(|&sys| (sys.mult * 10.0) as u8); - let sys = sys_l.last().unwrap(); + pub fn precompute(&mut self, src: &System) -> Result<(), String> { let total = self.tree.size() as f32; let t_start = Instant::now(); let mut prev = FnvHashMap::default(); @@ -593,8 +646,8 @@ impl Router { let mut depth = 0; let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); - queue.push_front((0, &sys)); - seen.insert(sys.id); + queue.push_front((0, &src)); + seen.insert(src.id); while !queue.is_empty() { print!( "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", @@ -622,7 +675,7 @@ impl Router { self.route_tree = Some(prev); let ofn = format!( "{}_{}{}.router", - src.replace("*", "").replace(" ", "_"), + src.system.replace("*", "").replace(" ", "_"), self.range, if self.primary_only { "_primary" } else { "" } ); @@ -634,13 +687,17 @@ impl Router { String::from(self.path.to_str().unwrap()), self.route_tree.as_ref().unwrap(), ); - return match bincode::serialize_into(&mut out_fh, &data) { + match bincode::serialize_into(&mut out_fh, &data) { Ok(_) => Ok(()), - Err(e) => Err(format!("Error: {}",e).to_string()) - }; + Err(e) => Err(format!("Error: {}", e).to_string()), + } } - fn get_systems_by_ids(&mut self, path: &PathBuf, ids: &[u32]) -> Result,String> { + fn get_systems_by_ids( + &mut self, + path: &PathBuf, + ids: &[u32], + ) -> Result, String> { let mut ret = FnvHashMap::default(); if let Some(c) = &mut self.cache.as_mut() { let mut missing = false; @@ -659,13 +716,12 @@ impl Router { return Ok(ret); } } - let mut reader = match csv::ReaderBuilder::new() - .from_path(path) { - Ok(reader) => reader, - Err(e) => { - return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e)); - } - }; + let mut reader = match csv::ReaderBuilder::new().from_path(path) { + Ok(reader) => reader, + Err(e) => { + return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e)); + } + }; reader .deserialize::() .map(|res| res.unwrap()) @@ -674,30 +730,20 @@ impl Router { ret.insert(sys.id, sys.build()); }) .count(); + for id in ids { + if !ret.contains_key(&id) { + return Err(format!("ID {} not found", id)); + } + } Ok(ret) } - fn get_system_by_name(path: &PathBuf, name: &str) -> Result { - // TODO: Fuzzy search (https://github.com/andylokandy/simsearch-rs) - let mut reader = csv::ReaderBuilder::new() - .from_path(path) - .unwrap_or_else(|e| { - eprintln!("Error opening {}: {}", path.to_str().unwrap(), e); - std::process::exit(1); - }); - let sys = reader - .deserialize::() - .map(|res| res.unwrap()) - .find(|sys| sys.system == name); - match sys { - Some(system) => Ok(system.build()), - None => Err(format!("System {} not found!",name).to_string()) - } - } - - pub fn route_to(&mut self, dst: &str, systems_path: &PathBuf) -> Result,String> { + pub fn route_to( + &mut self, + dst: &System, + systems_path: &PathBuf, + ) -> Result, String> { let prev = self.route_tree.as_ref().unwrap(); - let dst = Self::get_system_by_name(&systems_path, dst)?; if !prev.contains_key(&dst.id) { return Err(format!("System-ID {} not found", dst.id).to_string()); }; @@ -719,7 +765,7 @@ impl Router { let sys = match id_map.get(&sys_id) { Some(sys) => sys, None => { - return Err(format!("System-ID {} not found!",sys_id)); + return Err(format!("System-ID {} not found!", sys_id)); } }; v.push(sys.clone()) @@ -729,29 +775,29 @@ impl Router { pub fn route_bfs( &self, - src: &(&String, [f32; 3]), - dst: &(&String, [f32; 3]), + start_sys: &System, + goal_sys: &System, range: f32, - ) -> Result,String> { + ) -> Result, String> { println!("Running BFS"); - let (src_name, src) = src; - let (dst_name, dst) = dst; - let start_sys = self.closest(src); - let goal_sys = self.closest(dst); + let src_name = start_sys.system.clone(); + let dst_name = goal_sys.system.clone(); let d_total = dist(&start_sys.pos, &goal_sys.pos); - let mut state=SearchState { - mode:"BFS".into(), - depth:0, - queue_size:0, - d_rem: d_total, - d_total: d_total, + let mut d_rem = d_total; + let mut state = SearchState { + mode: "BFS".into(), + depth: 0, + queue_size: 0, + d_rem, + d_total, prc_done: 0.0, - n_seen:0, + n_seen: 0, prc_seen: 0.0, system: start_sys.system.clone(), - body: start_sys.body.clone() + body: start_sys.body.clone(), }; { + let d = dist(&start_sys.pos, &goal_sys.pos); println!("Plotting route from {} to {}...", src_name, dst_name); println!( "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", @@ -765,41 +811,47 @@ impl Router { let mut seen = FnvHashSet::default(); let mut depth = 0; let mut found = false; + let mut t_last = Instant::now(); let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); let mut d_rem = dist(&start_sys.pos, &goal_sys.pos); queue.push_front((0, &start_sys)); seen.insert(start_sys.id); while !(queue.is_empty() || found) { - state.depth=depth; - state.queue_size=queue.len(); - state.prc_done=((d_total-d_rem)*100f32) / d_total; - state.d_rem=d_rem; - state.n_seen=seen.len(); - state.prc_seen=((seen.len()*100) as f32) / total; - { - let s=queue.get(0).unwrap().1; - state.system=s.system.clone(); - state.body=s.body.clone(); - } - match (self.callback)(&state) { - Ok(_) => (), - Err(e) => { - return Err(format!("{:?}",e).to_string()); - } - }; while let Some((d, sys)) = queue.pop_front() { if sys.id == goal_sys.id { found = true; break; } + if t_last.elapsed().as_millis() > 100 { + state.depth = depth; + state.queue_size = queue.len(); + state.prc_done = ((d_total - d_rem) * 100f32) / d_total; + state.d_rem = d_rem; + state.n_seen = seen.len(); + state.prc_seen = ((seen.len() * 100) as f32) / total; + { + let s = queue.get(0).unwrap().1; + state.system = s.system.clone(); + state.body = s.body.clone(); + } + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + return Err(format!("{:?}", e).to_string()); + } + }; + t_last = Instant::now(); + } queue_next.extend( self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) + .filter(|&nb| { + (self.valid(nb, &start_sys, &goal_sys) || (nb.id == goal_sys.id)) + }) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); - let dist = dist(&nb.pos, &goal_sys.pos); + let dist = nb.distp(goal_sys); if dist < d_rem { d_rem = dist; } @@ -813,7 +865,7 @@ impl Router { println!(); println!(); if !found { - return Err(format!("No route from {} to {} found!", src_name, dst_name).to_string()); + return Err(format!("No route from {} to {} found!", src_name, dst_name)); } let mut v: Vec = Vec::new(); let mut curr_sys = goal_sys; @@ -830,54 +882,71 @@ impl Router { Ok(v) } } -pub fn route(opts: RouteOpts) -> Result>,String> { - +pub fn route(opts: RouteOpts) -> Result>, String> { if opts.systems.is_empty() { - return if opts.precomp_file.is_some() { - Err("Error: Please specify exatly one system".to_string()) + if opts.precomp_file.is_some() { + return Err("Error: Please specify exatly one system".to_owned()); } else if opts.precompute { - Err("Error: Please specify at least one system".to_string()) + return Err("Error: Please specify at least one system".to_owned()); } else { - Err("Error: Please specify at least two systems".to_string()) - } + return Err("Error: Please specify at least two systems".to_owned()); + }; } let mut path = opts.file_path; let mut router: Router = if opts.precomp_file.is_some() { - let (path_,ret) = Router::from_file(&opts.precomp_file.clone().unwrap(),Box::new(opts.callback))?; - path=path_; + let (path_, ret) = + Router::from_file(&opts.precomp_file.clone().unwrap(), Box::new(opts.callback))?; + path = path_; ret } else if opts.range.is_some() { - Router::new(&path, opts.range.unwrap(), opts.primary, Box::new(opts.callback))? + Router::new( + &path, + opts.range.unwrap(), + opts.radius_mult, + opts.primary, + Box::new(opts.callback), + )? } else { - return Err("Please specify a jump range!".to_string()); + Router::new( + &path, + opts.range.unwrap(), + opts.radius_mult, + opts.primary, + opts.callback, + )? }; + let systems: Vec = router + .resolve_systems(&opts.systems)? + .iter() + .map(|sys| sys.clone()) + .collect(); if opts.precompute { - for sys in opts.systems { + for sys in systems { router.route_tree = None; router.precompute(&sys)?; } - return Ok(None) + return Ok(None); } let route = if router.route_tree.is_some() { - router.route_to(opts.systems.first().unwrap(), &path)? + router.route_to(systems.first().unwrap(), &path)? } else if opts.permute { - router.best_name_multiroute( - &opts.systems, + router.best_multiroute( + &systems, opts.range.unwrap(), - (opts.keep_first,opts.keep_last), + (opts.keep_first, opts.keep_last), opts.mode, opts.factor.unwrap_or(1.0), )? } else { - router.name_multiroute( - &opts.systems, + router.multiroute( + &systems, opts.range.unwrap(), opts.mode, opts.factor.unwrap_or(1.0), )? }; if route.is_empty() { - return Err("No route found!".to_string()) + return Err("No route found!".to_string()); } - return Ok(Some(route)); + Ok(Some(route)) } diff --git a/setup.py b/setup.py index 6211685..8137fb5 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,14 @@ setup( ], packages=["ed_lrr_gui"], entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, - install_requires=["PyQt5", "appdirs", "PyYAML", "requests", "python-dateutil"], + install_requires=[ + "PyQt5", + "appdirs", + "PyYAML", + "requests", + "python-dateutil", + "pyperclip", + ], include_package_data=True, zip_safe=False, ) diff --git a/test.bat b/test.bat new file mode 100644 index 0000000..b7cddb8 --- /dev/null +++ b/test.bat @@ -0,0 +1,4 @@ +python build_gui.py +pip uninstall -y ed_lrr_gui +pip install -e . +ed_lrr_gui From 85827a70c5a403f975f0ab667d4e13ff57160d7a Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 00:10:23 +0200 Subject: [PATCH 20/72] chore: Added changelog --- .chglog/CHANGELOG.tpl.md | 6 ++++-- .chglog/config.yml | 13 ++++++++++++- CHANGELOG.md | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md index 1f731b6..0b655c2 100644 --- a/.chglog/CHANGELOG.tpl.md +++ b/.chglog/CHANGELOG.tpl.md @@ -4,8 +4,9 @@ {{ if .Unreleased.CommitGroups -}} {{ range .Unreleased.CommitGroups -}} +### {{ .Title }} {{ range .Commits -}} -- {{ .Header }} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} {{ end }} {{ end -}} {{ end -}} @@ -15,8 +16,9 @@ ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} {{ range .CommitGroups -}} +### {{ .Title }} {{ range .Commits -}} -- {{ .Header }} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} {{ end }} {{ end -}} diff --git a/.chglog/config.yml b/.chglog/config.yml index 65dde53..d86cb03 100644 --- a/.chglog/config.yml +++ b/.chglog/config.yml @@ -4,9 +4,20 @@ info: title: CHANGELOG repository_url: https://gitlab.com/Earthnuker/ed_lrr options: + commit_groups: + title_maps: + feat: Features + fix: Bug Fixes + perf: Performance Improvements + refactor: Code Refactoring + misc: Miscellaneous + other: Other + docs: Documentation header: - pattern: "^(.*)$" + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" pattern_maps: + - Type + - Scope - Subject notes: keywords: diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2d58412 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ + +## [Unreleased] + +### Features +- **GUI:** Implement route plotting and fuzzy search +- **GUI:** Add Download functionlaity, update Rust code, update Python code + +### Miscellaneous +- Added changelog + + + +## 0.0.0 - 2019-07-15 + +[Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/0.0.0...HEAD From 4b146430484b93b5ac064a62dbdad20133abcc1b Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 01:17:39 +0200 Subject: [PATCH 21/72] fix(router): Fixed some syntax errors created by botched merge --- rust/Cargo.lock | 417 +++++++++-------------------------------- rust/src/common.rs | 1 + rust/src/preprocess.rs | 6 +- rust/src/route.rs | 21 +-- 4 files changed, 100 insertions(+), 345 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 4ef4323..4ccdea1 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2,25 +2,24 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "atty" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -28,9 +27,9 @@ name = "bincode" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -59,13 +58,13 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -88,9 +87,9 @@ name = "clicolors-control" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -107,13 +106,13 @@ name = "console" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -124,11 +123,11 @@ name = "csv" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -136,7 +135,7 @@ name = "csv-core" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -144,13 +143,13 @@ name = "ctor" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "digest" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -168,19 +167,11 @@ dependencies = [ "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -<<<<<<< Updated upstream:rust/Cargo.lock - "rstar 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", -======= - "rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> Stashed changes:Cargo.lock ] [[package]] @@ -198,11 +189,6 @@ name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "generic-array" version = "0.12.3" @@ -214,24 +200,11 @@ dependencies = [ [[package]] name = "ghost" version = "0.1.0" -<<<<<<< Updated upstream:rust/Cargo.lock -======= source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "heck" -version = "0.3.1" ->>>>>>> Stashed changes:Cargo.lock -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -250,8 +223,8 @@ dependencies = [ "console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -270,8 +243,8 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -299,12 +272,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.58" +version = "0.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lock_api" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -316,11 +289,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -<<<<<<< Updated upstream:rust/Cargo.lock - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -======= "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> Stashed changes:Cargo.lock ] [[package]] @@ -328,20 +297,16 @@ name = "mashup-impl" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ -<<<<<<< Updated upstream:rust/Cargo.lock - "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -======= "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> Stashed changes:Cargo.lock "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -349,7 +314,7 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -360,36 +325,30 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "opaque-debug" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parking_lot" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.5.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -407,26 +366,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -<<<<<<< Updated upstream:rust/Cargo.lock -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -======= version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> Stashed changes:Cargo.lock ] [[package]] name = "proc-macro-hack-impl" -<<<<<<< Updated upstream:rust/Cargo.lock -version = "0.4.1" -======= version = "0.4.2" ->>>>>>> Stashed changes:Cargo.lock source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -443,11 +391,11 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -458,8 +406,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -469,8 +417,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -480,144 +428,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_syscall" -version = "0.1.54" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" -version = "1.1.7" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-automata" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -625,11 +460,8 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.7" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rstar" @@ -674,20 +506,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.94" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.95 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -697,7 +529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -707,9 +539,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -720,13 +552,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "spin" version = "0.5.0" -<<<<<<< Updated upstream:rust/Cargo.lock -======= -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strsim" -version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -734,39 +559,22 @@ name = "strsim" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "structopt" -version = "0.2.18" ->>>>>>> Stashed changes:Cargo.lock -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "syn" -version = "0.15.39" +version = "0.15.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "termion" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "termios" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -782,11 +590,6 @@ name = "typenum" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ucd-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-width" version = "0.1.5" @@ -797,16 +600,6 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "utf8-ranges" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "version_check" version = "0.1.5" @@ -832,14 +625,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bstr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc0572e02f76cb335f309b19e0a0d585b4f62788f7d26de2a13a836a637385f" +"checksum bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0a692f1c740e7e821ca71a22cf99b9b2322dfa94d10f71443befb1797b3946a" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" @@ -849,17 +642,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" -"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" -<<<<<<< Updated upstream:rust/Cargo.lock -======= -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" ->>>>>>> Stashed changes:Cargo.lock "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" "checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922" @@ -868,80 +656,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" -"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" +"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" +"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" "checksum mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b" "checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb" -"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" -"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" -"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" -"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" -"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" -<<<<<<< Updated upstream:rust/Cargo.lock -"checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" -"checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -======= "checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" "checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" ->>>>>>> Stashed changes:Cargo.lock "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086" "checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186" "checksum pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c494f8161f5b73096cc50f00fbb90fe670f476cde5e59c1decff39b546d54f40" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" -"checksum regex-automata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed09217220c272b29ef237a974ad58515bde75f194e3ffa7e6d0bf0f3b01f86" -"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" +"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" +"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" "checksum rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90bb34cd8efef7ed3ebfb29e713e51301c3e60fba37c3e9185a1afaf9ce643a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b" -"checksum serde_derive 1.0.95 (registry+https://github.com/rust-lang/crates.io-index)" = "5ea8eb91549d859275aef70c58bb30bd62ce50e5eb1a52d32b1b6886e02f7bce" +"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" +"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" -<<<<<<< Updated upstream:rust/Cargo.lock -======= -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" ->>>>>>> Stashed changes:Cargo.lock -"checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" -"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" +"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" "checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde" -<<<<<<< Updated upstream:rust/Cargo.lock -======= -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" ->>>>>>> Stashed changes:Cargo.lock "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" diff --git a/rust/src/common.rs b/rust/src/common.rs index 74d4d1f..33b8132 100644 --- a/rust/src/common.rs +++ b/rust/src/common.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::cmp::Ordering; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SystemSerde { diff --git a/rust/src/preprocess.rs b/rust/src/preprocess.rs index 83464b3..53a8e95 100644 --- a/rust/src/preprocess.rs +++ b/rust/src/preprocess.rs @@ -42,6 +42,7 @@ struct System { #[derive(Debug)] pub struct PreprocessState { pub file: String, + pub message: String, pub total: u64, pub done: u64, pub count: usize, @@ -68,7 +69,8 @@ fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> (),callback: file: path.to_str().unwrap().to_owned(), total: total_size, done: 0, - count: 0 + count: 0 , + message: format!("Processing {} ...", path.to_str().unwrap()) }; println!("Loading {} ...", path.to_str().unwrap()); while let Ok(n) = reader.read_line(&mut buffer) { @@ -82,7 +84,7 @@ fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> (),callback: let pos=reader.seek(SeekFrom::Current(0)).unwrap(); state.done=pos; state.count += 1; - if (t_last.elapsed().as_millis()>100) { + if t_last.elapsed().as_millis()>100 { callback(&state)?; t_last=Instant::now(); } diff --git a/rust/src/route.rs b/rust/src/route.rs index 9da946b..5d58c40 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -258,7 +258,6 @@ impl Router { filename: &PathBuf, callback: Box PyResult>, ) -> Result<(PathBuf, Self), String> { - let t_load = Instant::now(); let mut reader = BufReader::new(match File::open(&filename) { Ok(fh) => fh, Err(e) => { @@ -290,7 +289,7 @@ impl Router { if hash_file(&path) != file_hash { return Err("File hash mismatch!".to_string()); } - let cache = LineCache::new(&path).ok(); + let cache = LineCache::new(&path); Ok(( path.clone(), Self { @@ -796,16 +795,13 @@ impl Router { system: start_sys.system.clone(), body: start_sys.body.clone(), }; - { - let d = dist(&start_sys.pos, &goal_sys.pos); - println!("Plotting route from {} to {}...", src_name, dst_name); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", - range, - d_total, - d_total / range - ); - } + println!("Plotting route from {} to {}...", src_name, dst_name); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", + range, + d_total, + d_total / range + ); let total = self.tree.size() as f32; let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); @@ -814,7 +810,6 @@ impl Router { let mut t_last = Instant::now(); let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); - let mut d_rem = dist(&start_sys.pos, &goal_sys.pos); queue.push_front((0, &start_sys)); seen.insert(start_sys.id); while !(queue.is_empty() || found) { From cb4de8ae7394b3c6bf85a12728342cd5f5adddba Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 01:18:20 +0200 Subject: [PATCH 22/72] chore: Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d58412..13c14f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## [Unreleased] +### Bug Fixes +- **router:** Fixed some syntax errors created by botched merge + ### Features - **GUI:** Implement route plotting and fuzzy search - **GUI:** Add Download functionlaity, update Rust code, update Python code From fb3f79b7d45ec0f995a0bd8f5e28f63b9f7d768f Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 02:01:52 +0200 Subject: [PATCH 23/72] misc(formatting): ran `cargo fmt` and `cargo clippy`, fixed all warnings --- rust/src/common.rs | 6 +- rust/src/lib.rs | 82 +++++++++++++------------- rust/src/preprocess.rs | 127 +++++++++++++++++++++++------------------ rust/src/route.rs | 29 +++++----- 4 files changed, 131 insertions(+), 113 deletions(-) diff --git a/rust/src/common.rs b/rust/src/common.rs index 33b8132..b8fa857 100644 --- a/rust/src/common.rs +++ b/rust/src/common.rs @@ -28,7 +28,6 @@ impl SystemSerde { } } - #[derive(Debug, Clone, Deserialize, Serialize)] pub struct System { pub id: u32, @@ -42,13 +41,12 @@ pub struct System { impl Ord for System { fn cmp(&self, other: &Self) -> Ordering { - return self.id.cmp(&other.id); + self.id.cmp(&other.id) } } impl PartialOrd for System { fn partial_cmp(&self, other: &Self) -> Option { - return Some(self.cmp(other)); + Some(self.cmp(other)) } } - diff --git a/rust/src/lib.rs b/rust/src/lib.rs index ee39dd4..9b82f91 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -2,38 +2,40 @@ extern crate strsim; mod common; mod preprocess; mod route; -use std::collections::HashMap; +use common::{System, SystemSerde}; use pyo3::exceptions::*; use pyo3::prelude::*; use pyo3::types::{PyDict, PyList}; +use std::collections::HashMap; use std::path::PathBuf; -use common::{System,SystemSerde}; -fn find_matches(path:&PathBuf,names:Vec) -> Result)>,String> { - let mut best: HashMap)> = HashMap::new(); +fn find_matches( + path: &PathBuf, + names: Vec, +) -> Result)>, String> { + let mut best: HashMap)> = HashMap::new(); for name in &names { - best.insert(name.to_string(),(0.0,None)); - }; + best.insert(name.to_string(), (0.0, None)); + } let mut reader = match csv::ReaderBuilder::new().from_path(path) { - Ok(rdr) => rdr, - Err(e) => { - return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); - } - }; - let systems=reader - .deserialize::(); - for sys in systems { - let sys=sys.unwrap(); - for name in &names { - best.entry(name.clone()).and_modify(|ent| { - let d1=strsim::normalized_levenshtein(&sys.system,&name); - if d1>ent.0 { - *ent=(d1,Some(sys.build())) - } - }); - } + Ok(rdr) => rdr, + Err(e) => { + return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); } - return Ok(best); + }; + let systems = reader.deserialize::(); + for sys in systems { + let sys = sys.unwrap(); + for name in &names { + best.entry(name.clone()).and_modify(|ent| { + let d1 = strsim::normalized_levenshtein(&sys.system, &name); + if d1 > ent.0 { + *ent = (d1, Some(sys.build())) + } + }); + } + } + Ok(best) } #[pymodule] @@ -67,7 +69,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { &PathBuf::from(infile_bodies), &PathBuf::from(infile_systems), &PathBuf::from(outfile), - Box::new(callback_wrapped), + &callback_wrapped, ) .unwrap(); Ok(state.to_object(py)) @@ -75,17 +77,17 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { ///find_sys(sys_names,sys_list) /// -- - /// + /// /// Find system by name #[pyfn(m, "find_sys")] - fn find_sys(py:Python,sys_names:Vec,sys_list:String) -> PyResult { - let path=PathBuf::from(sys_list); - match find_matches(&path,sys_names) { + fn find_sys(py: Python, sys_names: Vec, sys_list: String) -> PyResult { + let path = PathBuf::from(sys_list); + match find_matches(&path, sys_names) { Ok(vals) => { - let ret=PyDict::new(py); - for (key,(diff,sys)) in vals { - let ret_dict=PyDict::new(py); - if let Some(val)= sys { + let ret = PyDict::new(py); + for (key, (diff, sys)) in vals { + let ret_dict = PyDict::new(py); + if let Some(val) = sys { let pos = PyList::new(py, val.pos.iter()); ret_dict.set_item("star_type", val.star_type.clone())?; ret_dict.set_item("system", val.system.clone())?; @@ -93,13 +95,13 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { ret_dict.set_item("distance", val.distance)?; ret_dict.set_item("pos", pos)?; ret_dict.set_item("id", val.id)?; - ret.set_item(key,(diff,ret_dict).to_object(py))?; + ret.set_item(key, (diff, ret_dict).to_object(py))?; } } - return Ok(ret.to_object(py)); - }, + Ok(ret.to_object(py)) + } Err(e) => { - return Err(PyErr::new::(e)); + Err(PyErr::new::(e)) } } } @@ -147,11 +149,11 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { state_dict.set_item("prc_seen", state.prc_seen)?; callback.call(py, (state_dict,), None) }; - let mut systems=Vec::new(); + let mut systems = Vec::new(); for sys in hops { systems.push(route::SysEntry::parse(&sys)) } - println!("SYSTEMS: {:?}",systems); + println!("SYSTEMS: {:?}", systems); let opts = RouteOpts { systems, range: Some(range), @@ -165,7 +167,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { keep_first, keep_last, primary, - radius_mult + radius_mult, }; let none = ().to_object(py); match route(opts) { diff --git a/rust/src/preprocess.rs b/rust/src/preprocess.rs index 53a8e95..5474244 100644 --- a/rust/src/preprocess.rs +++ b/rust/src/preprocess.rs @@ -1,14 +1,14 @@ use crate::common::SystemSerde; use fnv::FnvHashMap; +use pyo3::prelude::*; use serde::Deserialize; use serde_json::Result; use std::fs::File; use std::io::Seek; use std::io::{BufRead, BufReader, BufWriter, SeekFrom}; use std::path::PathBuf; -use std::time::Instant; use std::str; -use pyo3::prelude::*; +use std::time::Instant; #[derive(Debug, Deserialize)] #[allow(non_snake_case)] @@ -48,7 +48,6 @@ pub struct PreprocessState { pub count: usize, } - fn get_mult(star_type: &str) -> f32 { if star_type.contains("White Dwarf") { return 1.5; @@ -59,18 +58,22 @@ fn get_mult(star_type: &str) -> f32 { 1.0 } -fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> (),callback: &Box PyResult>) -> std::io::Result<()> { +fn process( + path: &PathBuf, + func: &mut dyn for<'r> FnMut(&'r str) -> (), + callback: &dyn Fn(&PreprocessState) -> PyResult, +) -> std::io::Result<()> { let mut buffer = String::new(); let fh = File::open(path)?; - let total_size= fh.metadata()?.len(); - let mut t_last=Instant::now(); + let total_size = fh.metadata()?.len(); + let mut t_last = Instant::now(); let mut reader = BufReader::new(fh); - let mut state=PreprocessState { + let mut state = PreprocessState { file: path.to_str().unwrap().to_owned(), total: total_size, done: 0, - count: 0 , - message: format!("Processing {} ...", path.to_str().unwrap()) + count: 0, + message: format!("Processing {} ...", path.to_str().unwrap()), }; println!("Loading {} ...", path.to_str().unwrap()); while let Ok(n) = reader.read_line(&mut buffer) { @@ -81,28 +84,35 @@ fn process(path: &PathBuf, func: &mut dyn for<'r> FnMut(&'r str) -> (),callback: if !buffer.is_empty() { func(&buffer); } - let pos=reader.seek(SeekFrom::Current(0)).unwrap(); - state.done=pos; + let pos = reader.seek(SeekFrom::Current(0)).unwrap(); + state.done = pos; state.count += 1; - if t_last.elapsed().as_millis()>100 { + if t_last.elapsed().as_millis() > 100 { callback(&state)?; - t_last=Instant::now(); + t_last = Instant::now(); } buffer.clear(); } Ok(()) } -fn process_systems(path: &PathBuf,callback: &Box PyResult> ) -> FnvHashMap { +fn process_systems( + path: &PathBuf, + callback: &dyn Fn(&PreprocessState) -> PyResult, +) -> FnvHashMap { let mut ret = FnvHashMap::default(); - process(path, &mut |line| { - let sys_res: Result = serde_json::from_str(&line); - if let Ok(sys) = sys_res { - ret.insert(sys.id, sys); - } else { - eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); - } - },callback) + process( + path, + &mut |line| { + let sys_res: Result = serde_json::from_str(&line); + if let Ok(sys) = sys_res { + ret.insert(sys.id, sys); + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, sys_res.unwrap_err()); + } + }, + callback, + ) .unwrap(); ret } @@ -125,7 +135,7 @@ fn process_bodies( path: &PathBuf, out_path: &PathBuf, systems: &mut FnvHashMap, - callback: &Box PyResult>, + callback: &dyn Fn(&PreprocessState) -> PyResult, ) -> std::io::Result<()> { println!( "Processing {} into {} ...", @@ -134,47 +144,56 @@ fn process_bodies( ); let mut n: u32 = 0; let mut wtr = csv::Writer::from_path(out_path)?; - process(path, &mut |line| { - if !line.contains("Star") { - return; - } - let body_res: Result = serde_json::from_str(&line); - if let Ok(body) = body_res { - if !body.body_type.contains("Star") { + process( + path, + &mut |line| { + if !line.contains("Star") { return; } - if let Some(sys) = systems.get(&body.systemId) { - let sub_type = body.subType; - let mult = get_mult(&sub_type); - let sys_name = sys.name.clone(); - let rec = SystemSerde { - id: n, - star_type: sub_type, - system: sys_name, - body: body.name, - mult, - distance: body.distance, - x: sys.coords.x, - y: sys.coords.y, - z: sys.coords.z, + let body_res: Result = serde_json::from_str(&line); + if let Ok(body) = body_res { + if !body.body_type.contains("Star") { + return; + } + if let Some(sys) = systems.get(&body.systemId) { + let sub_type = body.subType; + let mult = get_mult(&sub_type); + let sys_name = sys.name.clone(); + let rec = SystemSerde { + id: n, + star_type: sub_type, + system: sys_name, + body: body.name, + mult, + distance: body.distance, + x: sys.coords.x, + y: sys.coords.y, + z: sys.coords.z, + }; + wtr.serialize(rec).unwrap(); + n += 1; }; - wtr.serialize(rec).unwrap(); - n += 1; - }; - } else { - eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); - } - },callback) + } else { + eprintln!("\nError parsing: {}\n\t{:?}\n", line, body_res.unwrap_err()); + } + }, + callback, + ) .unwrap(); println!("Total Systems: {}", n); systems.clear(); Ok(()) } -pub fn preprocess_files(bodies: &PathBuf,systems:&PathBuf,out_path:&PathBuf,callback: Box PyResult>) -> std::io::Result<()> { +pub fn preprocess_files( + bodies: &PathBuf, + systems: &PathBuf, + out_path: &PathBuf, + callback: &dyn Fn(&PreprocessState) -> PyResult, +) -> std::io::Result<()> { if !out_path.exists() { - let mut systems = process_systems(systems,&callback); - process_bodies(bodies, out_path, &mut systems,&callback)?; + let mut systems = process_systems(systems, &callback); + process_bodies(bodies, out_path, &mut systems, &callback)?; } else { println!( "File '{}' exists, not overwriting it", diff --git a/rust/src/route.rs b/rust/src/route.rs index 5d58c40..3a7878f 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -104,6 +104,7 @@ impl System { pub fn dist2(&self, p: &[f32; 3]) -> f32 { dist2(&self.pos, p) } + pub fn distp(&self, p: &System) -> f32 { dist(&self.pos, &p.pos) } @@ -320,12 +321,12 @@ impl Router { return scoopable; } let df = src.distp(dst); - return (sys.distp(src) + sys.distp(dst)) < (df * (1.0 + self.radius_mult)); + (sys.distp(src) + sys.distp(dst)) < (df * (1.0 + self.radius_mult)) } pub fn best_multiroute( &self, - waypoints: &Vec, + waypoints: &[System], range: f32, keep: (bool, bool), mode: Mode, @@ -367,14 +368,14 @@ impl Router { pub fn multiroute( &self, - waypoints: &Vec, + waypoints: &[System], range: f32, mode: Mode, factor: f32, ) -> Result, String> { let mut route: Vec = Vec::new(); for pair in waypoints.windows(2) { - match pair.clone() { + match pair { [src, dst] => { let block = match mode { Mode::BFS => self.route_bfs(&src, &dst, range)?, @@ -423,13 +424,13 @@ impl Router { for ent in systems { match ent { SysEntry::ID(i) => match sys_by_id.get(i) { - Some(sys) => ret.push(sys.clone().clone()), + Some(sys) => ret.push((*sys).clone()), None => { return Err(format!("System: {:?} not found", ent)); } }, SysEntry::Name(n) => match sys_by_name.get(n) { - Some(sys) => ret.push(sys.clone().clone()), + Some(sys) => ret.push((*sys).clone()), None => { return Err(format!("System: {:?} not found", ent)); } @@ -509,9 +510,9 @@ impl Router { .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); - let d_g=nb.distp(goal_sys); - if d_g Result>, String> { }; let systems: Vec = router .resolve_systems(&opts.systems)? - .iter() - .map(|sys| sys.clone()) - .collect(); + .to_vec(); if opts.precompute { for sys in systems { router.route_tree = None; From 32e6e180e448f426594c71e6d5ce5f6911723cda Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 02:34:22 +0200 Subject: [PATCH 24/72] chore: Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13c14f2..f63bf32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Miscellaneous - Added changelog +- **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings From ce682a8866f302a60352333027e080f9df3e4f37 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 03:37:17 +0200 Subject: [PATCH 25/72] chore: Update changelog --- CHANGELOG.md | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f63bf32..31290c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,28 @@ ## [Unreleased] -### Bug Fixes -- **router:** Fixed some syntax errors created by botched merge - -### Features -- **GUI:** Implement route plotting and fuzzy search -- **GUI:** Add Download functionlaity, update Rust code, update Python code - ### Miscellaneous -- Added changelog - **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings - -## 0.0.0 - 2019-07-15 + +## [v0.2.1] - 2019-08-05 +### Bug Fixes +- **router:** Fixed some syntax errors created by botched merge -[Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/0.0.0...HEAD + + +## [v0.2.0] - 2019-08-05 +### Features +- **GUI:** Implement route plotting and fuzzy search + + + +## v0.1.0 - 2019-07-22 +### Features +- **GUI:** Add Download functionlaity, update Rust code, update Python code + + +[Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.1...HEAD +[v0.2.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.0...v0.2.0 From 66c510309fdd675c2d4aeb9bf50448aa20af5c67 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 03:43:37 +0200 Subject: [PATCH 26/72] chore: Update changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31290c4..c485f08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,11 +18,15 @@ -## v0.1.0 - 2019-07-22 +## [v0.1.0] - 2019-07-22 ### Features - **GUI:** Add Download functionlaity, update Rust code, update Python code + +## v0.0.0 - 2019-07-15 + [Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.1...HEAD [v0.2.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.0...v0.2.1 [v0.2.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.0...v0.2.0 +[v0.1.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.0.0...v0.1.0 From 87550a9ed538912c226059d3a78541c094bc2712 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 04:48:36 +0200 Subject: [PATCH 27/72] misc: Update changelog template to make conversion to PDF easier --- .chglog/CHANGELOG.tpl.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md index 0b655c2..c32cf05 100644 --- a/.chglog/CHANGELOG.tpl.md +++ b/.chglog/CHANGELOG.tpl.md @@ -1,5 +1,4 @@ {{ if .Versions -}} - ## [Unreleased] {{ if .Unreleased.CommitGroups -}} @@ -13,7 +12,6 @@ {{ end -}} {{ range .Versions }} - ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} {{ range .CommitGroups -}} ### {{ .Title }} From 7438043f26e6a4ef6514eb5eae9a75947ce6247b Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Mon, 5 Aug 2019 04:53:46 +0200 Subject: [PATCH 28/72] chore: Update changelog --- CHANGELOG.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c485f08..7d93a04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,29 +1,25 @@ - ## [Unreleased] ### Miscellaneous +- Update changelog template to make conversion to PDF easier - **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings - ## [v0.2.1] - 2019-08-05 ### Bug Fixes - **router:** Fixed some syntax errors created by botched merge - ## [v0.2.0] - 2019-08-05 ### Features - **GUI:** Implement route plotting and fuzzy search - ## [v0.1.0] - 2019-07-22 ### Features - **GUI:** Add Download functionlaity, update Rust code, update Python code - ## v0.0.0 - 2019-07-15 [Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.1...HEAD From dbc6f35ca2c910e35d45be613236fc07e0811918 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 02:50:48 +0200 Subject: [PATCH 29/72] docs: Add skeleton for documentation --- .gitignore | 1 + doc/.vscode/settings.json | 11 +++ doc/Makefile | 48 ++++++++++++ doc/filters/multifilter.py | 147 +++++++++++++++++++++++++++++++++++++ doc/src/ed-lrr.md | 58 +++++++++++++++ doc/src/img_out.py | 64 ++++++++++++++++ 6 files changed, 329 insertions(+) create mode 100644 doc/.vscode/settings.json create mode 100644 doc/Makefile create mode 100644 doc/filters/multifilter.py create mode 100644 doc/src/ed-lrr.md create mode 100644 doc/src/img_out.py diff --git a/.gitignore b/.gitignore index cfec1c9..f7b0fea 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ plot.py __pycache__ *.egg-info build +*.pdf \ No newline at end of file diff --git a/doc/.vscode/settings.json b/doc/.vscode/settings.json new file mode 100644 index 0000000..e674f84 --- /dev/null +++ b/doc/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "spellright.language": [ + "de", + "en" + ], + "spellright.documentTypes": [ + "markdown", + "latex", + "plaintext" + ] +} \ No newline at end of file diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..60a308c --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,48 @@ +MD = $(wildcard src/*.md) +DOTS = $(wildcard src/*.dot) +ASYS = $(wildcard src/*.asy) +PYS = $(wildcard src/img_*.py) +PDFS = $(MD:src/%.md=out/%.pdf) + +IMG_PDFS = $(ASYS:src/%.asy=img/%.pdf) $(PYS:src/img_%.py=img/%.pdf) $(DOTS:src/%.dot=img/%.pdf) + +IMGS = $(IMG_PDFS) + +TEMPLATE = eisvogel +PDF_ENGINE = xelatex +PANDOC = pandoc +PANDOC_OPTIONS = -F panflute -F pandoc-citeproc --pdf-engine=$(PDF_ENGINE) --template $(TEMPLATE) -N --standalone --listings + +GRAPHVIZ = dot +GRAPHVIZ_OPTIONS = -Tpdf + +ASY = asy +ASY_OPTIONS = -noV -f pdf + +PYTHON = python +PYTHON_OPTIONS = + +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path)))) + +.PHONY: clean all default +all: $(PDFS) +default: all + +out/%.pdf: src/%.md $(IMGS) Makefile + $(PANDOC) $(PANDOC_OPTIONS) -o $@ $< + +img/%.pdf: src/%.dot + $(GRAPHVIZ) $(GRAPHVIZ_OPTIONS) -o $@ $< + +img/%.pdf: src/img_%.py + $(PYTHON) $(PYTHON_OPTIONS) $< $@ + +img/%.pdf: src/%.asy + $(ASY) $(ASY_OPTIONS) -o $@ $< + +watch: + watchexec -w src -w data -w filters -w Makefile make all + +clean: + -rm $(PDFS) $(IMGS) \ No newline at end of file diff --git a/doc/filters/multifilter.py b/doc/filters/multifilter.py new file mode 100644 index 0000000..2cc9ff0 --- /dev/null +++ b/doc/filters/multifilter.py @@ -0,0 +1,147 @@ +from panflute import * +import tempfile +import sys +from jinja2 import Template, Environment, PackageLoader, select_autoescape +import contextlib +import io +import hashlib +from dateutil.parser import parse as dateparse +from functools import partial +import subprocess as SP +import panflute as pf +import os +import csv +import datetime +import re + + +def remove_pound(elem, doc): + if type(elem) == Str: + return Str(elem.text.lstrip("#")) + + +def fix_color(elem, doc): + if type(elem) == MetaMap: + for k in elem.content: + if k.endswith("-color"): + elem[k] = elem[k].walk(remove_pound) + + +def update_date(elem, doc): + if type(elem) == MetaMap: + datefmt = doc.get_metadata('datefmt', "%Y-%m-%d") + today = datetime.date.today().strftime(datefmt) + date = dateparse(doc.get_metadata('date', today)).date() + elem['date'] = MetaInlines(Str(date.strftime(datefmt))) + return elem + + +def csv_table(elem, doc): + if type(elem) == Para and len(elem.content) == 1 and type(elem.content[0]) == Image: + elem = elem.content[0] + ext = os.path.splitext(elem.url)[1][1:] + if ext == "csv": + caption = elem.content + has_header = elem.attributes.get( + 'has-header', "false").lower() == "true" + with open(elem.url) as f: + reader = csv.reader(f) + body = [] + for row in reader: + cells = [TableCell(Plain(Str(x))) for x in row] + body.append(TableRow(*cells)) + header = body.pop(0) if has_header else None + ret = Table(*body, header=header, caption=caption) + return ret + + +def code_refs(elem, doc): + if type(elem) == Cite: + label = elem.content[0] + if type(label) == Str: + label = label.text + filename = re.findall(r"^\[@lst:(.*)\]$", label) or [None] + if filename[0] in doc.inc_files: + return [RawInline("\\hyperref[{}]{{{}}}".format(filename[0], filename[0]), format="tex")] + + +def include_code(elem, doc): + if type(elem) == CodeBlock: + if "include" in elem.attributes: + filepath = elem.attributes.pop("include") + filename = os.path.split(filepath)[-1] + try: + elem.text += elem.text + \ + open(filepath, encoding="utf-8").read() + elem.attributes['caption'] = filename + doc.inc_files.append(filename) + except Exception as e: + elem.text += "Error: {}".format(e) + return [RawBlock("\\label{{{}}}".format(filename), format="tex"), elem] + + +def py_eval(options, data, element, doc): + out_buffer = io.StringIO() + with contextlib.redirect_stdout(out_buffer): + exec(data, doc.pyenv) + out_buffer.seek(0) + return convert_text(out_buffer.read()) + + +def jinja_py_filt(doc, file): + env = {} + code = open(file, encoding="utf-8").read() + exec(code, env) + return env['main'](doc) + + +def prepare(doc): + doc.inc_files = [] + doc.env = Environment() + doc.pyenv = {} + filters = {'py': partial(jinja_py_filt, doc)} + doc.env.filters.update(filters) + + +def process_templates(elem, doc): + if type(elem) == CodeBlock: + if elem.classes == ["@"]: + args = {'meta': doc.get_metadata()} + return convert_text(doc.env.from_string(elem.text).render(args)) + + +def yaml_filt(elem, doc): + tags = { + 'eval': py_eval, + } + return yaml_filter(elem, doc, tags=tags, strict_yaml=True) + + +def checkboxes(elem, doc): + if type(elem) in [Para, Plain]: + val = re.findall(r"^\[([xX]|\ )\] (.*)$", stringify(elem)) + if val: + val = val[0][0].lower() == "x" + else: + return elem + marker = { + True: RawInline("$\\boxtimes$", format="latex"), + False: RawInline("$\\square$", format="latex"), + }[val] + cont = [] + if val: + cont += elem.content[2:] + else: + cont += elem.content[4:] + return Plain(marker, Space, *cont) + return elem + + +def main(doc=None): + f = [process_templates, update_date, csv_table, include_code, + fix_color, code_refs, yaml_filt, checkboxes] + return run_filters(f, prepare=prepare, doc=doc) + + +if __name__ == "__main__": + main() diff --git a/doc/src/ed-lrr.md b/doc/src/ed-lrr.md new file mode 100644 index 0000000..4d8b295 --- /dev/null +++ b/doc/src/ed-lrr.md @@ -0,0 +1,58 @@ +--- +# Metadata +title: ED_LRR +author: +- Daniel Seiller +subtitle: 'Elite Dangerous: Long-Range Router' + +# Formating +toc: true +lang: en +colorlinks: true +papersize: a4 +numbersections: true + +#Panflute options +panflute-filters: [multifilter] +panflute-path: 'filters' + +#Template options +titlepage: true +toc-own-page: false +--- + +# How it works + +## `stars.csv` format + +### Columns + +| Name | Content | +| --------- | ------------------------------------------------------------------- | +| id | unique ID-Number (not to be confused with EDSM id or id64) | +| star_type | Type of Star | +| system | Name of System | +| body | Name of Star | +| mult | Jump Range Multiplier (1.5 for White Dwarfs, 4.0 for Neutron Stars) | +| distance | Distance from arrival in Ls | +| x,y,z | Position in Galactic Coordinates with Sol at (0,0,0) | + +## Routing Algorithms + +### Breadth-First Search (BFS) + +### A*-Search + +### Greedy Search + +## Optimizations + +## Routing Graphs + +# Usage + +## Preprocessing Data + +## Plotting a Route + +# [Changelog](https://gitlab.com/Earthnuker/ed_lrr/blob/pyqt_gui/CHANGELOG.md) diff --git a/doc/src/img_out.py b/doc/src/img_out.py new file mode 100644 index 0000000..7179b78 --- /dev/null +++ b/doc/src/img_out.py @@ -0,0 +1,64 @@ +import sys +import pylab as PL +import numpy as np +from scipy.spatial.ckdtree import cKDTree +import heapq + +exit() + + +def vec(a, b): + return b - a + + +def bfs(points): + return + + +def in_ellipse(p, f1, f2, r, offset=0): + df = ((f1 - f2) ** 2).sum(0) ** 0.5 + d_f1 = ((p - f1) ** 2).sum(1) ** 0.5 + d_f2 = ((p - f2) ** 2).sum(1) ** 0.5 + return (d_f1 + d_f2) < (df * (1 + r)) + + +num_points = 100000 + +p_orig = np.random.normal(0, 10, size=(num_points, 2)) +tree = cKDTree(p_orig) +f1 = np.array([0, -30]) +f2 = -f1 # np.random.normal(0, 20, (3,)) +# r = 2 ** ((n / cnt) - cnt) + +mask = in_ellipse(p_orig, f1, f2, 0.1) + +p = p_orig[mask] +p_orig = p_orig[~mask] + +colors = np.random.random(p.shape[0]) +fig = PL.gcf() +PL.scatter( + p_orig[:, 0], + p_orig[:, 1], + marker=".", + s=0.2, + edgecolor="None", + c=[(0.0, 0.0, 0.0)], + alpha=0.75, + rasterized=True, +) +PL.scatter( + p[:, 0], p[:, 1], marker="s", s=0.2, edgecolor="None", c=colors, rasterized=True +) +PL.plot(f1[0], f1[1], "r.", label="Source") +PL.plot(f2[0], f2[1], "g.", label="Destination") + +max_v = max(p_orig[:, 0].max(), p_orig[:, 1].max(), f1[0], f1[1], f2[0], f2[1]) + 2 +min_v = min(p_orig[:, 0].min(), p_orig[:, 1].min(), f1[0], f1[1], f2[0], f2[1]) - 2 + + +PL.xlim(min_v, max_v) +PL.ylim(min_v, max_v) + +PL.legend() +PL.savefig(sys.argv[1], dpi=1200) From 45570161d4751e1f8a507e943af3a22b0b82348b Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 02:51:56 +0200 Subject: [PATCH 30/72] chore: Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d93a04..0b8a5f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## [Unreleased] +### Documentation +- Add skeleton for documentation + ### Miscellaneous - Update changelog template to make conversion to PDF easier - **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings From fb54bdaf0cb17d2997510ec8e9176cc20e1cb7b2 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 03:02:47 +0200 Subject: [PATCH 31/72] docs: Rename `doc` folder to `docs`, update outline --- {doc => docs}/.vscode/settings.json | 0 {doc => docs}/Makefile | 0 {doc => docs}/filters/multifilter.py | 0 {doc => docs}/src/ed-lrr.md | 2 ++ {doc => docs}/src/img_out.py | 0 5 files changed, 2 insertions(+) rename {doc => docs}/.vscode/settings.json (100%) rename {doc => docs}/Makefile (100%) rename {doc => docs}/filters/multifilter.py (100%) rename {doc => docs}/src/ed-lrr.md (94%) rename {doc => docs}/src/img_out.py (100%) diff --git a/doc/.vscode/settings.json b/docs/.vscode/settings.json similarity index 100% rename from doc/.vscode/settings.json rename to docs/.vscode/settings.json diff --git a/doc/Makefile b/docs/Makefile similarity index 100% rename from doc/Makefile rename to docs/Makefile diff --git a/doc/filters/multifilter.py b/docs/filters/multifilter.py similarity index 100% rename from doc/filters/multifilter.py rename to docs/filters/multifilter.py diff --git a/doc/src/ed-lrr.md b/docs/src/ed-lrr.md similarity index 94% rename from doc/src/ed-lrr.md rename to docs/src/ed-lrr.md index 4d8b295..be4e17d 100644 --- a/doc/src/ed-lrr.md +++ b/docs/src/ed-lrr.md @@ -37,6 +37,8 @@ toc-own-page: false | distance | Distance from arrival in Ls | | x,y,z | Position in Galactic Coordinates with Sol at (0,0,0) | +## `stars.idx` format + ## Routing Algorithms ### Breadth-First Search (BFS) diff --git a/doc/src/img_out.py b/docs/src/img_out.py similarity index 100% rename from doc/src/img_out.py rename to docs/src/img_out.py From 714741a885a10a38cead0ae96bc9f8102e0ab2ff Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 03:24:17 +0200 Subject: [PATCH 32/72] docs: Update documentation to include basic description --- docs/src/ed-lrr.md | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/src/ed-lrr.md b/docs/src/ed-lrr.md index be4e17d..64566fa 100644 --- a/docs/src/ed-lrr.md +++ b/docs/src/ed-lrr.md @@ -21,7 +21,7 @@ titlepage: true toc-own-page: false --- -# How it works +# Implementation ## `stars.csv` format @@ -39,20 +39,50 @@ toc-own-page: false ## `stars.idx` format +`bincode` serialized data: + +- **[u64]**: List of byte offset for records (entry 0=first recod, entry 1= second record, etc) + ## Routing Algorithms ### Breadth-First Search (BFS) +Standard Breadth-First Search, always finds the shortest route + ### A*-Search -### Greedy Search +Modified A-Star search with tunable "greediness". Candidates weighted by $\text{number of jumps from start system} + (\text{estimated number of jumps to target system} * \text{greediness})$ + +A greediness of 0 is equivalent to BFS and a greediness of $\infty$ is equivalent to Greedy-Search + +### Greedy-Search + +Priority Queue weighted by minimum distance to target, prefers systems with high multiplier (Neutron Stars and White Dwarfs) ## Optimizations +### Ellipse elimination + +Only consider systems within an ellipsoid with source and destination as the foci, the width of the ellipsoid is adjustable + ## Routing Graphs +### File format + +`bincode` serialized data: + +- *bool* **primary**: flag to indicate that graph only includes primary stars +- *f32* **range**: jump range for routing graph +- *[u8]* **file_hash**: sha3 hash of `stars.csv` from which graph was generated +- *String* **path**: path to `stars.csv` from which graph was generated +- *FnvHashMap* **graph**: Hashmap mapping systems to the systems from which they can be rached, traversed from destination system backwards to source to reconstruct route + # Usage + + ## Preprocessing Data ## Plotting a Route From f027e020512b7598896524f930dbdf60f42f6c38 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 03:27:50 +0200 Subject: [PATCH 33/72] docs: Insert page break after table of contents --- docs/src/ed-lrr.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/ed-lrr.md b/docs/src/ed-lrr.md index 64566fa..7a4a234 100644 --- a/docs/src/ed-lrr.md +++ b/docs/src/ed-lrr.md @@ -21,6 +21,8 @@ titlepage: true toc-own-page: false --- +\pagebreak + # Implementation ## `stars.csv` format From 8ee20a141048250185a13a505e3821ae5785b525 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 03:33:25 +0200 Subject: [PATCH 34/72] chore: Update changelog --- .chglog/config.yml | 12 +++++++++++- CHANGELOG.md | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.chglog/config.yml b/.chglog/config.yml index d86cb03..7a42b92 100644 --- a/.chglog/config.yml +++ b/.chglog/config.yml @@ -4,8 +4,18 @@ info: title: CHANGELOG repository_url: https://gitlab.com/Earthnuker/ed_lrr options: + commits: + filters: + Type: + - feat + - fix + - perf + - refactor + - misc + - other + - docs commit_groups: - title_maps: + title_maps: feat: Features fix: Bug Fixes perf: Performance Improvements diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b8a5f5..4264e4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## [Unreleased] ### Documentation +- Insert pagebreak after table of contents +- Update documentation to include basic description +- Rename `doc` folder to `docs`, update outline - Add skeleton for documentation ### Miscellaneous From 9fa0644a54309c359f558e19562a9d08b87a31ee Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 03:36:37 +0200 Subject: [PATCH 35/72] chore: fix typo in changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4264e4a..d97e0b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## [Unreleased] ### Documentation -- Insert pagebreak after table of contents +- Insert page break after table of contents - Update documentation to include basic description - Rename `doc` folder to `docs`, update outline - Add skeleton for documentation @@ -23,7 +23,7 @@ ## [v0.1.0] - 2019-07-22 ### Features -- **GUI:** Add Download functionlaity, update Rust code, update Python code +- **GUI:** Add Download functionality, update Rust code, update Python code ## v0.0.0 - 2019-07-15 From 3846a6b89a9688ef43f57d9430db7fade1afecfd Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 03:38:43 +0200 Subject: [PATCH 36/72] chore: Add license --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ea8c62e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Daniel Seiller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From 922b99337a270a0bd568b7cbf029815494d47d8f Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 23:50:34 +0200 Subject: [PATCH 37/72] chore(changelog): Add link to commit to changelog --- .chglog/CHANGELOG.tpl.md | 80 ++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md index c32cf05..510e88b 100644 --- a/.chglog/CHANGELOG.tpl.md +++ b/.chglog/CHANGELOG.tpl.md @@ -1,40 +1,40 @@ -{{ if .Versions -}} -## [Unreleased] - -{{ if .Unreleased.CommitGroups -}} -{{ range .Unreleased.CommitGroups -}} -### {{ .Title }} -{{ range .Commits -}} -- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} -{{ end }} -{{ end -}} -{{ end -}} -{{ end -}} - -{{ range .Versions }} -## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} -{{ range .CommitGroups -}} -### {{ .Title }} -{{ range .Commits -}} -- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} -{{ end }} -{{ end -}} - -{{- if .NoteGroups -}} -{{ range .NoteGroups -}} -### {{ .Title }} -{{ range .Notes }} -{{ .Body }} -{{ end }} -{{ end -}} -{{ end -}} -{{ end -}} - -{{- if .Versions }} -[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD -{{ range .Versions -}} -{{ if .Tag.Previous -}} -[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} -{{ end -}} -{{ end -}} -{{ end -}} \ No newline at end of file +{{ if .Versions -}} +## [Unreleased] + +{{ if .Unreleased.CommitGroups -}} +{{ range .Unreleased.CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} [{{.Hash.Short}}]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Short }}) +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{ range .Versions }} +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} +{{ range .CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} [{{.Hash.Short}}]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Short }}) +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{- if .Versions }} +[Unreleased]: {{ $.Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD +{{ range .Versions -}} +{{ if .Tag.Previous -}} +[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} +{{ end -}} +{{ end -}} +{{ end -}} From 2e604a4281e04f2b6134ca6f79cd1cdbe1f40e29 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 6 Aug 2019 23:52:18 +0200 Subject: [PATCH 38/72] chore(changelog): Update changelog --- CHANGELOG.md | 68 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d97e0b8..357c26b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,34 +1,34 @@ -## [Unreleased] - -### Documentation -- Insert page break after table of contents -- Update documentation to include basic description -- Rename `doc` folder to `docs`, update outline -- Add skeleton for documentation - -### Miscellaneous -- Update changelog template to make conversion to PDF easier -- **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings - - -## [v0.2.1] - 2019-08-05 -### Bug Fixes -- **router:** Fixed some syntax errors created by botched merge - - -## [v0.2.0] - 2019-08-05 -### Features -- **GUI:** Implement route plotting and fuzzy search - - -## [v0.1.0] - 2019-07-22 -### Features -- **GUI:** Add Download functionality, update Rust code, update Python code - - -## v0.0.0 - 2019-07-15 - -[Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.1...HEAD -[v0.2.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.0...v0.2.1 -[v0.2.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.0...v0.2.0 -[v0.1.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.0.0...v0.1.0 +## [Unreleased] + +### Documentation +- Insert page break after table of contents [f027e02](https://gitlab.com/Earthnuker/ed_lrr/commit/f027e02) +- Update documentation to include basic description [714741a](https://gitlab.com/Earthnuker/ed_lrr/commit/714741a) +- Rename `doc` folder to `docs`, update outline [fb54bda](https://gitlab.com/Earthnuker/ed_lrr/commit/fb54bda) +- Add skeleton for documentation [dbc6f35](https://gitlab.com/Earthnuker/ed_lrr/commit/dbc6f35) + +### Miscellaneous +- Update changelog template to make conversion to PDF easier [87550a9](https://gitlab.com/Earthnuker/ed_lrr/commit/87550a9) +- **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings [fb3f79b](https://gitlab.com/Earthnuker/ed_lrr/commit/fb3f79b) + + +## [v0.2.1] - 2019-08-05 +### Bug Fixes +- **router:** Fixed some syntax errors created by botched merge [4b14643](https://gitlab.com/Earthnuker/ed_lrr/commit/4b14643) + + +## [v0.2.0] - 2019-08-05 +### Features +- **GUI:** Implement route plotting and fuzzy search [c290d5e](https://gitlab.com/Earthnuker/ed_lrr/commit/c290d5e) + + +## [v0.1.0] - 2019-07-22 +### Features +- **GUI:** Add Download functionality, update Rust code, update Python code [ec3972b](https://gitlab.com/Earthnuker/ed_lrr/commit/ec3972b) + + +## v0.0.0 - 2019-07-15 + +[Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.1...HEAD +[v0.2.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.0...v0.2.0 +[v0.1.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.0.0...v0.1.0 From 81da25441982e52ee513d2d2d9c8f7b8b38d09fe Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 31 Aug 2019 22:17:42 +0200 Subject: [PATCH 39/72] chore: Remove git stash markup --- ed_lrr_gui/__main__.py | 4 +-- ed_lrr_gui/gui/ed_lrr.py | 67 --------------------------------------- ed_lrr_gui/gui/ed_lrr.ui | 62 ------------------------------------ rust/.vscode/arduino.json | 5 +++ rust/src/lib.rs | 4 +-- test_gui.bat | 2 +- 6 files changed, 9 insertions(+), 135 deletions(-) create mode 100644 rust/.vscode/arduino.json diff --git a/ed_lrr_gui/__main__.py b/ed_lrr_gui/__main__.py index c03221f..153f408 100644 --- a/ed_lrr_gui/__main__.py +++ b/ed_lrr_gui/__main__.py @@ -141,11 +141,11 @@ class DownloadThread(QThread): self.running = False def run(self): - jobs = [ + dl_jobs = [ (self.systems_url, self.systems_file), (self.bodies_url, self.bodies_file), ] - for url, dest in jobs: + for url, dest in dl_jobs: outfile = url.split("/")[-1] size = RQ.head(url, headers={"Accept-Encoding": "None"}) size.raise_for_status() diff --git a/ed_lrr_gui/gui/ed_lrr.py b/ed_lrr_gui/gui/ed_lrr.py index 721546f..c33b639 100644 --- a/ed_lrr_gui/gui/ed_lrr.py +++ b/ed_lrr_gui/gui/ed_lrr.py @@ -26,14 +26,11 @@ class Ui_ED_LRR(object): ED_LRR.setDocumentMode(False) ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded) self.centralwidget = QtWidgets.QWidget(ED_LRR) -<<<<<<< Updated upstream -======= sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) self.centralwidget.setSizePolicy(sizePolicy) ->>>>>>> Stashed changes self.centralwidget.setObjectName("centralwidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName("verticalLayout") @@ -222,12 +219,6 @@ class Ui_ED_LRR(object): self.rd_precomp.setObjectName("rd_precomp") self.gr_mode.addWidget(self.rd_precomp, 0, 2, 1, 1) self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode) -<<<<<<< Updated upstream - self.btn_permute = QtWidgets.QPushButton(self.tab_route) - self.btn_permute.setObjectName("btn_permute") - self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btn_permute) -======= ->>>>>>> Stashed changes self.lst_sys = QtWidgets.QTreeWidget(self.tab_route) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -242,18 +233,6 @@ class Ui_ED_LRR(object): self.lst_sys.setAlternatingRowColors(True) self.lst_sys.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.lst_sys.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) -<<<<<<< Updated upstream - self.lst_sys.setHeaderHidden(True) - self.lst_sys.setObjectName("lst_sys") - self.lst_sys.headerItem().setText(0, "1") - self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.SpanningRole, self.lst_sys) - self.sb_range = QtWidgets.QDoubleSpinBox(self.tab_route) - self.sb_range.setObjectName("sb_range") - self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.sb_range) - self.lbl_range = QtWidgets.QLabel(self.tab_route) - self.lbl_range.setObjectName("lbl_range") - self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.lbl_range) -======= self.lst_sys.setHeaderHidden(False) self.lst_sys.setObjectName("lst_sys") self.lst_sys.headerItem().setText(0, "Name") @@ -265,7 +244,6 @@ class Ui_ED_LRR(object): self.lbl_range = QtWidgets.QLabel(self.tab_route) self.lbl_range.setObjectName("lbl_range") self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.lbl_range) ->>>>>>> Stashed changes self.gr_opts = QtWidgets.QGridLayout() self.gr_opts.setObjectName("gr_opts") self.cmb_mode = QtWidgets.QComboBox(self.tab_route) @@ -293,28 +271,16 @@ class Ui_ED_LRR(object): self.lbl_mode = QtWidgets.QLabel(self.tab_route) self.lbl_mode.setObjectName("lbl_mode") self.gr_opts.addWidget(self.lbl_mode, 0, 1, 1, 1) -<<<<<<< Updated upstream - self.formLayout_2.setLayout(9, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) - self.btn_go = QtWidgets.QPushButton(self.tab_route) - self.btn_go.setFlat(False) - self.btn_go.setObjectName("btn_go") - self.formLayout_2.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.btn_go) -======= self.formLayout_2.setLayout(10, QtWidgets.QFormLayout.SpanningRole, self.gr_opts) self.btn_go = QtWidgets.QPushButton(self.tab_route) self.btn_go.setFlat(False) self.btn_go.setObjectName("btn_go") self.formLayout_2.setWidget(11, QtWidgets.QFormLayout.LabelRole, self.btn_go) ->>>>>>> Stashed changes self.gridLayout_4 = QtWidgets.QGridLayout() self.gridLayout_4.setObjectName("gridLayout_4") self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route) self.chk_permute_keep_last.setObjectName("chk_permute_keep_last") -<<<<<<< Updated upstream - self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 2, 1, 1) -======= self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 3, 1, 1) ->>>>>>> Stashed changes self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -323,11 +289,7 @@ class Ui_ED_LRR(object): self.chk_permute_keep_first.setSizePolicy(sizePolicy) self.chk_permute_keep_first.setTristate(False) self.chk_permute_keep_first.setObjectName("chk_permute_keep_first") -<<<<<<< Updated upstream - self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 1, 1, 1) -======= self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 2, 1, 1) ->>>>>>> Stashed changes self.lbl_keep = QtWidgets.QLabel(self.tab_route) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -335,10 +297,6 @@ class Ui_ED_LRR(object): sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth()) self.lbl_keep.setSizePolicy(sizePolicy) self.lbl_keep.setObjectName("lbl_keep") -<<<<<<< Updated upstream - self.gridLayout_4.addWidget(self.lbl_keep, 0, 0, 1, 1) - self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4) -======= self.gridLayout_4.addWidget(self.lbl_keep, 0, 1, 1, 1) self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4) self.chk_permute = QtWidgets.QCheckBox(self.tab_route) @@ -347,7 +305,6 @@ class Ui_ED_LRR(object): self.btn_search = QtWidgets.QPushButton(self.tab_route) self.btn_search.setObjectName("btn_search") self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btn_search) ->>>>>>> Stashed changes self.tabs.addTab(self.tab_route, "") self.tab_log = QtWidgets.QWidget() self.tab_log.setObjectName("tab_log") @@ -369,23 +326,16 @@ class Ui_ED_LRR(object): self.menu.setObjectName("menu") self.menu_file = QtWidgets.QMenu(self.menu) self.menu_file.setObjectName("menu_file") -<<<<<<< Updated upstream -======= self.menuWindow = QtWidgets.QMenu(self.menu) self.menuWindow.setObjectName("menuWindow") self.menuStyle = QtWidgets.QMenu(self.menuWindow) self.menuStyle.setObjectName("menuStyle") ->>>>>>> Stashed changes ED_LRR.setMenuBar(self.menu) self.bar_status = QtWidgets.QStatusBar(ED_LRR) self.bar_status.setObjectName("bar_status") ED_LRR.setStatusBar(self.bar_status) self.menu_act_quit = QtWidgets.QAction(ED_LRR) self.menu_act_quit.setObjectName("menu_act_quit") -<<<<<<< Updated upstream - self.menu_file.addAction(self.menu_act_quit) - self.menu.addAction(self.menu_file.menuAction()) -======= self.actionA = QtWidgets.QAction(ED_LRR) self.actionA.setObjectName("actionA") self.actionB = QtWidgets.QAction(ED_LRR) @@ -394,7 +344,6 @@ class Ui_ED_LRR(object): self.menuWindow.addAction(self.menuStyle.menuAction()) self.menu.addAction(self.menu_file.menuAction()) self.menu.addAction(self.menuWindow.menuAction()) ->>>>>>> Stashed changes self.retranslateUi(ED_LRR) self.tabs.setCurrentIndex(2) @@ -428,20 +377,12 @@ class Ui_ED_LRR(object): self.tabs.setTabText(self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess")) self.lbl_sys_lst.setText(_translate("ED_LRR", "System List")) self.btn_sys_lst_browse.setText(_translate("ED_LRR", "...")) -<<<<<<< Updated upstream - self.btn_add.setText(_translate("ED_LRR", "Search+Add")) -======= self.btn_add.setText(_translate("ED_LRR", "Add")) ->>>>>>> Stashed changes self.inp_sys.setPlaceholderText(_translate("ED_LRR", "System Name")) self.btn_rm.setText(_translate("ED_LRR", "Remove")) self.rd_comp.setText(_translate("ED_LRR", "Compute Route")) self.rd_precomp.setText(_translate("ED_LRR", "Precompute Graph")) -<<<<<<< Updated upstream - self.btn_permute.setText(_translate("ED_LRR", "Permute")) -======= self.lst_sys.headerItem().setText(1, _translate("ED_LRR", "Type")) ->>>>>>> Stashed changes self.lbl_range.setText(_translate("ED_LRR", "Jump Range (Ly)")) self.cmb_mode.setCurrentText(_translate("ED_LRR", "Breadth-First Search")) self.cmb_mode.setItemText(0, _translate("ED_LRR", "Breadth-First Search")) @@ -454,13 +395,6 @@ class Ui_ED_LRR(object): self.chk_permute_keep_last.setText(_translate("ED_LRR", "Last")) self.chk_permute_keep_first.setText(_translate("ED_LRR", "First")) self.lbl_keep.setText(_translate("ED_LRR", "Keep Endpoints:")) -<<<<<<< Updated upstream - self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) - self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")) - self.menu_file.setTitle(_translate("ED_LRR", "File")) - self.menu_act_quit.setText(_translate("ED_LRR", "Quit")) - self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q")) -======= self.chk_permute.setText(_translate("ED_LRR", "Permute")) self.btn_search.setText(_translate("ED_LRR", "Search All")) self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) @@ -472,4 +406,3 @@ class Ui_ED_LRR(object): self.menu_act_quit.setShortcut(_translate("ED_LRR", "Ctrl+Q")) self.actionA.setText(_translate("ED_LRR", "A")) self.actionB.setText(_translate("ED_LRR", "B")) ->>>>>>> Stashed changes diff --git a/ed_lrr_gui/gui/ed_lrr.ui b/ed_lrr_gui/gui/ed_lrr.ui index 4685221..9872cd0 100644 --- a/ed_lrr_gui/gui/ed_lrr.ui +++ b/ed_lrr_gui/gui/ed_lrr.ui @@ -44,15 +44,12 @@ QTabWidget::Rounded -<<<<<<< Updated upstream -======= 0 0 ->>>>>>> Stashed changes @@ -372,11 +369,7 @@ -<<<<<<< Updated upstream - Search+Add -======= Add ->>>>>>> Stashed changes @@ -415,16 +408,6 @@ -<<<<<<< Updated upstream - - - - Permute - - - -======= ->>>>>>> Stashed changes @@ -461,13 +444,6 @@ QAbstractItemView::SelectRows -<<<<<<< Updated upstream - true - - - - 1 -======= false @@ -481,33 +457,21 @@ Type ->>>>>>> Stashed changes -<<<<<<< Updated upstream - - - - -======= ->>>>>>> Stashed changes Jump Range (Ly) -<<<<<<< Updated upstream - -======= ->>>>>>> Stashed changes @@ -579,11 +543,7 @@ -<<<<<<< Updated upstream - -======= ->>>>>>> Stashed changes GO! @@ -595,22 +555,14 @@ -<<<<<<< Updated upstream - -======= ->>>>>>> Stashed changes Last -<<<<<<< Updated upstream - -======= ->>>>>>> Stashed changes @@ -626,11 +578,7 @@ -<<<<<<< Updated upstream - -======= ->>>>>>> Stashed changes @@ -645,8 +593,6 @@ -<<<<<<< Updated upstream -======= @@ -661,7 +607,6 @@ ->>>>>>> Stashed changes @@ -709,9 +654,6 @@ -<<<<<<< Updated upstream - -======= Window @@ -725,7 +667,6 @@ ->>>>>>> Stashed changes @@ -736,8 +677,6 @@ Ctrl+Q -<<<<<<< Updated upstream -======= A @@ -748,7 +687,6 @@ B ->>>>>>> Stashed changes rd_comp diff --git a/rust/.vscode/arduino.json b/rust/.vscode/arduino.json new file mode 100644 index 0000000..21580ea --- /dev/null +++ b/rust/.vscode/arduino.json @@ -0,0 +1,5 @@ +{ + "board": "esp8266:esp8266:huzzah", + "configuration": "CpuFrequency=80,FlashSize=4M1M,LwIPVariant=v2mss536,Debug=Disabled,DebugLevel=None____,UploadSpeed=115200", + "port": "COM3" +} \ No newline at end of file diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 9b82f91..43bf006 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -100,9 +100,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { } Ok(ret.to_object(py)) } - Err(e) => { - Err(PyErr::new::(e)) - } + Err(e) => Err(PyErr::new::(e)), } } diff --git a/test_gui.bat b/test_gui.bat index 74e1f6e..5051fac 100644 --- a/test_gui.bat +++ b/test_gui.bat @@ -1 +1 @@ -python build_gui.py && ed_lrr_gui \ No newline at end of file +python build_gui.py && python ed_lrr_gui/__main__.py \ No newline at end of file From 4a392d9c87c77a249b152179fec8a715836f597d Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 31 Aug 2019 23:41:51 +0200 Subject: [PATCH 40/72] fix(setup): fix setup script to include subdirectories --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 8137fb5..20e467c 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup +from setuptools import setup,find_packages from setuptools_rust import Binding, RustExtension, Strip setup( @@ -16,7 +16,7 @@ setup( native=True, ) ], - packages=["ed_lrr_gui"], + packages=find_packages(), entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, install_requires=[ "PyQt5", From 3cab492a59625fde71b054192b71cbbbe95e6f38 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 31 Aug 2019 23:42:37 +0200 Subject: [PATCH 41/72] chore: remove arduino config generates by VS Code for ... some reason --- .gitignore | 4 +++- rust/.vscode/arduino.json | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 rust/.vscode/arduino.json diff --git a/.gitignore b/.gitignore index f7b0fea..db638e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ rust/target +rust/.history/ **/*.rs.bk *.tmp *.idx @@ -12,4 +13,5 @@ plot.py __pycache__ *.egg-info build -*.pdf \ No newline at end of file +*.pdf +.history \ No newline at end of file diff --git a/rust/.vscode/arduino.json b/rust/.vscode/arduino.json deleted file mode 100644 index 21580ea..0000000 --- a/rust/.vscode/arduino.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "board": "esp8266:esp8266:huzzah", - "configuration": "CpuFrequency=80,FlashSize=4M1M,LwIPVariant=v2mss536,Debug=Disabled,DebugLevel=None____,UploadSpeed=115200", - "port": "COM3" -} \ No newline at end of file From 377991164b35726f2b19db90b988ba6bc5ea3557 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 31 Aug 2019 23:43:52 +0200 Subject: [PATCH 42/72] docs: small wording change --- docs/src/ed-lrr.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/src/ed-lrr.md b/docs/src/ed-lrr.md index 7a4a234..90af66b 100644 --- a/docs/src/ed-lrr.md +++ b/docs/src/ed-lrr.md @@ -29,15 +29,15 @@ toc-own-page: false ### Columns -| Name | Content | -| --------- | ------------------------------------------------------------------- | -| id | unique ID-Number (not to be confused with EDSM id or id64) | -| star_type | Type of Star | -| system | Name of System | -| body | Name of Star | +| Name | Content | +| --------- | ------------------------------------------------------------ | +| id | unique ID-Number (not equal to id or id64, just a sequential number) | +| star_type | Type of Star | +| system | Name of System | +| body | Name of Star | | mult | Jump Range Multiplier (1.5 for White Dwarfs, 4.0 for Neutron Stars) | -| distance | Distance from arrival in Ls | -| x,y,z | Position in Galactic Coordinates with Sol at (0,0,0) | +| distance | Distance from arrival in Ls | +| x,y,z | Position in Galactic Coordinates with Sol at (0,0,0) | ## `stars.idx` format @@ -53,7 +53,7 @@ Standard Breadth-First Search, always finds the shortest route ### A*-Search -Modified A-Star search with tunable "greediness". Candidates weighted by $\text{number of jumps from start system} + (\text{estimated number of jumps to target system} * \text{greediness})$ +Modified A*-Search with adjustable "greediness". Priority Queue weighted by $\text{number of jumps from start system} + (\text{estimated number of jumps to target system} * \text{greediness})$ A greediness of 0 is equivalent to BFS and a greediness of $\infty$ is equivalent to Greedy-Search From 865889712e1429e156e433597fec9ec603fcd810 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 31 Aug 2019 23:45:30 +0200 Subject: [PATCH 43/72] chore: gitignore pip-wheel-metadata --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index db638e7..5b0dd33 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ __pycache__ *.egg-info build *.pdf -.history \ No newline at end of file +.history +pip-wheel-metadata \ No newline at end of file From 2636ecbdb9ada97439629afb3c6933081db0106d Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 17:40:56 +0200 Subject: [PATCH 44/72] chore: Setup tox+appveyor, refomat python code, prepare rust code to add branch pruning to search --- .appveyor.yml | 23 ++ .cargo/config | 2 + .gitignore | 3 +- LICENSE | 2 +- MANIFEST.in | 2 +- Pipfile | 12 + README.md | 10 +- appveyor.yml | 23 ++ build.bat | 21 +- build.py | 66 ++++ clean.bat | 2 +- docs/.vscode/settings.json | 2 +- docs/Makefile | 2 +- docs/filters/multifilter.py | 66 ++-- docs/src/img_out.py | 9 +- ed_lrr_gui/__init__.py | 4 +- ed_lrr_gui/__main__.py | 641 ++++++------------------------------ ed_lrr_gui/config.py | 3 +- ed_lrr_gui/gui/__init__.py | 1 + ed_lrr_gui/gui/ed_lrr.py | 2 +- ed_lrr_gui/gui/main.py | 546 ++++++++++++++++++++++++++++++ ed_lrr_gui/preprocess.py | 7 +- ed_lrr_gui/router.py | 14 +- icon/icon.ico | Bin 0 -> 376773 bytes icon/make.py | 115 +++++++ icon/out/icon_1.svg | 2 + icon/out/icon_1_small.svg | 2 + installer/ED_LRR.iss | 22 ++ rust/.cargo/config | 2 +- rust/Cargo.lock | 392 +++++++--------------- rust/Cargo.toml | 59 ++-- rust/src/lib.rs | 7 +- rust/src/route.rs | 37 ++- setup.py | 40 ++- tox.ini | 30 ++ 35 files changed, 1245 insertions(+), 926 deletions(-) create mode 100644 .appveyor.yml create mode 100644 .cargo/config create mode 100644 Pipfile create mode 100644 appveyor.yml create mode 100644 build.py create mode 100644 ed_lrr_gui/gui/main.py create mode 100644 icon/icon.ico create mode 100644 icon/make.py create mode 100644 icon/out/icon_1.svg create mode 100644 icon/out/icon_1_small.svg create mode 100644 installer/ED_LRR.iss create mode 100644 tox.ini diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..7ccaef9 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,23 @@ +image: Visual Studio 2019 +platform: x64 +version: 0.1.{build} +branches: + only: + - pyqt_gui + +environment: + VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat + VCVARSARG: x64 + +install: + - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc + - pip install tox + + +before_build: + - if defined VCVARS call "%VCVARS%" %VCVARSARG% + - conda activate + +test_script: + - tox \ No newline at end of file diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..7a30eca --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[build] +target-dir = "build\\temp.win-amd64-3.7\\ed_lrr_gui" diff --git a/.gitignore b/.gitignore index 5b0dd33..f0cdfd5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ __pycache__ build *.pdf .history -pip-wheel-metadata \ No newline at end of file +.tox +pip-wheel-metadata diff --git a/LICENSE b/LICENSE index ea8c62e..99ee78e 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in index fe1501c..2f28226 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include rust/Cargo.toml include rust/.cargo/config -recursive-include rust/src * \ No newline at end of file +recursive-include rust/src * diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..d3f6c2a --- /dev/null +++ b/Pipfile @@ -0,0 +1,12 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +ed-lrr-gui = {path = "."} + +[requires] +python_version = "3.7" diff --git a/README.md b/README.md index 3afaad9..2723c76 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# Prerequisites + +- conda (miniconda/anaconda) +- Visual Studio 2019 +- nightly rust compiler (`x86_64-pc-windows-msvc`) + # Testing ```bash @@ -14,7 +20,7 @@ rs_gui_test conda create -n ed_lrr_gui_env python=3 conda activate ed_lrr_gui_env python build_gui.py -pip install setuptools_rust +pip install setuptools_rust pyinstaller pip install . python setup.py build python setup.py bdist_wheel @@ -38,4 +44,4 @@ cd .. # TODO - integrate callbacks into the GUI: WIP - - QTimer pulls from queue updates UI (every 100ms) \ No newline at end of file + - QTimer pulls from queue updates UI (every 100ms) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..7ccaef9 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,23 @@ +image: Visual Studio 2019 +platform: x64 +version: 0.1.{build} +branches: + only: + - pyqt_gui + +environment: + VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat + VCVARSARG: x64 + +install: + - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc + - pip install tox + + +before_build: + - if defined VCVARS call "%VCVARS%" %VCVARSARG% + - conda activate + +test_script: + - tox \ No newline at end of file diff --git a/build.bat b/build.bat index 9487f53..7f064ec 100644 --- a/build.bat +++ b/build.bat @@ -1,11 +1,10 @@ -rm -rf build dist *.egg-info exe -python build_gui.py -pip uninstall -y ed_lrr_gui -pip install -I . setuptools_rust -python setup.py build -python setup.py bdist_wheel -python setup.py sdist -mkdir exe -cd exe -pyinstaller --noupx --noconsole --key="ED_LRR_GUI" --name ED_LRR_GUI ..\ed_lrr_gui\__main__.py -cd .. \ No newline at end of file +@echo off +:: TODO: convert to python script +:: set up new conda env, install packages, build, remove conda env +call conda create -y -n ed_lrr python=3 pycrypto || exit /b 1 +call conda activate ed_lrr || exit /b 1 +call conda install -y -c conda-forge nuitka +vcvars x64 +python build.py +call conda deactivate || exit /b 1 +call conda env remove -n ed_lrr || exit /b 1 \ No newline at end of file diff --git a/build.py b/build.py new file mode 100644 index 0000000..8bce8ab --- /dev/null +++ b/build.py @@ -0,0 +1,66 @@ +import subprocess as SP +from glob import glob +import os +import shutil +import pkg_resources as pkg +from contextlib import contextmanager + +@contextmanager +def in_dir(name,remove=False): + pwd=os.getcwd() + if os.path.isdir(name): + shutil.rmtree(name) + os.makedirs(name) + os.chdir(name) + yield + os.chdir(pwd) + if remove: + shutil.rmtree(name) + +SP.check_call(["pip", "install", "PyQt5"]) + +ui_path = os.path.dirname(os.path.abspath(__file__)) +for root, folders, files in os.walk(ui_path): + for file in files: + file = os.path.join(root, file) + outfile, ext = os.path.splitext(file) + if ext == ".ui": + outfile = outfile + ".py" + print(os.path.basename(file), "->", os.path.basename(outfile)) + SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file]) + +SP.check_call(["pip", "install", ".[dev]"]) +main_py=os.path.abspath("ed_lrr_gui\__main__.py") +with in_dir("exe"): + with in_dir("pyinstaller"): + SP.check_call( + [ + "pyinstaller", + "--clean", + "--noupx", + "-c", + '--key="ED_LRR_GUI"', + "--name", + "ED_LRR", + main_py, + ] + ) + with in_dir("nuitka"): + SP.check_call( + [ + "python", + "-m", + "nuitka", + "--plugin-enable=multiprocessing", + "--plugin-enable=qt-plugins", + "--standalone", + "--follow-imports", + main_py, + ] + ) + + +# with in_dir("installer"): +# shutil.rmtree("Output") +# SP.check_call(["iscc", "/QP", "ED_LRR.iss"]) + diff --git a/clean.bat b/clean.bat index 098a107..20a9545 100644 --- a/clean.bat +++ b/clean.bat @@ -2,4 +2,4 @@ rm -rfv _*.pyd *.egg-info pip-wheel-metadata dist exe build __pycache__ cd rust cargo clean cargo clean --release -cd .. \ No newline at end of file +cd .. diff --git a/docs/.vscode/settings.json b/docs/.vscode/settings.json index e674f84..f02fbe4 100644 --- a/docs/.vscode/settings.json +++ b/docs/.vscode/settings.json @@ -8,4 +8,4 @@ "latex", "plaintext" ] -} \ No newline at end of file +} diff --git a/docs/Makefile b/docs/Makefile index 60a308c..f0dbc9f 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -45,4 +45,4 @@ watch: watchexec -w src -w data -w filters -w Makefile make all clean: - -rm $(PDFS) $(IMGS) \ No newline at end of file + -rm $(PDFS) $(IMGS) diff --git a/docs/filters/multifilter.py b/docs/filters/multifilter.py index 2cc9ff0..3ae005c 100644 --- a/docs/filters/multifilter.py +++ b/docs/filters/multifilter.py @@ -1,18 +1,19 @@ -from panflute import * -import tempfile -import sys -from jinja2 import Template, Environment, PackageLoader, select_autoescape import contextlib -import io -import hashlib -from dateutil.parser import parse as dateparse -from functools import partial -import subprocess as SP -import panflute as pf -import os import csv import datetime +import hashlib +import io +import os import re +import subprocess as SP +import sys +import tempfile +from functools import partial + +import panflute as pf +from dateutil.parser import parse as dateparse +from jinja2 import Environment, PackageLoader, Template, select_autoescape +from panflute import * def remove_pound(elem, doc): @@ -29,10 +30,10 @@ def fix_color(elem, doc): def update_date(elem, doc): if type(elem) == MetaMap: - datefmt = doc.get_metadata('datefmt', "%Y-%m-%d") + datefmt = doc.get_metadata("datefmt", "%Y-%m-%d") today = datetime.date.today().strftime(datefmt) - date = dateparse(doc.get_metadata('date', today)).date() - elem['date'] = MetaInlines(Str(date.strftime(datefmt))) + date = dateparse(doc.get_metadata("date", today)).date() + elem["date"] = MetaInlines(Str(date.strftime(datefmt))) return elem @@ -42,8 +43,7 @@ def csv_table(elem, doc): ext = os.path.splitext(elem.url)[1][1:] if ext == "csv": caption = elem.content - has_header = elem.attributes.get( - 'has-header', "false").lower() == "true" + has_header = elem.attributes.get("has-header", "false").lower() == "true" with open(elem.url) as f: reader = csv.reader(f) body = [] @@ -62,7 +62,12 @@ def code_refs(elem, doc): label = label.text filename = re.findall(r"^\[@lst:(.*)\]$", label) or [None] if filename[0] in doc.inc_files: - return [RawInline("\\hyperref[{}]{{{}}}".format(filename[0], filename[0]), format="tex")] + return [ + RawInline( + "\\hyperref[{}]{{{}}}".format(filename[0], filename[0]), + format="tex", + ) + ] def include_code(elem, doc): @@ -71,9 +76,8 @@ def include_code(elem, doc): filepath = elem.attributes.pop("include") filename = os.path.split(filepath)[-1] try: - elem.text += elem.text + \ - open(filepath, encoding="utf-8").read() - elem.attributes['caption'] = filename + elem.text += elem.text + open(filepath, encoding="utf-8").read() + elem.attributes["caption"] = filename doc.inc_files.append(filename) except Exception as e: elem.text += "Error: {}".format(e) @@ -92,28 +96,26 @@ def jinja_py_filt(doc, file): env = {} code = open(file, encoding="utf-8").read() exec(code, env) - return env['main'](doc) + return env["main"](doc) def prepare(doc): doc.inc_files = [] doc.env = Environment() doc.pyenv = {} - filters = {'py': partial(jinja_py_filt, doc)} + filters = {"py": partial(jinja_py_filt, doc)} doc.env.filters.update(filters) def process_templates(elem, doc): if type(elem) == CodeBlock: if elem.classes == ["@"]: - args = {'meta': doc.get_metadata()} + args = {"meta": doc.get_metadata()} return convert_text(doc.env.from_string(elem.text).render(args)) def yaml_filt(elem, doc): - tags = { - 'eval': py_eval, - } + tags = {"eval": py_eval} return yaml_filter(elem, doc, tags=tags, strict_yaml=True) @@ -138,8 +140,16 @@ def checkboxes(elem, doc): def main(doc=None): - f = [process_templates, update_date, csv_table, include_code, - fix_color, code_refs, yaml_filt, checkboxes] + f = [ + process_templates, + update_date, + csv_table, + include_code, + fix_color, + code_refs, + yaml_filt, + checkboxes, + ] return run_filters(f, prepare=prepare, doc=doc) diff --git a/docs/src/img_out.py b/docs/src/img_out.py index 7179b78..deb32bc 100644 --- a/docs/src/img_out.py +++ b/docs/src/img_out.py @@ -1,8 +1,9 @@ -import sys -import pylab as PL -import numpy as np -from scipy.spatial.ckdtree import cKDTree import heapq +import sys + +import numpy as np +import pylab as PL +from scipy.spatial.ckdtree import cKDTree exit() diff --git a/ed_lrr_gui/__init__.py b/ed_lrr_gui/__init__.py index 9bce23f..ce16d39 100644 --- a/ed_lrr_gui/__init__.py +++ b/ed_lrr_gui/__init__.py @@ -1,4 +1,4 @@ from _ed_lrr import * -from . import gui -from .router import Router + from .preprocess import Preprocessor +from .router import Router diff --git a/ed_lrr_gui/__main__.py b/ed_lrr_gui/__main__.py index 153f408..be94950 100644 --- a/ed_lrr_gui/__main__.py +++ b/ed_lrr_gui/__main__.py @@ -1,562 +1,111 @@ import sys -import os -import requests as RQ -from datetime import datetime, timedelta -from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt, QObject -from PyQt5.QtWidgets import ( - QMainWindow, - QApplication, - QFileDialog, - QProgressDialog, - QTreeWidgetItem, - QAction, - QMessageBox, -) -from urllib.request import Request, urlopen -import gzip -import pathlib -from PyQt5.QtGui import QPalette, QColor -import ed_lrr_gui -import ed_lrr_gui.config as cfg -from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR -from ed_lrr_gui import Router, Preprocessor import multiprocessing as MP import queue -import csv -import _ed_lrr +import ctypes +from math import floor +import click +from click_default_group import DefaultGroup +import requests as RQ +from ed_lrr_gui import Router +from ed_lrr_gui import Preprocessor +import ed_lrr_gui.gui as ED_LRR_GUI +CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) - -def sizeof_fmt(num, suffix="B"): - for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: - if abs(num) < 1024.0: - return "{:.02f}{}{}".format(num, unit, suffix) - num /= 1024.0 - return "{:.02f}{}{}".format(num, "Yi", suffix) - - -def t_round(dt): - return dt - dt % timedelta(seconds=1) - - -class ProgressDialog(QProgressDialog): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.setWindowModality(Qt.WindowModal) - - -class Job(QObject): - progress = pyqtSignal("PyQt_PyObject") - - def __init__(self, app, cls, *args, build_progress=None, **kwargs): - super().__init__() - self.job = cls(*args, **kwargs) - self.timer = QTimer(app) - self.app = app - self.timer.timeout.connect(self.interval) - self.timer.start(100) - self.last_val = None - self.build_progress = build_progress - self.progress_dialog = None - self.state = {} - - def start(self): - """ - if self.diag_prog is None: - self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) - if self.dl_thread: - self.diag_prog.canceled.connect(self.dl_canceled) - self.diag_prog.show() - t_elapsed = datetime.today() - self.dl_started - rate = args["done"] / t_elapsed.total_seconds() - remaining = (args["size"] - args["done"]) / rate - rate = round(rate, 2) - # print(rate, remaining) - try: - t_rem = timedelta(seconds=remaining) - except OverflowError: - t_rem = "-" - msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( - filename, - sizeof_fmt(args["done"]), - sizeof_fmt(args["size"]), - sizeof_fmt(rate), - t_round(t_elapsed), - t_round(t_rem), - ) - self.diag_prog.setLabelText(msg) - self.diag_prog.setWindowTitle("Downloading EDSM Dumps") - self.diag_prog.setValue((args["done"] * 1000) // args["size"]) - """ - self.started = datetime.today() - if self.build_progress: - self.progress_dialog = ProgressDialog("", "Cancel", 0, 1000, self.app) - self.progress_dialog.canceled.connect(self.cancel) - self.progress_dialog.show() - self.progress.connect(self.__build_progress) - else: - self.progress.connect( - lambda *args, **kwargs: print("PROGRESS:", *args, **kwargs) - ) - return self.job.start() - - def __build_progress(self, *args, **kwargs): - kwargs["self"] = self - return self.build_progress(*args, **kwargs) - - def cancel(self): - self.job.terminate() - self.job = None - - def done(self): - return (self.job.is_alive() == False) and (self.job.queue.empty()) - - def interval(self): - while True: - try: - res = self.job.queue.get(True, 0.1) - except queue.Empty: - return - if res == self.last_val: - continue - self.state.update(res) - self.progress.emit(self.state) - self.last_val = res - - -class DownloadThread(QThread): - progress = pyqtSignal("PyQt_PyObject") - - def __init__(self, systems_url, systems_file, bodies_url, bodies_file): - super().__init__() - self.systems_url = systems_url - self.systems_file = systems_file - self.bodies_url = bodies_url - self.bodies_file = bodies_file - self.running = True - - def __del__(self): - self.wait() - - def stop(self): - self.running = False - - def run(self): - dl_jobs = [ - (self.systems_url, self.systems_file), - (self.bodies_url, self.bodies_file), - ] - for url, dest in dl_jobs: - outfile = url.split("/")[-1] - size = RQ.head(url, headers={"Accept-Encoding": "None"}) - size.raise_for_status() - size = int(size.headers.get("Content-Length", 0)) - with open(dest, "wb") as of: - resp = RQ.get(url, stream=True) - for chunk in resp.iter_content(1024 * 1024): - of.write(chunk) - self.progress.emit( - {"done": of.tell(), "size": size, "outfile": outfile} - ) - if not self.running: - return - - -class App(QApplication): - def __init__(self): - super().__init__(sys.argv) - self.setStyle("Fusion") - self.setup_styles() - - def set_style(self, style): - print("LOAD:", style) - self.setPalette(self.styles[style]) - - def setup_styles(self): - self.styles = {} - styles = { - "Dark": { - "Window": QColor(53, 53, 53), - "WindowText": Qt.white, - "Base": QColor(15, 15, 15), - "AlternateBase": QColor(53, 53, 53), - "ToolTipBase": Qt.white, - "ToolTipText": Qt.white, - "Text": Qt.white, - "Button": QColor(53, 53, 53), - "ButtonText": Qt.white, - "BrightText": Qt.red, - "Highlight": QColor(255, 128, 0), - "HighlightedText": Qt.black, - } - } - for style, colors in styles.items(): - palette = QPalette() - for entry, color in colors.items(): - palette.setColor(getattr(QPalette, entry), color) - if color == Qt.darkGray: - palette.setColor( - QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) - ) - else: - palette.setColor( - QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray - ) - self.styles[style] = palette - self.styles["Light"] = self.style().standardPalette() - - -class ED_LRR(Ui_ED_LRR): - dl_thread = None - diag_prog = None - dl_started = None - system_found = pyqtSignal("PyQt_PyObject") - - def __init__(self): - super().__init__() - self.config = cfg.load() - self.jobs = {} - - def start_job(self, cls, *args, **kwargs): - print("START JOB:", cls, args, kwargs) - name = cls.__name__ - if name in self.jobs and self.jobs[name].done(): - del self.jobs[name] - if not name in self.jobs: - self.jobs[name] = Job(self.app, cls, *args, **kwargs) - self.jobs[name].start() - - def get_open_file(self, filetypes, callback=None): - fileName, _ = QFileDialog.getOpenFileName( - self.main_window, - "Open file", - str(cfg.data_dir), - filetypes, - options=QFileDialog.DontUseNativeDialog, - ) - if callback: - return callback(fileName) - return fileName - - def get_save_file(self, filetypes, callback=None): - fileName, _ = QFileDialog.getSaveFileName( - self.main_window, - "Save file", - str(cfg.data_dir), - filetypes, - options=QFileDialog.DontUseNativeDialog, - ) - if callback: - return callback(fileName) - return fileName - - def set_sys_lst(self, path): - if path not in self.config.history_out_path: - self.config.history_out_path.append(path) - self.inp_sys_lst.addItem(path) - self.inp_out_pp.addItem(path) - self.inp_sys_lst.setCurrentText(path) - self.inp_out_pp.setCurrentText(path) - - def set_bodies_file(self, path): - if path not in self.config.history_bodies_path: - self.config.history_bodies_path.append(path) - self.inp_bodies_pp.addItem(path) - - def set_systems_file(self, path): - if path not in self.config.history_systems_path: - self.config.history_systems_path.append(path) - self.inp_systems_pp.addItem(path) - - def update_dropdowns(self): +@click.group(invoke_without_command=True,context_settings=CONTEXT_SETTINGS) +@click.pass_context +def main(ctx): + "Elite: Dangerous long range router, command line interface" + if ctx.invoked_subcommand is None: + ctx.invoke(gui) return + return - def log(self, *args): - t = datetime.today() - msg_t = "[{}] {}".format(t, str.format(*args)) - self.txt_log.append(msg_t) +@main.command() +@click.option("--debug",help="Debug print",is_flag=True) +def gui(debug): + "Run the ED LRR GUI (default)" + if not debug: + ctypes.windll.kernel32.FreeConsole() + sys.stdin=open("NUL","rt") + sys.stdout=open("NUL","wt") + sys.stderr=open("NUL","wt") + sys.exit(ED_LRR_GUI.main()) - def set_comp_mode(self, _): - if self.rd_comp.isChecked(): - comp_mode = "Compute Route" - self.btn_add.setText("Add") - if self.rd_precomp.isChecked(): - comp_mode = "Precompute Graph" - self.btn_add.setText("Select") - self.log("COMP_MODE", comp_mode) - self.lst_sys.setEnabled(self.rd_comp.isChecked()) - self.btn_rm.setEnabled(self.rd_comp.isChecked()) - self.cmb_mode.setEnabled(self.rd_comp.isChecked()) - self.chk_permute.setEnabled(self.rd_comp.isChecked()) - self.lbl_keep.setEnabled(self.rd_comp.isChecked()) - self.lbl_mode.setEnabled(self.rd_comp.isChecked()) - self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked()) - self.chk_permute_keep_last.setEnabled(self.rd_comp.isChecked()) - self.set_route_mode(self.rd_precomp.isChecked() or None) +@main.command() +@click.option("--url","-u",help="Base URL",default="https://www.edsm.net/dump/",show_default=True) +@click.option("--systems","-s",help="Target path for systemsWithCoordinates.json",default="systemsWithCoordinates.json",show_default=True) +@click.option("--bodies","-b",help="Target path for bodies.json",default="bodies.json",show_default=True) +def download(*args,**kwargs): + "Download EDSM dumps" + print("Download:",args,kwargs) + click.pause() - def set_route_mode(self, mode=None): - if mode == None: - mode = self.cmb_mode.currentText() - self.lbl_greedyness.setEnabled(mode == "A*-Search") - self.sld_greedyness.setEnabled(mode == "A*-Search") +@main.command() +def preprocess(*args,**kwargs): + "Preprocess EDSM dumps" + print("PreProcess:",ctx,args,kwargs) + click.pause() - def set_greedyness(self, value): - self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100)) - @property - def systems(self): - ret = [] - for n in range(self.lst_sys.topLevelItemCount()): - ret.append(self.sys_to_dict(n)) - return ret - - def sys_to_dict(self, n): - header = [ - self.lst_sys.headerItem().data(c, 0) - for c in range(self.lst_sys.headerItem().columnCount()) - ] - system = [ - self.lst_sys.topLevelItem(n).data(c, 0) - for c in range(self.lst_sys.topLevelItem(n).columnCount()) - ] - ret = dict(zip(header, system)) - ret["id"] = getattr(self.lst_sys.topLevelItem(n), "__id__", None) - ret.pop(None, None) - return ret - - def error(self, msg): - QMessageBox.critical(self.main_window, "ERROR!", msg) - - def get_sys_list(self): - if not self.inp_sys_lst.currentText(): - self.error("System list is required!") - return - path = pathlib.Path(self.inp_sys_lst.currentText()) - if not path.exists(): - self.error("System list does not exist, run download and preprocess first!") - return - return path - - def run(self): - if not all(s["Type"] for s in self.systems): - self.error('Not all systens have been resolved, please click "Search All"') - return - print(self.systems) - systems = [str(s["id"]) for s in self.systems] - jump_range = self.sb_range.value() - mode = self.cmb_mode.currentText() - primary = self.chk_primary.isChecked() - keep_first = self.chk_permute_keep_first.isChecked() - keep_last = self.chk_permute_keep_last.isChecked() - permute = self.chk_permute.isChecked() - greedyness = ( - self.sld_greedyness.value() / 100 - if self.sld_greedyness.isEnabled() - else None - ) - path = self.get_sys_list() - if path is None: - return - precomp = path.with_suffix(".idx") - path = str(path) - if not precomp.exists(): - precomp = None - else: - precomp = str(precomp) - mode = { - "Breadth-First Search": "bfs", - "A*-Search": "astar", - "Greedy-Search": "greedy", - }[mode] - print( - systems, - jump_range, - mode, - primary, - permute, - (keep_first, keep_last), - greedyness, - path, - precomp, - ) - self.start_job( - Router, - systems, - jump_range, - 0.1, - mode, - primary, - permute, - keep_first, - keep_last, - greedyness, - precomp, - path, - ) - - def find_sys_by_names(self, names): - t_s = datetime.today() - if not self.get_sys_list(): - return None - ret = _ed_lrr.find_sys(names, self.inp_sys_lst.currentText()) - print("Took:", datetime.today() - t_s) - return ret - - def resolve_systems(self): - names = [] - for n in range(self.lst_sys.topLevelItemCount()): - names.append(self.sys_to_dict(n)["Name"]) - systems = self.find_sys_by_names(names) - if systems is None: - return - for i, name in enumerate(names): - _, system = systems[name] - self.lst_sys.topLevelItem(i).setData(0, 0, system["system"]) - self.lst_sys.topLevelItem(i).setData(1, 0, system["star_type"]) - self.lst_sys.topLevelItem(i).__id__ = system["id"] - # diff, item = self.find_sys_by_name(name) - # print("Found", (diff, item)) - - def add_system(self): - name = self.inp_sys.text() - item = QTreeWidgetItem(self.lst_sys, [name, None]) - item.resolved = False - item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) - - def remove_system(self): - root = self.lst_sys.invisibleRootItem() - for item in self.lst_sys.selectedItems(): - root.removeChild(item) - - def dl_canceled(self): - if self.dl_thread: - print("Cancel!") +@main.command() +@click.option("--path","-i",required=True,metavar="",help="Path to stars.csv",default="./stars.csv",type=click.Path(exists=True,dir_okay=False),show_default=True ) +@click.option("--precomp_file","-pf",metavar="",help="Precomputed routing graph to use",type=click.Path(exists=True,dir_okay=False)) +@click.option("--range","-r",required=True,metavar="",help="Jump range (Ly)",type=click.FloatRange(min=0)) +@click.option("--prune","-d",default=(0,0),metavar=" ",help="Prune search branches",nargs=2,type=click.Tuple([click.IntRange(min=0),click.FloatRange(min=0)])) +@click.option("--permute","-p",type=click.Choice(["all","keep_first","keep_last","keep_both"]),default=None,help="Permute hops to find shortest route",show_default=True) +@click.option("--primary","-ps",is_flag=True,default=False,help="Only route through primary stars") +@click.option("--factor","-g",metavar="",default=0.5,help="Greedyness factor for A-Star",show_default=True) +@click.option("--mode","-m",default="bfs",help="Search mode",type=click.Choice(["bfs","a-star","greedy"]),show_default=True) +@click.argument('systems',nargs=-1) +def route(**kwargs): + "Compute a route" + if kwargs['prune']==(0,0): + kwargs['prune']=None + def to_string(state): + if state: + return "[{}] {}".format(state['depth'],state['system']) + keep_first,keep_last={ + "all":(False,False), + "keep_first":(True,False), + "keep_last":(False,True), + "keep_both":(True,True), + None: (False,False) + }[kwargs['permute']] + args=[kwargs['systems'],kwargs['range'],kwargs['prune'],kwargs['mode'],kwargs['primary'],kwargs['permute']!=None,keep_first,keep_last,kwargs['factor'],None,kwargs['path']] + with click.progressbar(length=100,label="Computing route",show_percent=True,item_show_func=to_string,width=50) as pbar: + router=Router(*args) + router.start() + state={} + pstate={} + while not (router.queue.empty() and router.is_alive()==False): try: - self.dl_thread.progress.disconnect() - except TypeError: + event = router.queue.get(True,0.1) + state.update(event) + if state!=pstate: + pbar.current_item=state.get("status") + if pbar.current_item: + pbar.pos=floor(pbar.current_item["prc_done"]*10)/10 + pbar.update(0) + pstate=state + except queue.Empty: pass - self.dl_thread.stop() - self.dl_thread.wait() - self.diag_prog.close() - self.dl_thread = None - self.diag_prog = None - self.dl_started = None + pbar.pos=100 + pbar.update(0) + print(state.get("result")) + print("DONE!") - def handle_dl_progress(self, args): - filename = os.path.split(args["outfile"])[-1] - if self.diag_prog is None: - self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) - if self.dl_thread: - self.diag_prog.canceled.connect(self.dl_canceled) - self.diag_prog.show() - t_elapsed = datetime.today() - self.dl_started - rate = args["done"] / t_elapsed.total_seconds() - remaining = (args["size"] - args["done"]) / rate - rate = round(rate, 2) - # print(rate, remaining) - try: - t_rem = timedelta(seconds=remaining) - except OverflowError: - t_rem = "-" - msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( - filename, - sizeof_fmt(args["done"]), - sizeof_fmt(args["size"]), - sizeof_fmt(rate), - t_round(t_elapsed), - t_round(t_rem), - ) - self.diag_prog.setLabelText(msg) - self.diag_prog.setWindowTitle("Downloading EDSM Dumps") - self.diag_prog.setValue((args["done"] * 1000) // args["size"]) - - def run_download(self): - if self.dl_thread: - return - self.dl_started = datetime.today() - self.dl_thread = DownloadThread( - self.inp_systems_dl.currentText(), - self.inp_systems_dest_dl.currentText(), - self.inp_bodies_dl.currentText(), - self.inp_bodies_dest_dl.currentText(), - ) - self.dl_thread.progress.connect(self.handle_dl_progress) - self.dl_thread.start() - print(".") - - def update_permute_chk(self, state): - self.chk_permute_keep_first.setEnabled(state) - self.chk_permute_keep_last.setEnabled(state) - self.lbl_keep.setEnabled(state) - - def setup_signals(self): - self.btn_download.clicked.connect(self.run_download) - self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json") - self.inp_bodies_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\b.json") - self.set_greedyness(self.sld_greedyness.value()) - self.cmb_mode.currentTextChanged.connect(self.set_route_mode) - self.rd_comp.toggled.connect(self.set_comp_mode) - self.rd_precomp.toggled.connect(self.set_comp_mode) - self.sld_greedyness.valueChanged.connect(self.set_greedyness) - self.btn_go.clicked.connect(self.run) - self.btn_add.clicked.connect(self.add_system) - self.btn_rm.clicked.connect(self.remove_system) - self.chk_permute.stateChanged.connect(self.update_permute_chk) - self.btn_search.clicked.connect(self.resolve_systems) - self.btn_out_browse_pp.clicked.connect( - lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) - ) - self.btn_sys_lst_browse.clicked.connect( - lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst) - ) - - self.btn_bodies_browse_pp.clicked.connect( - lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file) - ) - self.btn_bodies_dest_browse_dl.clicked.connect( - lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file) - ) - self.btn_systems_browse_pp.clicked.connect( - lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file) - ) - self.btn_systems_dest_browse_dl.clicked.connect( - lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file) - ) - - def handle_close(self): - cfg.write(self.config) - print("BYEEEEEE!") - - def setup_styles(self, win, app): - for name in app.styles: - action = QAction(app) - action.setObjectName("action_load_style_" + name) - action.setText(name) - action.triggered.connect(lambda _, name=name: app.set_style(name)) - self.menuStyle.addAction(action) - - def setupUi(self, MainWindow, app): - super().setupUi(MainWindow) - self.update_dropdowns() - self.main_window = MainWindow - self.app = app - self.setup_signals() - self.lst_sys.setHeaderLabels(["Name", "Type"]) - self.set_route_mode() - self.update_permute_chk(self.chk_permute.isChecked()) - self.setup_styles(MainWindow, app) +@main.command() +@click.option("--path","-i",required=True,help="Path to stars.csv",default="./stars.csv",type=click.Path(exists=True,dir_okay=False),show_default=True ) +@click.option("--precomp_file","-pc",help="Precomputed routing graph to use",type=click.Path(exists=True,dir_okay=False)) +@click.option("--range","-r",required=True,help="Jump range (Ly)",type=click.FloatRange(min=0)) +@click.option("--primary","-ps",help="Only route through primary stars") +@click.option("--output","-o",required=True,help="Output path",default="./stars.idx",type=click.Path(exists=False,dir_okay=False),show_default=True ) +@click.argument('systems',nargs=-1) +def precompute(*args,**kwargs): + "Precompute routing graph" + print("PreComp:",ctx,args,kwargs) -def main(): - app = App() - MainWindow = QMainWindow() - ui = ED_LRR() - ui.setupUi(MainWindow, app) - MainWindow.show() - ret = app.exec_() - ui.handle_close() - exit(ret) - - -if __name__ == "__main__": +if __name__ == '__main__': MP.freeze_support() - main() + main() \ No newline at end of file diff --git a/ed_lrr_gui/config.py b/ed_lrr_gui/config.py index 3e748b7..9720f2d 100644 --- a/ed_lrr_gui/config.py +++ b/ed_lrr_gui/config.py @@ -1,7 +1,8 @@ import pathlib +from collections import namedtuple + import appdirs import yaml -from collections import namedtuple config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR")) config_dir.mkdir(parents=True, exist_ok=True) diff --git a/ed_lrr_gui/gui/__init__.py b/ed_lrr_gui/gui/__init__.py index e69de29..b668da9 100644 --- a/ed_lrr_gui/gui/__init__.py +++ b/ed_lrr_gui/gui/__init__.py @@ -0,0 +1 @@ +from .main import main \ No newline at end of file diff --git a/ed_lrr_gui/gui/ed_lrr.py b/ed_lrr_gui/gui/ed_lrr.py index c33b639..0ce8074 100644 --- a/ed_lrr_gui/gui/ed_lrr.py +++ b/ed_lrr_gui/gui/ed_lrr.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'D:\devel\rust\ed_lrr_gui\ed_lrr_gui\gui\ed_lrr.ui' # -# Created by: PyQt5 UI code generator 5.13.0 +# Created by: PyQt5 UI code generator 5.13.1 # # WARNING! All changes made in this file will be lost! diff --git a/ed_lrr_gui/gui/main.py b/ed_lrr_gui/gui/main.py new file mode 100644 index 0000000..af409d7 --- /dev/null +++ b/ed_lrr_gui/gui/main.py @@ -0,0 +1,546 @@ +import csv +import gzip +import multiprocessing as MP +import os +import pathlib +import queue +import sys +from sys import exit +from datetime import datetime, timedelta +from urllib.request import Request, urlopen + +import _ed_lrr +import ed_lrr_gui +import ed_lrr_gui.config as cfg +import requests as RQ +from ed_lrr_gui import Preprocessor, Router +from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR +from PyQt5.QtCore import QObject, Qt, QThread, QTimer, pyqtSignal +from PyQt5.QtGui import QColor, QPalette,QIcon +from PyQt5.QtWidgets import ( + QAction, + QApplication, + QFileDialog, + QMainWindow, + QMessageBox, + QProgressDialog, + QTreeWidgetItem, +) + + +def sizeof_fmt(num, suffix="B"): + for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: + if abs(num) < 1024.0: + return "{:.02f}{}{}".format(num, unit, suffix) + num /= 1024.0 + return "{:.02f}{}{}".format(num, "Yi", suffix) + + +def t_round(dt): + return dt - dt % timedelta(seconds=1) + + +class ProgressDialog(QProgressDialog): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setWindowModality(Qt.WindowModal) + + +class Job(QObject): + progress = pyqtSignal("PyQt_PyObject") + + def __init__(self, app, main_window, cls, *args, **kwargs): + super().__init__() + self.job = cls(*args, **kwargs) + self.timer = QTimer(app) + self.app = app + self.main_window = main_window + self.timer.timeout.connect(self.interval) + self.timer.start(100) + self.last_val = None + self.progress_dialog = None + self.handle_progess = None + self.state = {} + + def setup_progress(self, handle_progess): + self.progress.connect( + lambda *args, **kwargs: handle_progess(self, *args, **kwargs) + ) + + def start(self): + if self.progress_dialog is None: + self.progress.connect( + lambda *args, **kwargs: print("PROGRESS:", *args, **kwargs) + ) + self.started = datetime.today() + return self.job.start() + + def cancel(self): + self.job.terminate() + self.job = None + + def done(self): + return (self.job.is_alive() == False) and (self.job.queue.empty()) + + def interval(self): + while True: + try: + res = self.job.queue.get(True, 0.1) + except queue.Empty: + return + if res == self.last_val: + continue + self.state.update(res) + self.progress.emit(self.state) + self.last_val = res + + +class DownloadThread(QThread): + progress = pyqtSignal("PyQt_PyObject") + + def __init__(self, systems_url, systems_file, bodies_url, bodies_file): + super().__init__() + self.systems_url = systems_url + self.systems_file = systems_file + self.bodies_url = bodies_url + self.bodies_file = bodies_file + self.running = True + + def __del__(self): + self.wait() + + def stop(self): + self.running = False + + def run(self): + dl_jobs = [ + (self.systems_url, self.systems_file), + (self.bodies_url, self.bodies_file), + ] + for url, dest in dl_jobs: + outfile = url.split("/")[-1] + size = RQ.head(url, headers={"Accept-Encoding": "None"}) + size.raise_for_status() + size = int(size.headers.get("Content-Length", 0)) + with open(dest, "wb") as of: + resp = RQ.get(url, stream=True) + for chunk in resp.iter_content(1024 * 1024): + of.write(chunk) + self.progress.emit( + {"done": of.tell(), "size": size, "outfile": outfile} + ) + if not self.running: + return + + +class App(QApplication): + def __init__(self): + super().__init__(sys.argv) + self.setStyle("Fusion") + self.setup_styles() + + def set_style(self, style): + print("LOAD:", style) + self.setPalette(self.styles[style]) + + def setup_styles(self): + self.styles = {} + styles = { + "Dark": { + "Window": QColor(53, 53, 53), + "WindowText": Qt.white, + "Base": QColor(15, 15, 15), + "AlternateBase": QColor(53, 53, 53), + "ToolTipBase": Qt.white, + "ToolTipText": Qt.white, + "Text": Qt.white, + "Button": QColor(53, 53, 53), + "ButtonText": Qt.white, + "BrightText": Qt.red, + "Highlight": QColor(255, 128, 0), + "HighlightedText": Qt.black, + } + } + for style, colors in styles.items(): + palette = QPalette() + for entry, color in colors.items(): + palette.setColor(getattr(QPalette, entry), color) + if color == Qt.darkGray: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) + ) + else: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray + ) + self.styles[style] = palette + self.styles["Light"] = self.style().standardPalette() + + +class ED_LRR(Ui_ED_LRR): + dl_thread = None + diag_prog = None + dl_started = None + system_found = pyqtSignal("PyQt_PyObject") + + def __init__(self): + super().__init__() + self.config = cfg.load() + self.jobs = {} + + def new_job(self, cls, *args, **kwargs): + print("CREATE JOB:", cls, args, kwargs) + name = cls.__name__ + if name in self.jobs and self.jobs[name].done(): + del self.jobs[name] + if not name in self.jobs: + self.jobs[name] = Job(self.app, self.main_window, cls, *args, **kwargs) + return self.jobs[name] + + def get_open_file(self, filetypes, callback=None): + fileName, _ = QFileDialog.getOpenFileName( + self.main_window, + "Open file", + str(cfg.data_dir), + filetypes, + options=QFileDialog.DontUseNativeDialog, + ) + if callback: + return callback(fileName) + return fileName + + def get_save_file(self, filetypes, callback=None): + fileName, _ = QFileDialog.getSaveFileName( + self.main_window, + "Save file", + str(cfg.data_dir), + filetypes, + options=QFileDialog.DontUseNativeDialog, + ) + if callback: + return callback(fileName) + return fileName + + def set_sys_lst(self, path): + if path not in self.config.history_out_path: + self.config.history_out_path.append(path) + self.inp_sys_lst.addItem(path) + self.inp_out_pp.addItem(path) + self.inp_sys_lst.setCurrentText(path) + self.inp_out_pp.setCurrentText(path) + + def set_bodies_file(self, path): + if path not in self.config.history_bodies_path: + self.config.history_bodies_path.append(path) + self.inp_bodies_pp.addItem(path) + + def set_systems_file(self, path): + if path not in self.config.history_systems_path: + self.config.history_systems_path.append(path) + self.inp_systems_pp.addItem(path) + + def update_dropdowns(self): + return + + def log(self, *args): + t = datetime.today() + msg_t = "[{}] {}".format(t, str.format(*args)) + self.txt_log.append(msg_t) + + def set_comp_mode(self, _): + if self.rd_comp.isChecked(): + comp_mode = "Compute Route" + self.btn_add.setText("Add") + if self.rd_precomp.isChecked(): + comp_mode = "Precompute Graph" + self.btn_add.setText("Select") + self.log("COMP_MODE", comp_mode) + self.lst_sys.setEnabled(self.rd_comp.isChecked()) + self.btn_rm.setEnabled(self.rd_comp.isChecked()) + self.cmb_mode.setEnabled(self.rd_comp.isChecked()) + self.chk_permute.setEnabled(self.rd_comp.isChecked()) + self.lbl_keep.setEnabled(self.rd_comp.isChecked()) + self.lbl_mode.setEnabled(self.rd_comp.isChecked()) + self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked()) + self.chk_permute_keep_last.setEnabled(self.rd_comp.isChecked()) + self.set_route_mode(self.rd_precomp.isChecked() or None) + + def set_route_mode(self, mode=None): + if mode == None: + mode = self.cmb_mode.currentText() + self.lbl_greedyness.setEnabled(mode == "A*-Search") + self.sld_greedyness.setEnabled(mode == "A*-Search") + + def set_greedyness(self, value): + self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100)) + + @property + def systems(self): + ret = [] + for n in range(self.lst_sys.topLevelItemCount()): + ret.append(self.sys_to_dict(n)) + return ret + + def sys_to_dict(self, n): + header = [ + self.lst_sys.headerItem().data(c, 0) + for c in range(self.lst_sys.headerItem().columnCount()) + ] + system = [ + self.lst_sys.topLevelItem(n).data(c, 0) + for c in range(self.lst_sys.topLevelItem(n).columnCount()) + ] + ret = dict(zip(header, system)) + ret["id"] = getattr(self.lst_sys.topLevelItem(n), "__id__", None) + ret.pop(None, None) + return ret + + def error(self, msg): + QMessageBox.critical(self.main_window, "ERROR!", msg) + + def get_sys_list(self): + if not self.inp_sys_lst.currentText(): + self.error("System list is required!") + return + path = pathlib.Path(self.inp_sys_lst.currentText()) + if not path.exists(): + self.error("System list does not exist, run download and preprocess first!") + return + return path + + def route_progress(self, job, state): + print("RP:", job, state) + + def run(self): + if not all(s["Type"] for s in self.systems): + self.error('Not all systens have been resolved, please click "Search All"') + return + print(self.systems) + systems = [str(s["id"]) for s in self.systems] + jump_range = self.sb_range.value() + mode = self.cmb_mode.currentText() + primary = self.chk_primary.isChecked() + keep_first = self.chk_permute_keep_first.isChecked() + keep_last = self.chk_permute_keep_last.isChecked() + permute = self.chk_permute.isChecked() + greedyness = ( + self.sld_greedyness.value() / 100 + if self.sld_greedyness.isEnabled() + else None + ) + path = self.get_sys_list() + if path is None: + return + precomp = None + path = str(path) + mode = { + "Breadth-First Search": "bfs", + "A*-Search": "astar", + "Greedy-Search": "greedy", + }[mode] + print( + systems, + jump_range, + mode, + primary, + permute, + (keep_first, keep_last), + greedyness, + path, + precomp, + ) + route_job = self.new_job( + Router, + systems, + jump_range, + 0.1, + mode, + primary, + permute, + keep_first, + keep_last, + greedyness, + precomp, + path, + ) + if route_job: + self.route_progress_dialog = ProgressDialog( + "Computing route...", "Cancel", 0, 100, self.main_window + ) + self.route_progress_dialog.canceled.connect(route_job.cancel) + route_job.start() + self.route_progress_dialog.show() + else: + self.error("Another route job is already running!") + + def find_sys_by_names(self, names): + t_s = datetime.today() + if not self.get_sys_list(): + return None + # TODO: start thread/subprocess + ret = _ed_lrr.find_sys(names, self.inp_sys_lst.currentText()) + print("Took:", datetime.today() - t_s) + return ret + + def resolve_systems(self): + # TODO: show spinner + names = [] + for n in range(self.lst_sys.topLevelItemCount()): + names.append(self.sys_to_dict(n)["Name"]) + systems = self.find_sys_by_names(names) + if systems is None: + return + for i, name in enumerate(names): + _, system = systems[name] + self.lst_sys.topLevelItem(i).setData(0, 0, system["system"]) + self.lst_sys.topLevelItem(i).setData(1, 0, system["star_type"]) + self.lst_sys.topLevelItem(i).__id__ = system["id"] + # diff, item = self.find_sys_by_name(name) + # print("Found", (diff, item)) + + def add_system(self): + name = self.inp_sys.text() + item = QTreeWidgetItem(self.lst_sys, [name, None]) + item.resolved = False + item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) + + def remove_system(self): + root = self.lst_sys.invisibleRootItem() + for item in self.lst_sys.selectedItems(): + root.removeChild(item) + + def dl_canceled(self): + if self.dl_thread: + print("Cancel!") + try: + self.dl_thread.progress.disconnect() + except TypeError: + pass + self.dl_thread.stop() + self.dl_thread.wait() + self.diag_prog.close() + self.dl_thread = None + self.diag_prog = None + self.dl_started = None + + def handle_dl_progress(self, args): + filename = os.path.split(args["outfile"])[-1] + if self.diag_prog is None: + self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) + if self.dl_thread: + self.diag_prog.canceled.connect(self.dl_canceled) + self.diag_prog.show() + t_elapsed = datetime.today() - self.dl_started + rate = args["done"] / t_elapsed.total_seconds() + remaining = (args["size"] - args["done"]) / rate + rate = round(rate, 2) + # print(rate, remaining) + try: + t_rem = timedelta(seconds=remaining) + except OverflowError: + t_rem = "-" + msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( + filename, + sizeof_fmt(args["done"]), + sizeof_fmt(args["size"]), + sizeof_fmt(rate), + t_round(t_elapsed), + t_round(t_rem), + ) + self.diag_prog.setLabelText(msg) + self.diag_prog.setWindowTitle("Downloading EDSM Dumps") + self.diag_prog.setValue((args["done"] * 1000) // args["size"]) + + def run_download(self): + if self.dl_thread: + return + self.dl_started = datetime.today() + self.dl_thread = DownloadThread( + self.inp_systems_dl.currentText(), + self.inp_systems_dest_dl.currentText(), + self.inp_bodies_dl.currentText(), + self.inp_bodies_dest_dl.currentText(), + ) + self.dl_thread.progress.connect(self.handle_dl_progress) + self.dl_thread.start() + print(".") + + def update_permute_chk(self, state): + self.chk_permute_keep_first.setEnabled(state) + self.chk_permute_keep_last.setEnabled(state) + self.lbl_keep.setEnabled(state) + + def setup_signals(self): + self.btn_download.clicked.connect(self.run_download) + self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json") + self.inp_bodies_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\b.json") + self.set_greedyness(self.sld_greedyness.value()) + self.cmb_mode.currentTextChanged.connect(self.set_route_mode) + self.rd_comp.toggled.connect(self.set_comp_mode) + self.rd_precomp.toggled.connect(self.set_comp_mode) + self.sld_greedyness.valueChanged.connect(self.set_greedyness) + self.btn_go.clicked.connect(self.run) + self.btn_add.clicked.connect(self.add_system) + self.btn_rm.clicked.connect(self.remove_system) + self.chk_permute.stateChanged.connect(self.update_permute_chk) + self.btn_search.clicked.connect(self.resolve_systems) + self.btn_out_browse_pp.clicked.connect( + lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) + ) + self.btn_sys_lst_browse.clicked.connect( + lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst) + ) + + self.btn_bodies_browse_pp.clicked.connect( + lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file) + ) + self.btn_bodies_dest_browse_dl.clicked.connect( + lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file) + ) + self.btn_systems_browse_pp.clicked.connect( + lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file) + ) + self.btn_systems_dest_browse_dl.clicked.connect( + lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file) + ) + + def handle_close(self): + cfg.write(self.config) + print("BYEEEEEE!") + + def setup_styles(self, win, app): + for name in app.styles: + action = QAction(app) + action.setObjectName("action_load_style_" + name) + action.setText(name) + action.triggered.connect(lambda _, name=name: app.set_style(name)) + self.menuStyle.addAction(action) + + def setupUi(self, MainWindow, app): + super().setupUi(MainWindow) + self.update_dropdowns() + self.main_window = MainWindow + self.app = app + self.setup_signals() + self.lst_sys.setHeaderLabels(["Name", "Type"]) + self.set_route_mode() + self.update_permute_chk(self.chk_permute.isChecked()) + self.setup_styles(MainWindow, app) + + +def main(): + MP.freeze_support() + app = App() + app.setWindowIcon(QIcon(r'D:\devel\rust\ed_lrr_gui\icon\icon.ico')) + MainWindow = QMainWindow() + MainWindow.setWindowIcon(QIcon(r'D:\devel\rust\ed_lrr_gui\icon\icon.ico')) + ui = ED_LRR() + ui.setupUi(MainWindow, app) + MainWindow.show() + ret = app.exec_() + ui.handle_close() + exit(ret) + + +if __name__ == "__main__": + main() diff --git a/ed_lrr_gui/preprocess.py b/ed_lrr_gui/preprocess.py index f59b2b4..a487833 100644 --- a/ed_lrr_gui/preprocess.py +++ b/ed_lrr_gui/preprocess.py @@ -1,8 +1,9 @@ -from multiprocessing import Process, Queue, freeze_support import queue -from datetime import datetime, timedelta -import _ed_lrr from collections import namedtuple +from datetime import datetime, timedelta +from multiprocessing import Process, Queue, freeze_support + +import _ed_lrr class Preprocessor(Process): diff --git a/ed_lrr_gui/router.py b/ed_lrr_gui/router.py index 4e5bbfe..c9f99ce 100644 --- a/ed_lrr_gui/router.py +++ b/ed_lrr_gui/router.py @@ -1,8 +1,16 @@ -from multiprocessing import Process, Queue, freeze_support import queue -from datetime import datetime, timedelta -import _ed_lrr from collections import namedtuple +from datetime import datetime, timedelta +from multiprocessing import Process, Queue, freeze_support + +import _ed_lrr +# from PyQt5.QtWidgets import QProgressDialog + + +# class RouteProgress(QProgressDialog): +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# self.setWindowModality(Qt.WindowModal) class Router(Process): diff --git a/icon/icon.ico b/icon/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e46e62b1dab3e045fb35732efe53facfd92b304f GIT binary patch literal 376773 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.8: + dwg.add(dwg.circle((px,py),r=base_r+random.random()*base_r,stroke_width=w,stroke='#0ae')).fill('#0ae') + else: + dwg.add(dwg.circle((px,py),r=base_r+random.random()*base_r,stroke_width=w,stroke=color)).fill(color) + r=base_r + for _ in range(random.randint(1,max_rings)): + if small: + random.random() + random.random() + continue + r+=ring_step(random.random()) + if random.random()>0.75: + circ=dwg.add(dwg.circle((px,py),r=r,stroke_width=w,stroke="#ea0")) + else: + circ=dwg.add(dwg.circle((px,py),r=r,stroke_width=w,stroke=color)) + circ.fill(color,opacity=0) + + dwg.save() + + + +seed=0 +generate(seed,"icon_1",small=False) +generate(seed,"icon_1_small",small=True) diff --git a/icon/out/icon_1.svg b/icon/out/icon_1.svg new file mode 100644 index 0000000..1fb9797 --- /dev/null +++ b/icon/out/icon_1.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/icon/out/icon_1_small.svg b/icon/out/icon_1_small.svg new file mode 100644 index 0000000..e31b894 --- /dev/null +++ b/icon/out/icon_1_small.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/installer/ED_LRR.iss b/installer/ED_LRR.iss new file mode 100644 index 0000000..8e31873 --- /dev/null +++ b/installer/ED_LRR.iss @@ -0,0 +1,22 @@ +[Setup] +AppName = "ED_LRR" +AppVersion ="0.1.0" +; WizardStyle = modern +DefaultDirName = {autopf}\ED_LRR +DefaultGroupName=ED_LRR +Compression = lzma/ultra +SolidCompression = true +InternalCompressLevel = ultra +OutputBaseFilename="ED_LRR Setup" +ChangesEnvironment = true + +[Files] +Source: "..\exe\dist\ED_LRR\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs + +[Icons] +Name: "{group}\ED_LRR"; Filename: "{app}\ED_LRR.exe"; WorkingDir: "{app}" +Name: "{group}\Uninstall ED_LRR"; Filename: "{uninstallexe}" + +[Run] +Filename: "{app}\ED_LRR.exe"; Description: "Launch ED_LRR"; Flags: postinstall nowait skipifsilent unchecked +Filename: "{app}\ED_LRR.exe"; Parameters: "download" \ No newline at end of file diff --git a/rust/.cargo/config b/rust/.cargo/config index f0b7483..a5af40a 100644 --- a/rust/.cargo/config +++ b/rust/.cargo/config @@ -1,2 +1,2 @@ [build] -rustflags = ["-C", "target-cpu=native"] \ No newline at end of file +rustflags = ["-C", "target-cpu=native"] diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 4ccdea1..5ce2860 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -8,15 +8,6 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "atty" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "autocfg" version = "0.1.5" @@ -29,14 +20,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "block-buffer" version = "0.7.3" @@ -64,7 +50,7 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -77,47 +63,6 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cfg-if" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clicolors-control" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "console" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "csv" version = "1.1.1" @@ -127,7 +72,7 @@ dependencies = [ "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -163,12 +108,11 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -179,11 +123,6 @@ name = "either" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "encode_unicode" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fnv" version = "1.0.6" @@ -209,42 +148,51 @@ dependencies = [ [[package]] name = "humantime" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "indicatif" -version = "0.11.0" +name = "indoc" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "indoc-impl" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inventory" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inventory-impl" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,41 +220,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lock_api" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mashup" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mashup-impl" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -317,41 +239,29 @@ dependencies = [ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "number_prefix" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "parking_lot" -version = "0.9.0" +name = "paste" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "parking_lot_core" -version = "0.6.2" +name = "paste-impl" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -366,17 +276,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -version = "0.4.2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc-macro2" version = "0.4.30" @@ -386,39 +293,51 @@ dependencies = [ ] [[package]] -name = "pyo3" -version = "0.7.0" +name = "proc-macro2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3cls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pyo3-derive-backend" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pyo3cls" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3-derive-backend 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -435,18 +354,21 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.1.56" +name = "quote" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "regex" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -460,12 +382,12 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rstar" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -473,40 +395,14 @@ dependencies = [ "pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ryu" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "scopeguard" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", @@ -529,7 +425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -544,14 +440,9 @@ dependencies = [ "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "smallvec" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "spin" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -570,11 +461,13 @@ dependencies = [ ] [[package]] -name = "termios" -version = "0.3.1" +name = "syn" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -590,116 +483,85 @@ name = "typenum" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unindent" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0a692f1c740e7e821ca71a22cf99b9b2322dfa94d10f71443befb1797b3946a" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" -"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" -"checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922" -"checksum inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a877ae8bce77402d5e9ed870730939e097aad827b2a932b361958fa9d6e75aa" +"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +"checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8" +"checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75" +"checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" +"checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" -"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" -"checksum mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b" -"checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49" +"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" -"checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" -"checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" +"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086" -"checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186" -"checksum pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c494f8161f5b73096cc50f00fbb90fe670f476cde5e59c1decff39b546d54f40" +"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +"checksum pyo3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5862a106c576591645b9fa36b56764b6c894dda70800479892997e5b4fd41c0f" +"checksum pyo3-derive-backend 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d6d14afa2d06a63331dad47b4b40cac06c3be1e3d7de56d020eab2b3e9484b" +"checksum pyo3cls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e39529c2416febd394f7d032abbce5fa1915e32b2fc9b564e1d9d017acac78d" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" -"checksum rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90bb34cd8efef7ed3ebfb29e713e51301c3e60fba37c3e9185a1afaf9ce643a" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08c3cf91d6318ed050a8dda79bc857665f9c3d41524b6f70bbd0396c5d9d662d" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" +"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a" "checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" +"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6" "checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" -"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d0d32a92c9ed197278e09140c32dec854ad5826f0e0e18c1d2a1690f15c8d5" +"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2a579f7..df5607e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,32 +1,27 @@ -[package] -name = "ed_lrr" -version = "0.1.0" -authors = ["Daniel Seiller "] -edition = "2018" -repository = "https://gitlab.com/Earthnuker/ed_lrr.git" -license = "WTFPL" - - -[lib] -crate-type = ["cdylib"] - -[profile.release] -#debug=true - -[dependencies] -csv = "1.1.1" -serde = { version = "1.0", features = ["derive"] } -rstar = "0.5.0" -humantime = "1.2.0" -permutohedron = "0.2.4" -serde_json = "1.0.40" -indicatif = "0.11.0" -fnv = "1.0.6" -bincode = "1.1.4" -sha3 = "0.8.2" -byteorder = "1.3.2" -strsim = "0.9.2" - -[dependencies.pyo3] -version = "0.7.0" -features = ["extension-module"] +[package] +name = "ed_lrr" +version = "0.1.0" +authors = ["Daniel Seiller "] +edition = "2018" +repository = "https://gitlab.com/Earthnuker/ed_lrr.git" +license = "WTFPL" + + +[lib] +crate-type = ["cdylib"] +name = "_ed_lrr" + +[dependencies] +pyo3 = { version = "0.8.0", features = ["extension-module"] } +csv = "1.1.1" +serde = { version = "1.0", features = ["derive"] } +rstar = "0.5.1" +humantime = "1.3.0" +permutohedron = "0.2.4" +serde_json = "1.0.40" +fnv = "1.0.6" +bincode = "1.1.4" +sha3 = "0.8.2" +byteorder = "1.3.2" +strsim = "0.9.2" + diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 43bf006..8204e74 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -114,7 +114,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { py: Python<'static>, hops: Vec, range: f32, - radius_mult: f32, + prune: Option<(usize,f64)>, mode: String, primary: bool, permute: bool, @@ -145,13 +145,14 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { state_dict.set_item("prc_done", state.prc_done)?; state_dict.set_item("n_seen", state.n_seen)?; state_dict.set_item("prc_seen", state.prc_seen)?; + state_dict.set_item("from", state.from.clone())?; + state_dict.set_item("to", state.to.clone())?; callback.call(py, (state_dict,), None) }; let mut systems = Vec::new(); for sys in hops { systems.push(route::SysEntry::parse(&sys)) } - println!("SYSTEMS: {:?}", systems); let opts = RouteOpts { systems, range: Some(range), @@ -165,7 +166,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { keep_first, keep_last, primary, - radius_mult, + prune, }; let none = ().to_object(py); match route(opts) { diff --git a/rust/src/route.rs b/rust/src/route.rs index 3a7878f..247084b 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -20,6 +20,8 @@ pub struct SearchState { pub mode: String, pub system: String, pub body: String, + pub from: String, + pub to: String, pub depth: usize, pub queue_size: usize, pub d_rem: f32, @@ -55,7 +57,7 @@ pub struct RouteOpts { pub keep_last: bool, pub factor: Option, pub mode: Mode, - pub radius_mult: f32, + pub prune: Option<(usize,f64)>, pub systems: Vec, pub callback: Box PyResult>, } @@ -191,7 +193,8 @@ pub struct Router { range: f32, primary_only: bool, path: PathBuf, - radius_mult: f32, + prune: Option<(usize,f64)>, + prune_map: FnvHashMap, callback: Box PyResult>, } @@ -199,7 +202,7 @@ impl Router { pub fn new( path: &PathBuf, range: f32, - radius_mult: f32, + prune: Option<(usize,f64)>, primary_only: bool, callback: Box PyResult>, ) -> Result { @@ -245,7 +248,8 @@ impl Router { cache: LineCache::new(path), path: path.clone(), callback, - radius_mult, + prune, + prune_map: FnvHashMap::default() }; println!( "{} Systems loaded in {}", @@ -302,7 +306,8 @@ impl Router { primary_only: primary, path, callback, - radius_mult: 0f32, + prune: None, + prune_map: FnvHashMap::default() }, )) } @@ -317,11 +322,8 @@ impl Router { fn valid(&self, sys: &System, src: &System, dst: &System) -> bool { let scoopable = self.scoopable.contains(&sys.id); - if self.radius_mult == 0.0 { - return scoopable; - } - let df = src.distp(dst); - (sys.distp(src) + sys.distp(dst)) < (df * (1.0 + self.radius_mult)) + return scoopable; + // TODO: check prune map } pub fn best_multiroute( @@ -466,6 +468,8 @@ impl Router { prc_done: 0.0, n_seen: 0, prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), body: start_sys.body.clone(), system: start_sys.system.clone(), }; @@ -569,6 +573,8 @@ impl Router { prc_done: 0.0, n_seen: 0, prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), body: start_sys.body.clone(), system: start_sys.system.clone(), }; @@ -793,6 +799,8 @@ impl Router { prc_done: 0.0, n_seen: 0, prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), system: start_sys.system.clone(), body: start_sys.body.clone(), }; @@ -879,6 +887,7 @@ impl Router { } } pub fn route(opts: RouteOpts) -> Result>, String> { + // TODO: implement pruning (check if dist to target improved by at least $n*jump_range$ Ly in the last $m$ steps) if opts.systems.is_empty() { if opts.precomp_file.is_some() { return Err("Error: Please specify exatly one system".to_owned()); @@ -898,7 +907,7 @@ pub fn route(opts: RouteOpts) -> Result>, String> { Router::new( &path, opts.range.unwrap(), - opts.radius_mult, + opts.prune, opts.primary, Box::new(opts.callback), )? @@ -906,14 +915,12 @@ pub fn route(opts: RouteOpts) -> Result>, String> { Router::new( &path, opts.range.unwrap(), - opts.radius_mult, + opts.prune, opts.primary, opts.callback, )? }; - let systems: Vec = router - .resolve_systems(&opts.systems)? - .to_vec(); + let systems: Vec = router.resolve_systems(&opts.systems)?.to_vec(); if opts.precompute { for sys in systems { router.route_tree = None; diff --git a/setup.py b/setup.py index 20e467c..af29aac 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,21 @@ -from setuptools import setup,find_packages +import sys +import distutils.cmd +import distutils.log +from setuptools import find_packages, setup from setuptools_rust import Binding, RustExtension, Strip +with open("README.md", "r") as fh: + long_description = fh.read() + + setup( name="ed_lrr_gui", version="0.1.0", author="Daniel Seiller", author_email="earthnuker@gmail.com", + description="Elite: Dangerous long range route plotter", + long_description=long_description, + long_description_content_type="text/markdown", url="none yet", rust_extensions=[ RustExtension( @@ -17,14 +27,38 @@ setup( ) ], packages=find_packages(), - entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, + entry_points={ + "console_scripts": [ + "ed_lrr_gui_console = ed_lrr_gui.gui.__main__:main", + "ed_lrr = ed_lrr_gui.__main__:main", + ], + "gui_scripts": ["ed_lrr_gui = ed_lrr_gui.gui.__main__:main"], + }, install_requires=[ - "PyQt5", "appdirs", "PyYAML", "requests", "python-dateutil", "pyperclip", + "click", + "PyQt5", + "click-default-group" + ], + setup_requires=[ + "setuptools", + "setuptools-rust", + "wheel", + "pyinstaller", + "pytest-runner", + ], + tests_require=["pytest", "pytest-pep8", "pytest-cov"], + extras_require={ + "dev": ["black", "pyinstaller","jinja2","svgwrite","tsp"], + }, + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", ], include_package_data=True, zip_safe=False, diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..3212d14 --- /dev/null +++ b/tox.ini @@ -0,0 +1,30 @@ +[tox] +envlist = py37 +requires = tox-conda + +[testenv] +recreate = True +skip_install = True +deps = + PyQt5 + setuptools_rust +conda_deps = + pycrypto + nuitka +passenv = + CARGO_HOME + RUSTUP_HOME + INCLUDE + LIB + MSSdk + DISTUTILS_USE_SDK +whitelist_externals = + cargo +conda_channels = + conda-forge +extras = + dev +commands = + python build_gui.py + pip install .[dev] + python -m nuitka --plugin-enable=multiprocessing --plugin-enable=qt-plugins --standalone --follow-imports --output-dir=exe ed_lrr_gui\__main__.py From 461f806488045967c83b9c6ad5c6416afced7b9b Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 17:41:48 +0200 Subject: [PATCH 45/72] chore: cleanup --- .cargo/config | 2 -- appveyor.yml | 23 ----------------------- 2 files changed, 25 deletions(-) delete mode 100644 .cargo/config delete mode 100644 appveyor.yml diff --git a/.cargo/config b/.cargo/config deleted file mode 100644 index 7a30eca..0000000 --- a/.cargo/config +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target-dir = "build\\temp.win-amd64-3.7\\ed_lrr_gui" diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 7ccaef9..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,23 +0,0 @@ -image: Visual Studio 2019 -platform: x64 -version: 0.1.{build} -branches: - only: - - pyqt_gui - -environment: - VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat - VCVARSARG: x64 - -install: - - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - - pip install tox - - -before_build: - - if defined VCVARS call "%VCVARS%" %VCVARSARG% - - conda activate - -test_script: - - tox \ No newline at end of file From 519005e62517b84f74e172d411f763356004203c Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 17:44:33 +0200 Subject: [PATCH 46/72] chore: more cleanup --- .chglog/config.yml | 4 ++-- .gitignore | 3 +++ Pipfile | 12 ------------ Pipfile.lock | 24 ++++++++++++++++++++++++ build.bat | 10 ---------- clean.bat | 5 ----- test.bat | 4 ---- test_gui.bat | 1 - 8 files changed, 29 insertions(+), 34 deletions(-) delete mode 100644 Pipfile create mode 100644 Pipfile.lock delete mode 100644 build.bat delete mode 100644 clean.bat delete mode 100644 test.bat delete mode 100644 test_gui.bat diff --git a/.chglog/config.yml b/.chglog/config.yml index 7a42b92..04fafe0 100644 --- a/.chglog/config.yml +++ b/.chglog/config.yml @@ -15,7 +15,7 @@ options: - other - docs commit_groups: - title_maps: + title_maps: feat: Features fix: Bug Fixes perf: Performance Improvements @@ -31,4 +31,4 @@ options: - Subject notes: keywords: - - BREAKING CHANGE \ No newline at end of file + - BREAKING CHANGE diff --git a/.gitignore b/.gitignore index f0cdfd5..3264073 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ build .history .tox pip-wheel-metadata +.eggs/ +exe/ +installer/Output/ diff --git a/Pipfile b/Pipfile deleted file mode 100644 index d3f6c2a..0000000 --- a/Pipfile +++ /dev/null @@ -1,12 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] -ed-lrr-gui = {path = "."} - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..66964ed --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,24 @@ +{ + "_meta": { + "hash": { + "sha256": "49acc8c3ea047d6a35faed08243dba88a571bfc7112957089d5d1ae634249f98" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "ed-lrr-gui": { + "path": "." + } + }, + "develop": {} +} diff --git a/build.bat b/build.bat deleted file mode 100644 index 7f064ec..0000000 --- a/build.bat +++ /dev/null @@ -1,10 +0,0 @@ -@echo off -:: TODO: convert to python script -:: set up new conda env, install packages, build, remove conda env -call conda create -y -n ed_lrr python=3 pycrypto || exit /b 1 -call conda activate ed_lrr || exit /b 1 -call conda install -y -c conda-forge nuitka -vcvars x64 -python build.py -call conda deactivate || exit /b 1 -call conda env remove -n ed_lrr || exit /b 1 \ No newline at end of file diff --git a/clean.bat b/clean.bat deleted file mode 100644 index 20a9545..0000000 --- a/clean.bat +++ /dev/null @@ -1,5 +0,0 @@ -rm -rfv _*.pyd *.egg-info pip-wheel-metadata dist exe build __pycache__ -cd rust -cargo clean -cargo clean --release -cd .. diff --git a/test.bat b/test.bat deleted file mode 100644 index b7cddb8..0000000 --- a/test.bat +++ /dev/null @@ -1,4 +0,0 @@ -python build_gui.py -pip uninstall -y ed_lrr_gui -pip install -e . -ed_lrr_gui diff --git a/test_gui.bat b/test_gui.bat deleted file mode 100644 index 5051fac..0000000 --- a/test_gui.bat +++ /dev/null @@ -1 +0,0 @@ -python build_gui.py && python ed_lrr_gui/__main__.py \ No newline at end of file From c1082a75c2527a09dbfbe35dd8604375bda952d3 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 17:44:52 +0200 Subject: [PATCH 47/72] chore: remove Pipfile.lock --- Pipfile.lock | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 Pipfile.lock diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 66964ed..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,24 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "49acc8c3ea047d6a35faed08243dba88a571bfc7112957089d5d1ae634249f98" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "ed-lrr-gui": { - "path": "." - } - }, - "develop": {} -} From d454cfad3a39565f229e9ff2c2601e1b5f731f2a Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 17:53:28 +0200 Subject: [PATCH 48/72] chore: update appveyor.yml --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 7ccaef9..7099c96 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -17,7 +17,7 @@ install: before_build: - if defined VCVARS call "%VCVARS%" %VCVARSARG% - - conda activate + - C:\Miniconda3\Miniconda3\Library\bin\conda.bat activate test_script: - tox \ No newline at end of file From 1a33d47c9a464a1b0c74d9ee8a01a9b136a9066d Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 18:00:05 +0200 Subject: [PATCH 49/72] chore: update appveyor.yml --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 7099c96..250511f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -17,7 +17,7 @@ install: before_build: - if defined VCVARS call "%VCVARS%" %VCVARSARG% - - C:\Miniconda3\Miniconda3\Library\bin\conda.bat activate + - C:\Miniconda3\Library\bin\conda.bat activate test_script: - tox \ No newline at end of file From 66f04c48968d61bab9d18233ca64b8a27d5f5c25 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 18:10:08 +0200 Subject: [PATCH 50/72] chore: rename .appveyor.yaml --- .appveyor.yml => appveyor.yml | 4 ++-- tox.ini | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) rename .appveyor.yml => appveyor.yml (91%) diff --git a/.appveyor.yml b/appveyor.yml similarity index 91% rename from .appveyor.yml rename to appveyor.yml index 250511f..976338d 100644 --- a/.appveyor.yml +++ b/appveyor.yml @@ -19,5 +19,5 @@ before_build: - if defined VCVARS call "%VCVARS%" %VCVARSARG% - C:\Miniconda3\Library\bin\conda.bat activate -test_script: - - tox \ No newline at end of file +build_script: + - tox -e build \ No newline at end of file diff --git a/tox.ini b/tox.ini index 3212d14..f811ab8 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,7 @@ envlist = py37 requires = tox-conda [testenv] +description = Build ED_LRR recreate = True skip_install = True deps = From 220133fb230c97278a622cfa57f325b7e0c33c30 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 18:16:30 +0200 Subject: [PATCH 51/72] chore: update appveyor.yaml --- appveyor.yml | 11 +++++------ tox.ini | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 976338d..4c5b2f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,15 +9,14 @@ environment: VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat VCVARSARG: x64 -install: +build: false + +before_test: - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - - pip install tox - - -before_build: - if defined VCVARS call "%VCVARS%" %VCVARSARG% - C:\Miniconda3\Library\bin\conda.bat activate + - pip install tox -build_script: +test_script: - tox -e build \ No newline at end of file diff --git a/tox.ini b/tox.ini index f811ab8..c290237 100644 --- a/tox.ini +++ b/tox.ini @@ -2,7 +2,7 @@ envlist = py37 requires = tox-conda -[testenv] +[testenv:conda] description = Build ED_LRR recreate = True skip_install = True From 855e56a179cd6e03a16c1f048e4e0f2de2c0bce0 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 18:19:49 +0200 Subject: [PATCH 52/72] chore: update appveyor.yaml --- appveyor.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 4c5b2f6..d048f9f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,14 +8,16 @@ branches: environment: VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat VCVARSARG: x64 + MINICONDA: C:\Miniconda3 build: false -before_test: +install: + - "set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%PATH%" - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% - - C:\Miniconda3\Library\bin\conda.bat activate + - conda activate - pip install tox test_script: From ade8e1bb0d8b02f08bfdf5c3f7688624e9ca4159 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 18:30:07 +0200 Subject: [PATCH 53/72] chore: update appveyor.yml --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d048f9f..374e772 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,12 +8,12 @@ branches: environment: VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat VCVARSARG: x64 - MINICONDA: C:\Miniconda3 + MINICONDA: C:\Miniconda3-x64 build: false install: - - "set PATH=%MINICONDA%;%MINICONDA%\\Scripts;%PATH%" + - set PATH=%MINICONDA%\\Scripts;%MINICONDA%\\Library\\bin;%PATH% - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% From 874e392d8754c1be5dd87c0b55b4b90f40102f97 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 18:35:22 +0200 Subject: [PATCH 54/72] chore: update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 374e772..90ce3d7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ environment: build: false install: - - set PATH=%MINICONDA%\\Scripts;%MINICONDA%\\Library\\bin;%PATH% + - set PATH=%MINICONDA%\\Library\\bin;%MINICONDA%\\Scripts;%USERPROFILE%\\.cargo\\bin;%PATH% - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% From 6bb7e1e7165136fdd74e4f1895b64a05c20c77d9 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 18:43:25 +0200 Subject: [PATCH 55/72] fix: fixed tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index c290237..f811ab8 100644 --- a/tox.ini +++ b/tox.ini @@ -2,7 +2,7 @@ envlist = py37 requires = tox-conda -[testenv:conda] +[testenv] description = Build ED_LRR recreate = True skip_install = True From 59390fed2f82a50b6c920ed4b8859de3695fec8e Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 19:16:58 +0200 Subject: [PATCH 56/72] fix: fixed appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 90ce3d7..b65cd28 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,4 +21,4 @@ install: - pip install tox test_script: - - tox -e build \ No newline at end of file + - tox \ No newline at end of file From 11efe303eeb1c855ea53f25f086279cd4f6b5b97 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 23:52:15 +0200 Subject: [PATCH 57/72] fix: fix nuikta call to download without confirmation --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f811ab8..fcb8511 100644 --- a/tox.ini +++ b/tox.ini @@ -28,4 +28,4 @@ extras = commands = python build_gui.py pip install .[dev] - python -m nuitka --plugin-enable=multiprocessing --plugin-enable=qt-plugins --standalone --follow-imports --output-dir=exe ed_lrr_gui\__main__.py + python -m nuitka --plugin-enable=multiprocessing --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py From fa485be07e59524b07d7e19260d00741e8037c5d Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Fri, 20 Sep 2019 23:53:15 +0200 Subject: [PATCH 58/72] fix: fix nuikta call to clean build directory --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index fcb8511..6e46619 100644 --- a/tox.ini +++ b/tox.ini @@ -28,4 +28,4 @@ extras = commands = python build_gui.py pip install .[dev] - python -m nuitka --plugin-enable=multiprocessing --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py + python -m nuitka --plugin-enable=multiprocessing --remove-output --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py From 1c1e20816aa06d67218413a5382c4d979f424f8a Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:04:41 +0200 Subject: [PATCH 59/72] chore(CI): remove tox, switch to appveyor, add artifact paths --- appveyor.yml | 19 +++++++++++++++++-- installer/ED_LRR.iss | 7 +++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index b65cd28..26a0d78 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,13 +12,28 @@ environment: build: false +artifacts: + - path: exe\__main__.dist\ + name: ED_LRR + type: zip + + - path: installer\Output\*.exe + name: Setup + type: file + install: - set PATH=%MINICONDA%\\Library\\bin;%MINICONDA%\\Scripts;%USERPROFILE%\\.cargo\\bin;%PATH% + - set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH% - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% - conda activate - - pip install tox test_script: - - tox \ No newline at end of file + - python build_gui.py + - pip install .[dev] + - python -m nuitka --plugin-enable=multiprocessing --remove-output --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py + - rename exe\__main__.dist\__main__.exe ED_LRR.exe + - cd installer + - iscc /QP ED_LRR.iss + diff --git a/installer/ED_LRR.iss b/installer/ED_LRR.iss index 8e31873..43236fa 100644 --- a/installer/ED_LRR.iss +++ b/installer/ED_LRR.iss @@ -11,12 +11,15 @@ OutputBaseFilename="ED_LRR Setup" ChangesEnvironment = true [Files] -Source: "..\exe\dist\ED_LRR\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs +Source: "..\exe\__main__.dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs [Icons] Name: "{group}\ED_LRR"; Filename: "{app}\ED_LRR.exe"; WorkingDir: "{app}" Name: "{group}\Uninstall ED_LRR"; Filename: "{uninstallexe}" +[Tasks] +;Name: modifypath; Description: Add application directory to PATH; Flags: unchecked + [Run] Filename: "{app}\ED_LRR.exe"; Description: "Launch ED_LRR"; Flags: postinstall nowait skipifsilent unchecked -Filename: "{app}\ED_LRR.exe"; Parameters: "download" \ No newline at end of file +; Filename: "{app}\ED_LRR.exe"; Parameters: "download" From da2d85b3339e02fedfd40a51e1b67c71e37e10c1 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:05:08 +0200 Subject: [PATCH 60/72] chore(CI): Update tox.ini to build installer --- tox.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tox.ini b/tox.ini index 6e46619..f9b2756 100644 --- a/tox.ini +++ b/tox.ini @@ -21,6 +21,7 @@ passenv = DISTUTILS_USE_SDK whitelist_externals = cargo + iscc conda_channels = conda-forge extras = @@ -29,3 +30,6 @@ commands = python build_gui.py pip install .[dev] python -m nuitka --plugin-enable=multiprocessing --remove-output --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py + rename exe\__main__.dist\__main__.exe ED_LRR.exe + cd installer + iscc /QP ED_LRR.iss \ No newline at end of file From 71a45a30e7dc5906cdd28bbc3428c92c8ff88747 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:11:17 +0200 Subject: [PATCH 61/72] chore: Update appveyor.yml, fix missing backslash escape --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 26a0d78..8aa199f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,7 +23,7 @@ artifacts: install: - set PATH=%MINICONDA%\\Library\\bin;%MINICONDA%\\Scripts;%USERPROFILE%\\.cargo\\bin;%PATH% - - set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH% + - set PATH="C:\\Program Files (x86)\\Inno Setup 5";%PATH% - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% From b27ef9010505046dda31e532365b796e59d724d3 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:20:27 +0200 Subject: [PATCH 62/72] chore: fix appveyor --- appveyor.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8aa199f..47e01d0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,8 +9,9 @@ environment: VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat VCVARSARG: x64 MINICONDA: C:\Miniconda3-x64 + INNO: C:\Program Files (x86)\Inno Setup 5 -build: false +build: off artifacts: - path: exe\__main__.dist\ @@ -23,7 +24,7 @@ artifacts: install: - set PATH=%MINICONDA%\\Library\\bin;%MINICONDA%\\Scripts;%USERPROFILE%\\.cargo\\bin;%PATH% - - set PATH="C:\\Program Files (x86)\\Inno Setup 5";%PATH% + - set PATH=%INNO%;%PATH% - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% From e8beb559f2c8d5100fc1ca33ae38f7a293869b8e Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:26:34 +0200 Subject: [PATCH 63/72] fix: add missing dependencies to appveyor.yml --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 47e01d0..0038a6e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,6 +29,8 @@ install: - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% - conda activate + - conda install pycrypto nuitka + - pip intall PyQt5 setuptools_rust test_script: - python build_gui.py From 6d9f1ef04bfe10370dba6adb73b9fefc0e7e7ed9 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:32:49 +0200 Subject: [PATCH 64/72] fix: add missing conda channel --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 0038a6e..c2fa4bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,7 +29,7 @@ install: - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% - conda activate - - conda install pycrypto nuitka + - conda install -c conda-forge pycrypto nuitka - pip intall PyQt5 setuptools_rust test_script: From eaddb188ba931f0396e926fd1fb96264bd3c1cfa Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:38:27 +0200 Subject: [PATCH 65/72] fix: disable confirmation for conda install --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c2fa4bf..bb3f614 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,7 +29,7 @@ install: - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% - conda activate - - conda install -c conda-forge pycrypto nuitka + - conda install -y -c conda-forge pycrypto nuitka - pip intall PyQt5 setuptools_rust test_script: From 09e6f0afb55f4fda8627884890b8c7be737c9261 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 20:44:46 +0200 Subject: [PATCH 66/72] fix: typo in appveyor.yml --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index bb3f614..a92d4c1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,11 +26,11 @@ install: - set PATH=%MINICONDA%\\Library\\bin;%MINICONDA%\\Scripts;%USERPROFILE%\\.cargo\\bin;%PATH% - set PATH=%INNO%;%PATH% - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc + - rustup-init -y --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% - conda activate - conda install -y -c conda-forge pycrypto nuitka - - pip intall PyQt5 setuptools_rust + - pip install PyQt5 setuptools_rust test_script: - python build_gui.py From fe3534e9d6d7c7399eae4cc4d1c8f6841d6f4245 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 21 Sep 2019 21:25:02 +0200 Subject: [PATCH 67/72] fix: switch inno setup version in appveyor --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a92d4c1..492b378 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,7 +9,7 @@ environment: VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat VCVARSARG: x64 MINICONDA: C:\Miniconda3-x64 - INNO: C:\Program Files (x86)\Inno Setup 5 + INNO: C:\Program Files (x86)\Inno Setup 6 build: off @@ -29,6 +29,7 @@ install: - rustup-init -y --default-toolchain nightly --default-host x86_64-pc-windows-msvc - if defined VCVARS call "%VCVARS%" %VCVARSARG% - conda activate + - conda update -y -n base -c defaults conda - conda install -y -c conda-forge pycrypto nuitka - pip install PyQt5 setuptools_rust From d498746a5c5097a2dfdd9409fa7d53daf653db64 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 28 Sep 2019 15:35:30 +0200 Subject: [PATCH 68/72] feat(router): Add dialog to display computed route --- ed_lrr_gui/gui/widget_route.py | 55 ++++++++++++++++++++ ed_lrr_gui/gui/widget_route.ui | 94 ++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 ed_lrr_gui/gui/widget_route.py create mode 100644 ed_lrr_gui/gui/widget_route.ui diff --git a/ed_lrr_gui/gui/widget_route.py b/ed_lrr_gui/gui/widget_route.py new file mode 100644 index 0000000..b0f2b75 --- /dev/null +++ b/ed_lrr_gui/gui/widget_route.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'D:\devel\rust\ed_lrr_gui\ed_lrr_gui\gui\widget_route.ui' +# +# Created by: PyQt5 UI code generator 5.13.1 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.setWindowModality(QtCore.Qt.WindowModal) + Dialog.resize(430, 300) + self.layout_main = QtWidgets.QGridLayout(Dialog) + self.layout_main.setObjectName("layout_main") + self.layout_top = QtWidgets.QGridLayout() + self.layout_top.setObjectName("layout_top") + self.lst_route = QtWidgets.QTreeWidget(Dialog) + self.lst_route.setProperty("showDropIndicator", False) + self.lst_route.setDefaultDropAction(QtCore.Qt.IgnoreAction) + self.lst_route.setAlternatingRowColors(True) + self.lst_route.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) + self.lst_route.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem) + self.lst_route.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.lst_route.setItemsExpandable(False) + self.lst_route.setAllColumnsShowFocus(False) + self.lst_route.setObjectName("lst_route") + self.layout_top.addWidget(self.lst_route, 0, 0, 1, 1) + self.layout_main.addLayout(self.layout_top, 0, 0, 1, 1) + self.layout_bottom = QtWidgets.QGridLayout() + self.layout_bottom.setObjectName("layout_bottom") + self.chk_copy = QtWidgets.QCheckBox(Dialog) + self.chk_copy.setObjectName("chk_copy") + self.layout_bottom.addWidget(self.chk_copy, 1, 0, 1, 1) + self.pushButton = QtWidgets.QPushButton(Dialog) + self.pushButton.setObjectName("pushButton") + self.layout_bottom.addWidget(self.pushButton, 1, 1, 1, 1) + self.layout_main.addLayout(self.layout_bottom, 1, 0, 1, 1) + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Route")) + self.lst_route.headerItem().setText(0, _translate("Dialog", "Num")) + self.lst_route.headerItem().setText(1, _translate("Dialog", "System")) + self.lst_route.headerItem().setText(2, _translate("Dialog", "Body")) + self.lst_route.headerItem().setText(3, _translate("Dialog", "Distance (Ls)")) + self.chk_copy.setText(_translate("Dialog", "Auto-copy next hop to clipboard")) + self.pushButton.setText(_translate("Dialog", "Close")) diff --git a/ed_lrr_gui/gui/widget_route.ui b/ed_lrr_gui/gui/widget_route.ui new file mode 100644 index 0000000..e9cd562 --- /dev/null +++ b/ed_lrr_gui/gui/widget_route.ui @@ -0,0 +1,94 @@ + + + Dialog + + + Qt::WindowModal + + + + 0 + 0 + 430 + 300 + + + + Route + + + + + + + + false + + + Qt::IgnoreAction + + + true + + + QAbstractItemView::NoSelection + + + QAbstractItemView::ScrollPerItem + + + QAbstractItemView::ScrollPerPixel + + + false + + + false + + + + Num + + + + + System + + + + + Body + + + + + Distance (Ls) + + + + + + + + + + + + Auto-copy next hop to clipboard + + + + + + + Close + + + + + + + + + + From fb3a13037cb2a8580a967462ee31ba39f82b241d Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 28 Sep 2019 15:37:32 +0200 Subject: [PATCH 69/72] feat(build system): Remove build.py (switched to tox), add output to build_gui.py --- build.py | 66 ---------------------------------------------------- build_gui.py | 1 + 2 files changed, 1 insertion(+), 66 deletions(-) delete mode 100644 build.py diff --git a/build.py b/build.py deleted file mode 100644 index 8bce8ab..0000000 --- a/build.py +++ /dev/null @@ -1,66 +0,0 @@ -import subprocess as SP -from glob import glob -import os -import shutil -import pkg_resources as pkg -from contextlib import contextmanager - -@contextmanager -def in_dir(name,remove=False): - pwd=os.getcwd() - if os.path.isdir(name): - shutil.rmtree(name) - os.makedirs(name) - os.chdir(name) - yield - os.chdir(pwd) - if remove: - shutil.rmtree(name) - -SP.check_call(["pip", "install", "PyQt5"]) - -ui_path = os.path.dirname(os.path.abspath(__file__)) -for root, folders, files in os.walk(ui_path): - for file in files: - file = os.path.join(root, file) - outfile, ext = os.path.splitext(file) - if ext == ".ui": - outfile = outfile + ".py" - print(os.path.basename(file), "->", os.path.basename(outfile)) - SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file]) - -SP.check_call(["pip", "install", ".[dev]"]) -main_py=os.path.abspath("ed_lrr_gui\__main__.py") -with in_dir("exe"): - with in_dir("pyinstaller"): - SP.check_call( - [ - "pyinstaller", - "--clean", - "--noupx", - "-c", - '--key="ED_LRR_GUI"', - "--name", - "ED_LRR", - main_py, - ] - ) - with in_dir("nuitka"): - SP.check_call( - [ - "python", - "-m", - "nuitka", - "--plugin-enable=multiprocessing", - "--plugin-enable=qt-plugins", - "--standalone", - "--follow-imports", - main_py, - ] - ) - - -# with in_dir("installer"): -# shutil.rmtree("Output") -# SP.check_call(["iscc", "/QP", "ED_LRR.iss"]) - diff --git a/build_gui.py b/build_gui.py index 6327ad2..82a1d86 100644 --- a/build_gui.py +++ b/build_gui.py @@ -10,4 +10,5 @@ for root, folders, files in os.walk(ui_path): outfile, ext = os.path.splitext(file) if ext == ".ui": outfile = outfile + ".py" + print(file,"->",outfile) SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file]) From b1143c3510c16efdbe6a8386ccfdda15d5d08c65 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 28 Sep 2019 15:38:33 +0200 Subject: [PATCH 70/72] feat(config): Update config system to use profig --- ed_lrr_gui/config.py | 74 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/ed_lrr_gui/config.py b/ed_lrr_gui/config.py index 9720f2d..6bf3d79 100644 --- a/ed_lrr_gui/config.py +++ b/ed_lrr_gui/config.py @@ -1,46 +1,46 @@ import pathlib from collections import namedtuple - +import profig import appdirs -import yaml +import os -config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR")) +config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR", "")) config_dir.mkdir(parents=True, exist_ok=True) -config_file = config_dir / "config.yml" +config_file = config_dir / "config.ini" config_file.touch() -data_dir = pathlib.Path(appdirs.user_data_dir("ED_LRR")) -data_dir.mkdir(parents=True, exist_ok=True) +cfg = profig.Config(str(config_file), strict=True) +cfg.init("history.bodies_url", [], "path_list", comment="history of bodies.json urls") +cfg.init("history.systems_url", [], "path_list", comment="history of systems.json urls") +cfg.init( + "history.bodies_path", + [], + "path_list", + comment="history of bodies.json download paths", +) +cfg.init( + "history.systems_path", + [], + "path_list", + comment="history of systems.json download paths", +) +cfg.init( + "history.out_path", + [], + "path_list", + comment="history of output paths (stars.csv and precomputed graphs)", +) +cfg.init("route.range", 7.56, comment="jump range") +cfg.init("route.primary", False, comment="only route through primary stars") +cfg.init("route.mode", "bfs", comment="routing mode") +cfg.init( + "route.prune.min_improvement", + 10.0, + comment="path needs to improve by at least (jump_range*min_improvement) in route.prune.steps", +) +cfg.init("route.prune.steps", 5, comment="number of steps before path gets pruned") +cfg.init("route.greediness", 0.5, comment="A* greediness") +cfg.init("folders.data_dir", os.path.join(config_dir, "data"), comment="Data directory") -def make_config(): - return { - "history_bodies_url": [], - "history_systems_url": [], - "history_bodies_path": [], - "history_systems_path": [], - "history_out_path": [], - "range": None, - "primary": False, - "mode": "bfs", - "greedyness": 0.5, - } - - -def write(cfg): - with config_file.open("w", encoding="utf-8") as of: - yaml.dump(cfg._asdict(), of, default_flow_style=False) - - -def load(): - data = yaml.load(config_file.open(encoding="utf-8"), Loader=yaml.Loader) - if data is None: - data = make_config() - write(data) - - return namedtuple("Config", data)(**data) - - -# print("CFG:", yaml.load_config()) -# print(config_file, data_dir) -# exit(1) +cfg.sync() From 0107cf2f8efac0e92be70a6edda81d0d90da2d10 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 28 Sep 2019 15:40:38 +0200 Subject: [PATCH 71/72] chore(router): Update dependencies --- rust/Cargo.lock | 147 ++++++++++++++++++------------------------------ rust/Cargo.toml | 53 +++++++++-------- 2 files changed, 82 insertions(+), 118 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 5ce2860..2e4b9be 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -10,17 +10,17 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bincode" -version = "1.1.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -44,13 +44,13 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -68,11 +68,11 @@ name = "csv" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -85,11 +85,11 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "ed_lrr" -version = "0.1.0" +version = "0.0.0" dependencies = [ - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -112,7 +112,7 @@ dependencies = [ "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -120,7 +120,7 @@ dependencies = [ [[package]] name = "either" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -133,17 +133,17 @@ name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ghost" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -169,7 +169,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -180,8 +180,8 @@ name = "inventory" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ctor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -190,7 +190,7 @@ name = "inventory-impl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -200,7 +200,7 @@ name = "itertools" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -215,7 +215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -236,7 +236,7 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -259,7 +259,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -279,22 +279,14 @@ name = "proc-macro-hack" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -312,7 +304,7 @@ dependencies = [ "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3cls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -324,7 +316,7 @@ name = "pyo3-derive-backend" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -334,7 +326,7 @@ name = "pyo3cls" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "pyo3-derive-backend 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -345,20 +337,12 @@ name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -402,20 +386,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.98" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -425,7 +409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -450,22 +434,12 @@ name = "strsim" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "syn" -version = "0.15.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -475,17 +449,12 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -505,21 +474,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" -"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0a692f1c740e7e821ca71a22cf99b9b2322dfa94d10f71443befb1797b3946a" +"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" -"checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" +"checksum ctor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3e061727ebef83bbccac7c27b9a5ff9fd83094d34cb20f4005440a9562a27de7" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" +"checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8" "checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75" @@ -528,7 +497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" @@ -538,30 +507,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" "checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" "checksum pyo3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5862a106c576591645b9fa36b56764b6c894dda70800479892997e5b4fd41c0f" "checksum pyo3-derive-backend 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d6d14afa2d06a63331dad47b4b40cac06c3be1e3d7de56d020eab2b3e9484b" "checksum pyo3cls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e39529c2416febd394f7d032abbce5fa1915e32b2fc9b564e1d9d017acac78d" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08c3cf91d6318ed050a8dda79bc857665f9c3d41524b6f70bbd0396c5d9d662d" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a" -"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" +"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6" -"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d0d32a92c9ed197278e09140c32dec854ad5826f0e0e18c1d2a1690f15c8d5" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index df5607e..edeebf7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,27 +1,26 @@ -[package] -name = "ed_lrr" -version = "0.1.0" -authors = ["Daniel Seiller "] -edition = "2018" -repository = "https://gitlab.com/Earthnuker/ed_lrr.git" -license = "WTFPL" - - -[lib] -crate-type = ["cdylib"] -name = "_ed_lrr" - -[dependencies] -pyo3 = { version = "0.8.0", features = ["extension-module"] } -csv = "1.1.1" -serde = { version = "1.0", features = ["derive"] } -rstar = "0.5.1" -humantime = "1.3.0" -permutohedron = "0.2.4" -serde_json = "1.0.40" -fnv = "1.0.6" -bincode = "1.1.4" -sha3 = "0.8.2" -byteorder = "1.3.2" -strsim = "0.9.2" - +[package] +name = "ed_lrr" +version = "0.0.0" +authors = ["Daniel Seiller "] +edition = "2018" +repository = "https://gitlab.com/Earthnuker/ed_lrr.git" +license = "WTFPL" + + +[lib] +crate-type = ["cdylib"] +name = "_ed_lrr" + +[dependencies] +pyo3 = { version = "0.8.0", features = ["extension-module"] } +csv = "1.1.1" +serde = { version = "1.0.101", features = ["derive"] } +humantime = "1.3.0" +permutohedron = "0.2.4" +serde_json = "1.0.40" +fnv = "1.0.6" +bincode = "1.2.0" +sha3 = "0.8.2" +byteorder = "1.3.2" +strsim = "0.9.2" +rstar = "0.5.1" From 88a0378dfe7eb691dfc6b34cb94bb2a7fee526cf Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Sat, 28 Sep 2019 15:41:25 +0200 Subject: [PATCH 72/72] feat(router): Start implementing route pruning support --- rust/src/lib.rs | 2 +- rust/src/route.rs | 61 ++++++++++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 8204e74..3f64052 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -114,7 +114,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { py: Python<'static>, hops: Vec, range: f32, - prune: Option<(usize,f64)>, + prune: Option<(usize, f32)>, mode: String, primary: bool, permute: bool, diff --git a/rust/src/route.rs b/rust/src/route.rs index 247084b..f3fd95e 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -57,7 +57,7 @@ pub struct RouteOpts { pub keep_last: bool, pub factor: Option, pub mode: Mode, - pub prune: Option<(usize,f64)>, + pub prune: Option<(usize, f32)>, pub systems: Vec, pub callback: Box PyResult>, } @@ -193,8 +193,7 @@ pub struct Router { range: f32, primary_only: bool, path: PathBuf, - prune: Option<(usize,f64)>, - prune_map: FnvHashMap, + prune: Option<(usize, f32)>, callback: Box PyResult>, } @@ -202,7 +201,7 @@ impl Router { pub fn new( path: &PathBuf, range: f32, - prune: Option<(usize,f64)>, + prune: Option<(usize, f32)>, primary_only: bool, callback: Box PyResult>, ) -> Result { @@ -249,7 +248,6 @@ impl Router { path: path.clone(), callback, prune, - prune_map: FnvHashMap::default() }; println!( "{} Systems loaded in {}", @@ -307,7 +305,6 @@ impl Router { path, callback, prune: None, - prune_map: FnvHashMap::default() }, )) } @@ -320,10 +317,9 @@ impl Router { self.points_in_sphere(&sys.pos, sys.mult * r) } - fn valid(&self, sys: &System, src: &System, dst: &System) -> bool { + fn valid(&self, sys: &System) -> bool { let scoopable = self.scoopable.contains(&sys.id); return scoopable; - // TODO: check prune map } pub fn best_multiroute( @@ -379,6 +375,14 @@ impl Router { for pair in waypoints.windows(2) { match pair { [src, dst] => { + let d_total=dist(&src.pos,&dst.pos); + println!("Plotting route from [{}] to [{}]...", src.system, dst.system); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", + range, + d_total, + d_total / range + ); let block = match mode { Mode::BFS => self.route_bfs(&src, &dst, range)?, Mode::Greedy => self.route_greedy(&src, &dst, range)?, @@ -510,7 +514,7 @@ impl Router { } queue.extend( self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id))) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); @@ -583,11 +587,11 @@ impl Router { let mut prev = FnvHashMap::default(); let mut seen = FnvHashSet::default(); let mut found = false; - let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); - queue.push((-goal_sys.mult, start_sys.distp(goal_sys), 0, &start_sys)); + let mut queue: Vec<(f32, usize, &System)> = Vec::new(); + queue.push((start_sys.distp(goal_sys), 0, &start_sys)); seen.insert(start_sys.id); while !(queue.is_empty() || found) { - while let Some((_, _, depth, sys)) = queue.pop() { + while let Some((_, depth, sys)) = queue.pop() { if t_last.elapsed().as_millis() > 100 { t_last = Instant::now(); state.depth = depth; @@ -611,7 +615,7 @@ impl Router { } queue.extend( self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id))) + .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) .filter(|&nb| seen.insert(nb.id)) .map(|nb| { prev.insert(nb.id, sys); @@ -619,10 +623,10 @@ impl Router { if d_g < d_rem { d_rem = d_g; } - (-nb.mult, d_g, depth + 1, nb) + (d_g, depth + 1, nb) }), ); - queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); + queue.sort_by(|a, b| fcmp(a.0, b.0).then(a.1.cmp(&b.1))); queue.reverse(); } } @@ -786,6 +790,7 @@ impl Router { range: f32, ) -> Result, String> { println!("Running BFS"); + let min_improvement = self.prune.map(|v| (v.0,v.1*range)).unwrap_or_else(|| (0,0.0)); let src_name = start_sys.system.clone(); let dst_name = goal_sys.system.clone(); let d_total = dist(&start_sys.pos, &goal_sys.pos); @@ -804,15 +809,9 @@ impl Router { system: start_sys.system.clone(), body: start_sys.body.clone(), }; - println!("Plotting route from {} to {}...", src_name, dst_name); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", - range, - d_total, - d_total / range - ); let total = self.tree.size() as f32; - let mut prev = FnvHashMap::default(); + let mut prev: FnvHashMap = FnvHashMap::default(); + let mut prune_map: FnvHashMap = FnvHashMap::default(); let mut seen = FnvHashSet::default(); let mut depth = 0; let mut found = false; @@ -847,10 +846,24 @@ impl Router { }; t_last = Instant::now(); } + if self.prune.is_some() { + let best_dist = if let Some(p_sys) = prev.get(&sys.id) { + dist2(&p_sys.pos, &goal_sys.pos).min( + prune_map + .get(&p_sys.id) + .map(|v| v.1) + .unwrap_or(std::f32::MAX), + ) + } else { + dist2(&sys.pos, &goal_sys.pos) + }; + prune_map.insert(sys.id, (depth, best_dist)); + } + // TODO: check improvement, if too small: continue queue_next.extend( self.neighbours(&sys, range) .filter(|&nb| { - (self.valid(nb, &start_sys, &goal_sys) || (nb.id == goal_sys.id)) + (self.valid(nb) || (nb.id == goal_sys.id)) }) .filter(|&nb| seen.insert(nb.id)) .map(|nb| {