yougotmapped 1.0.1__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,67 +1,80 @@
1
- # utils/output.py
2
1
  import json
3
2
  import csv
3
+ from pathlib import Path
4
4
  from io import StringIO
5
5
 
6
6
 
7
- def format_as_normal(data):
8
- output = []
9
- for d in data:
7
+ def _flatten_dict(data: dict, parent_key: str = "", sep: str = "_") -> dict:
8
+ items = {}
9
+
10
+ for key, value in data.items():
11
+ new_key = f"{parent_key}{sep}{key}" if parent_key else key
12
+
13
+ if isinstance(value, dict):
14
+ items.update(_flatten_dict(value, new_key, sep=sep))
15
+ else:
16
+ items[new_key] = value
17
+
18
+ return items
19
+
20
+
21
+ def format_normal(results: list[dict]) -> str:
22
+ blocks = []
23
+
24
+ for entry in results:
10
25
  lines = []
11
- for key, value in d.items():
26
+ for key, value in entry.items():
12
27
  if isinstance(value, dict):
13
- lines.append(f"{key.title()}:")
28
+ lines.append(f"{key}:")
14
29
  for sub_key, sub_val in value.items():
15
- lines.append(f" {sub_key.title()}: {sub_val}")
30
+ lines.append(f" {sub_key}: {sub_val}")
16
31
  else:
17
- lines.append(f"{key.title()}: {value}")
18
- output.append("\n".join(lines))
19
- output.append("\n" + "-" * 40 + "\n")
20
- return "\n".join(output)
21
-
22
-
23
- def flatten_for_csv(entry):
24
- """
25
- Flatten nested dictionaries for CSV.
26
- For example: {"anonymity": {"vpn": False}} -> {"anonymity_vpn": False}
27
- """
28
- flat = {}
29
- for key, value in entry.items():
30
- if isinstance(value, dict):
31
- for sub_key, sub_val in value.items():
32
- flat[f"{key}_{sub_key}"] = sub_val
33
- else:
34
- flat[key] = value
35
- return flat
32
+ lines.append(f"{key}: {value}")
33
+
34
+ blocks.append("\n".join(lines))
35
+ blocks.append("-" * 40)
36
+
37
+ return "\n".join(blocks)
38
+
39
+
40
+ def format_json(results: list[dict]) -> str:
41
+ return json.dumps(results, indent=4)
36
42
 
37
43
 
38
- def format_as_csv(data):
39
- if not data:
44
+ def format_csv(results: list[dict]) -> str:
45
+ if not results:
40
46
  return ""
41
- flat_data = [flatten_for_csv(d) for d in data]
42
- # Collect all possible fields across entries
43
- fieldnames = sorted({key for d in flat_data for key in d.keys()})
44
- output = StringIO()
45
- writer = csv.DictWriter(output, fieldnames=fieldnames)
47
+
48
+ flattened = [_flatten_dict(r) for r in results]
49
+
50
+ fieldnames = sorted(
51
+ {key for entry in flattened for key in entry.keys()}
52
+ )
53
+
54
+ buffer = StringIO()
55
+ writer = csv.DictWriter(buffer, fieldnames=fieldnames)
46
56
  writer.writeheader()
47
- for d in flat_data:
48
- writer.writerow(d)
49
- return output.getvalue()
50
57
 
58
+ for entry in flattened:
59
+ writer.writerow(entry)
60
+
61
+ return buffer.getvalue()
51
62
 
52
- def format_as_json(data):
53
- return json.dumps(data, indent=4)
54
63
 
64
+ def write_output(
65
+ results: list[dict],
66
+ path: str | Path,
67
+ fmt: str = "normal",
68
+ ) -> Path:
69
+ fmt = fmt.lower()
70
+ path = Path(path).resolve()
55
71
 
56
- def write_formatted_output(data, file_path, fmt_type="normal"):
57
- fmt_type = fmt_type.lower()
58
- if fmt_type == "csv":
59
- formatted = format_as_csv(data)
60
- elif fmt_type == "json":
61
- formatted = format_as_json(data)
72
+ if fmt == "json":
73
+ content = format_json(results)
74
+ elif fmt == "csv":
75
+ content = format_csv(results)
62
76
  else:
63
- formatted = format_as_normal(data)
77
+ content = format_normal(results)
64
78
 
65
- with open(file_path, "w", encoding="utf-8") as f:
66
- f.write(formatted)
67
- print(f"Output saved to {file_path} in {fmt_type.upper()} format.")
79
+ path.write_text(content, encoding="utf-8")
80
+ return path
@@ -1,56 +1,107 @@
1
- # utils/pings.py
2
1
  from ping3 import ping
3
2
  import statistics
4
3
 
5
- def classify_rtt_latency(latency):
6
- if latency < 1:
7
- return "LAN or loopback same machine or local router"
8
- elif latency < 5:
9
- return "Local network — same building or direct fiber"
10
- elif latency < 20:
11
- return "Nearby region very low-latency ISP link"
12
- elif latency < 50:
13
- return "Fast WAN — CDN, local data center, or strong routing"
14
- elif latency < 100:
15
- return "Typical internet — stable ISP-to-ISP connection"
16
- elif latency < 200:
17
- return "Remote server possible transcontinental routing"
18
- elif latency < 400:
19
- return "High latency — distant, congested, or routed via relay"
20
- else:
21
- return "Unstable or suspicious — VPN, proxy, or degraded network"
22
-
23
- def ping_target(host, count=4):
24
- """
25
- Pings the given host and returns avg latency, loss %, estimated distance, and a basic label.
26
- """
4
+
5
+ FIBER_SPEED_KM_PER_MS = 200 # physical upper bound
6
+ REAL_WORLD_FACTOR = 0.5 # routing + overhead penalty
7
+ EFFECTIVE_SPEED = FIBER_SPEED_KM_PER_MS * REAL_WORLD_FACTOR
8
+
9
+
10
+ def estimate_distance_km(rtt_ms: float) -> tuple[int, int, int]:
11
+ one_way_ms = rtt_ms / 2
12
+
13
+ estimated = one_way_ms * EFFECTIVE_SPEED
14
+
15
+ min_km = int(estimated * 0.7)
16
+ max_km = int(estimated * 1.3)
17
+
18
+ return int(min_km), int(estimated), int(max_km)
19
+
20
+
21
+ def classify_latency(rtt_ms: float) -> str:
22
+ if rtt_ms < 1:
23
+ return "Loopback or same-host"
24
+ if rtt_ms < 5:
25
+ return "Local network / same building"
26
+ if rtt_ms < 20:
27
+ return "Metro or nearby region"
28
+ if rtt_ms < 50:
29
+ return "Regional / same country"
30
+ if rtt_ms < 100:
31
+ return "Inter-country"
32
+ if rtt_ms < 200:
33
+ return "Intercontinental"
34
+ return "Very distant or routed via relay/VPN"
35
+
36
+
37
+ def ping_target(host: str, count: int = 5, timeout: float = 1.0) -> dict:
27
38
  latencies = []
28
39
 
29
40
  for _ in range(count):
30
41
  try:
31
- delay = ping(host, timeout=1)
32
- if delay:
33
- latencies.append(delay)
42
+ delay = ping(host, timeout=timeout)
43
+ if delay is not None:
44
+ latencies.append(delay * 1000) # ms
34
45
  except Exception:
35
46
  continue
36
47
 
48
+ sent = count
37
49
  received = len(latencies)
38
- lost = count - received
50
+ lost = sent - received
39
51
 
40
52
  if received == 0:
41
- return f"Ping to {host}: unreachable ({count} packets lost)"
53
+ return {
54
+ "reachable": False,
55
+ "sent": sent,
56
+ "received": 0,
57
+ "packet_loss_percent": 100.0,
58
+ }
59
+
60
+ min_rtt = round(min(latencies), 2)
61
+ avg_rtt = round(statistics.mean(latencies), 2)
62
+ med_rtt = round(statistics.median(latencies), 2)
63
+ max_rtt = round(max(latencies), 2)
64
+
65
+ min_km, est_km, max_km = estimate_distance_km(med_rtt)
66
+
67
+ return {
68
+ "reachable": True,
69
+ "sent": sent,
70
+ "received": received,
71
+ "packet_loss_percent": round((lost / sent) * 100, 1),
72
+ "rtt_ms": {
73
+ "min": min_rtt,
74
+ "avg": avg_rtt,
75
+ "median": med_rtt,
76
+ "max": max_rtt,
77
+ },
78
+ "distance_km": {
79
+ "estimated": est_km,
80
+ "min": min_km,
81
+ "max": max_km,
82
+ },
83
+ "classification": classify_latency(med_rtt),
84
+ }
42
85
 
43
- avg_latency_ms = round(statistics.mean(latencies) * 1000, 2)
44
- packet_loss = round((lost / count) * 100, 1)
45
86
 
46
- # Go back to fast, rough RTT-based estimate: 200 km/ms
47
- estimated_distance_km = round((avg_latency_ms / 2) * 200)
48
- label = classify_rtt_latency(avg_latency_ms)
87
+ def format_ping_result(result: dict) -> None:
88
+ if not result.get("reachable"):
89
+ print("Host unreachable (100% packet loss)")
90
+ return
49
91
 
50
- return (
51
- f"Ping to {host} ({count} packets):\n"
52
- f" Avg Latency: {avg_latency_ms} ms\n"
53
- f" Packet Loss: {packet_loss}%\n"
54
- f" Est. Distance: ~{estimated_distance_km} km (RTT-based)\n"
55
- f" Inference: {label}"
92
+ print(f"Packets: sent={result['sent']} received={result['received']}")
93
+ print(f"Packet loss: {result['packet_loss_percent']}%")
94
+
95
+ rtt = result["rtt_ms"]
96
+ print(
97
+ f"RTT (ms): min={rtt['min']} avg={rtt['avg']} "
98
+ f"median={rtt['median']} max={rtt['max']}"
99
+ )
100
+
101
+ dist = result["distance_km"]
102
+ print(
103
+ f"Estimated distance: ~{dist['estimated']} km "
104
+ f"(range {dist['min']}–{dist['max']} km)"
56
105
  )
106
+
107
+ print(f"Inference: {result['classification']}")
@@ -1,70 +1,95 @@
1
- # utils/trace.py
2
1
  import subprocess
3
2
  import platform
4
- import re
5
3
  import ipaddress
6
- from yougotmapped.utils.network import get_geolocation
4
+ import re
7
5
 
8
- def run_traceroute(host, max_hops=30, timeout=60):
9
- system = platform.system()
10
- if system == "Windows":
11
- cmd = ["tracert", "-h", str(max_hops), host]
12
- elif system in ["Linux", "Darwin"]:
13
- cmd = ["traceroute", "-m", str(max_hops), "-w", "1", host]
14
- else:
15
- return f"Traceroute not supported on {system}"
6
+ from yougotmapped.utils.network import get_hop_location
16
7
 
17
- try:
18
- result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
19
- return format_trace_output(result.stdout)
20
- except subprocess.TimeoutExpired:
21
- return f"Traceroute to {host} timed out after {timeout} seconds."
22
- except FileNotFoundError:
23
- return f"Traceroute command not found on this system."
24
- except Exception as e:
25
- return f"Traceroute failed: {e}"
26
8
 
9
+ IP_REGEX = re.compile(r"(\d{1,3}(?:\.\d{1,3}){3})")
10
+ RTT_REGEX = re.compile(r"(\d+(?:\.\d+)?)\s*ms")
27
11
 
28
- def is_private_ip(ip):
12
+
13
+ def _is_private_ip(ip: str) -> bool:
29
14
  try:
30
15
  return ipaddress.ip_address(ip).is_private
31
16
  except ValueError:
32
17
  return False
33
18
 
34
19
 
35
- def extract_ip_latency(line):
36
- ip_match = re.findall(r"(\d+\.\d+\.\d+\.\d+)", line)
37
- rtt_match = re.findall(r"(\d+\.\d+) ms", line)
38
- return ip_match[0] if ip_match else None, rtt_match[0] if rtt_match else None
20
+ def _build_traceroute_command(host: str, max_hops: int) -> list[str]:
21
+ if platform.system() == "Windows":
22
+ return ["tracert", "-h", str(max_hops), host]
23
+
24
+ return ["traceroute", "-m", str(max_hops), "-w", "1", host]
39
25
 
40
26
 
41
- def format_trace_output(raw_output):
42
- lines = raw_output.strip().split("\n")
43
- formatted_lines = []
44
- last_ip = None
27
+ def run_traceroute(
28
+ host: str,
29
+ max_hops: int = 30,
30
+ timeout: int = 60,
31
+ ) -> dict:
32
+ cmd = _build_traceroute_command(host, max_hops)
45
33
 
46
- for index, line in enumerate(lines):
47
- ip, rtt = extract_ip_latency(line)
48
- if not ip:
34
+ try:
35
+ proc = subprocess.run(
36
+ cmd,
37
+ capture_output=True,
38
+ text=True,
39
+ timeout=timeout,
40
+ )
41
+ except subprocess.TimeoutExpired:
42
+ return {"error": "Traceroute timed out"}
43
+ except FileNotFoundError:
44
+ return {"error": "Traceroute command not found"}
45
+ except Exception as exc:
46
+ return {"error": str(exc)}
47
+
48
+ hops = []
49
+
50
+ for index, line in enumerate(proc.stdout.splitlines(), start=1):
51
+ ips = IP_REGEX.findall(line)
52
+ if not ips:
49
53
  continue
50
54
 
51
- label = "(Private)" if is_private_ip(ip) else extract_label(line)
52
- formatted_lines.append(f"[{index+1}] {ip.ljust(18)} {label.ljust(30)} {rtt} ms")
53
- last_ip = ip
55
+ ip = ips[0]
56
+ private = _is_private_ip(ip)
57
+
58
+ rtts = [float(x) for x in RTT_REGEX.findall(line)]
59
+ rtt_ms = rtts if rtts else None
60
+
61
+ hop_geo = None
62
+ if not private:
63
+ hop_geo = get_hop_location(ip)
64
+
65
+ hops.append({
66
+ "hop": index,
67
+ "ip": ip,
68
+ "private": private,
69
+ "rtt_ms": rtt_ms,
70
+ "latitude": hop_geo.get("latitude") if hop_geo else None,
71
+ "longitude": hop_geo.get("longitude") if hop_geo else None,
72
+ })
73
+
74
+ return {
75
+ "target": host,
76
+ "hops": hops,
77
+ }
78
+
54
79
 
55
- # Append final geolocation if last IP is public
56
- if last_ip and not is_private_ip(last_ip):
57
- data = get_geolocation(last_ip, None)
58
- if data:
59
- geo_info = f" --> {data.get('city', 'N/A')}, {data.get('region', '')} ({data.get('org', 'N/A')})"
60
- formatted_lines.append(geo_info)
80
+ def format_traceroute(result: dict) -> None:
81
+ if "error" in result:
82
+ print(f"Traceroute error: {result['error']}")
83
+ return
61
84
 
62
- return "\n".join(formatted_lines)
85
+ for hop in result.get("hops", []):
86
+ hop_no = hop["hop"]
87
+ ip = hop["ip"]
88
+ label = "PRIVATE" if hop["private"] else "PUBLIC"
63
89
 
90
+ rtt = hop["rtt_ms"]
91
+ rtt_display = (
92
+ f"{min(rtt):.1f} ms" if isinstance(rtt, list) else "*"
93
+ )
64
94
 
65
- def extract_label(line):
66
- parts = line.split()
67
- for part in parts:
68
- if any(ext in part for ext in [".com", ".net", ".org"]):
69
- return f"({part})"
70
- return "(Public)"
95
+ print(f"[{hop_no:>2}] {ip:<15} {label:<7} {rtt_display}")
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: yougotmapped
3
+ Version: 1.1.0
4
+ Summary: A terminal tool to map IPs and domains with style.
5
+ Author-email: diputs <diputs-sudo@proton.me>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/diputs-sudo/YouGotMapped
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: requests
15
+ Requires-Dist: folium
16
+ Requires-Dist: ping3
17
+ Requires-Dist: scapy
18
+ Dynamic: license-file
19
+
20
+ # YouGotMapped
21
+
22
+ ![Example traceroute and geographic routing visualization generated by YouGotMapped](docs/example-output.png)
23
+
24
+ YouGotMapped is a command-line network intelligence and visualization tool that correlates IP addresses and domains with geographic, routing, and performance data.
25
+
26
+ It integrates geolocation, latency analysis, traceroute inspection, and anonymity detection into a single, structured workflow, producing both human-readable output and machine-consumable logs.
27
+
28
+ ---
29
+
30
+ ## Overview
31
+
32
+ YouGotMapped is designed to provide visibility into how traffic traverses networks and where endpoints are geographically represented. It is suitable for diagnostic, educational, and research use in environments where the user has appropriate authorization.
33
+
34
+ The tool emphasizes clarity, traceability, and reproducibility of results.
35
+
36
+ ---
37
+
38
+ ## Key Capabilities
39
+
40
+ - IP and domain geolocation
41
+ - Interactive geographic visualization via HTML maps
42
+ - ICMP-based reachability and latency measurement
43
+ - Jitter analysis and stability inference
44
+ - TCP MSS discovery
45
+ - Bandwidth estimation using TCP performance models
46
+ - Hop-by-hop traceroute with geographic correlation
47
+ - VPN, proxy, and anonymity signal detection
48
+ - Structured output in JSON, CSV, or plain text formats
49
+
50
+ ---
51
+
52
+ ## Intended Use
53
+
54
+ YouGotMapped is intended for:
55
+
56
+ - Network diagnostics and troubleshooting
57
+ - Infrastructure visibility and analysis
58
+ - Educational exploration of routing behavior
59
+ - Authorized reconnaissance in controlled environments
60
+
61
+ Users are responsible for ensuring they have explicit permission to analyze any systems or networks they do not own.
62
+
63
+ ---
64
+
65
+ ## Prohibited Use
66
+
67
+ This project must not be used for:
68
+
69
+ - Unauthorized monitoring or surveillance
70
+ - Targeting individuals or private infrastructure
71
+ - Harassment, exploitation, or data misuse
72
+ - Any activity that violates applicable laws or policies
73
+
74
+ ---
75
+
76
+ ## Requirements
77
+
78
+ - Python 3.8 or newer
79
+ - Network access permitting ICMP and TCP probes
80
+ - Runtime dependencies:
81
+ - `requests`
82
+ - `folium`
83
+ - `ping3`
84
+ - `scapy`
85
+
86
+ Dependencies are validated at startup.
87
+
88
+ ---
89
+
90
+ ## Installation
91
+
92
+ YouGotMapped can be installed directly from PyPI:
93
+
94
+ ```bash
95
+ pip install yougotmapped
96
+ ```
97
+
98
+ After installation, the `yougotmapped` command is available on the system PATH.
99
+
100
+ ### From Source
101
+
102
+ Clone the repository:
103
+
104
+ ```bash
105
+ git clone https://github.com/your-username/YouGotMapped.git
106
+ cd YouGotMapped
107
+ ```
108
+
109
+ Install dependencies:
110
+
111
+ ```bash
112
+ pip install -r requirements.txt
113
+ ```
114
+
115
+ Running from Source:
116
+
117
+ ```bash
118
+ python -m yougotmapped.cli
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Usage
124
+
125
+ Analyze a single target using all available modules:
126
+
127
+ ```bash
128
+ yougotmapped -i 8.8.8.8 -a
129
+ ```
130
+
131
+ Export results as JSON:
132
+
133
+ ```bash
134
+ yougotmapped -i 8.8.8.8 -a -o f:json
135
+ ```
136
+
137
+ Disable map generation:
138
+
139
+ ```bash
140
+ yougotmapped -i example.com -t --no-map
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Command-Line Options
146
+
147
+ ```text
148
+ -i, --ip [IP ...] IP addresses or domains
149
+ -f, --file FILE Input file with targets
150
+ -p, --ping Latency and reachability test
151
+ -j, --jitter Jitter and stability analysis
152
+ -m, --mtu MTU / MSS discovery
153
+ -b, --bandwidth Bandwidth estimation
154
+ -t, --trace Traceroute analysis
155
+ -c, --hidecheck Anonymity detection
156
+ -a, --all Run all modules
157
+ --no-map Disable map output
158
+ -o, --output Output format (f:json, f:csv, f:normal)
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Output
164
+
165
+ Each execution produces:
166
+
167
+ * Structured log files with timestamps
168
+ * Optional interactive HTML maps
169
+ * Terminal summaries for immediate inspection
170
+
171
+ Outputs are designed to be both auditable and reproducible.
172
+
173
+ ---
174
+
175
+ ## Legal Notice
176
+
177
+ By using this software, you acknowledge that:
178
+
179
+ * You have authorization to analyze the specified targets
180
+ * You accept full responsibility for its use
181
+ * The author is not liable for misuse or resulting damages
182
+
183
+ This software is provided for educational and research purposes.
184
+
185
+ ---
186
+
187
+ ## Contributing
188
+
189
+ Contributions are welcome if they improve accuracy, reliability, or clarity and adhere to ethical and legal standards. Functionality that materially enables misuse will not be accepted.
190
+
191
+ ---
192
+
193
+ ## License
194
+
195
+ This project is licensed under the MIT License. See the LICENSE file for details.
196
+
@@ -0,0 +1,21 @@
1
+ yougotmapped/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ yougotmapped/cli.py,sha256=wK4y2Oh1iGiBXdJ6stMJ6veajS6-_0ZXh5OxsWnjHHo,7399
3
+ yougotmapped/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ yougotmapped/utils/anonymity.py,sha256=qi2vdNsnppYwounC1OQdaAs21FqmNj4KewtDh3e5H7c,2439
5
+ yougotmapped/utils/bandwidth.py,sha256=6jVUPNn4e0DM_mwN5k5AwVSzNoipY1DmWqZZpbbOtTw,1526
6
+ yougotmapped/utils/dependencies.py,sha256=hF_r2PDBGfXgKeOyDc-iTtOzmdvBlR95iUnJZ0soimo,1494
7
+ yougotmapped/utils/ingress.py,sha256=X9Gp11KnKMBwaox3W4tAaQs52ICiDPSMWJwwLSrIg4w,1692
8
+ yougotmapped/utils/jitter.py,sha256=Kuc66BbywBoFDmbi-FRkMrx21r9YBlqfFhUI9GQuT_g,1940
9
+ yougotmapped/utils/mapping.py,sha256=j-kPVEFocNy8fUvjdxr9H5hDSbvSLVNEek6J9xJ0Vlc,2719
10
+ yougotmapped/utils/mss.py,sha256=KK8gVtnzpYi9c8eM313BC4X_wPx1wOGis4vTZgdNs_Q,3029
11
+ yougotmapped/utils/mtu.py,sha256=ZbjLhNRko0ngYEPBKtZbnOTtXIlxcm-ylYOIz_SReZM,1772
12
+ yougotmapped/utils/network.py,sha256=kq_uFKq2vpzDdZ9s748ke-NzLS3Y_woARSB3htNC8Qg,2173
13
+ yougotmapped/utils/output.py,sha256=1nLRr3X-o_KdsUASWXhvS9TibZOv05X_Inj7_a2ZCWI,1867
14
+ yougotmapped/utils/ping.py,sha256=TbI-lWSR6OaYKRpYqmUNEraW-nhkh5F-9WJd7jl7bto,2866
15
+ yougotmapped/utils/trace.py,sha256=dKDpxcMnrZd-y6jjqTMrl6_ylIwYSreZMOmXXvbwHrw,2383
16
+ yougotmapped-1.1.0.dist-info/licenses/LICENSE,sha256=E9UVVmDEpddJlGAMso045DiZPv_MO-UdjzTXkhiG7ps,1068
17
+ yougotmapped-1.1.0.dist-info/METADATA,sha256=1p8ZuWX9wLV_epP93rhURl1_YjpJmbl5FldS9SVeRvE,4790
18
+ yougotmapped-1.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
19
+ yougotmapped-1.1.0.dist-info/entry_points.txt,sha256=zv6jK4RV-3qvJ59qY1dZxML0g3qahKVMztwobKtTP-Q,55
20
+ yougotmapped-1.1.0.dist-info/top_level.txt,sha256=XYHTw9YTF8Rz9Xj06Gh-xEl5IYs467gQR4BYlNrxZmM,13
21
+ yougotmapped-1.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,9 +1,9 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 diputs
3
+ Copyright (c) 2025 diputs-sudo
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the Software), to deal
6
+ of this software and associated documentation files (the "Software"), to deal
7
7
  in the Software without restriction, including without limitation the rights
8
8
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
9
  copies of the Software, and to permit persons to whom the Software is
@@ -12,16 +12,10 @@ furnished to do so, subject to the following conditions:
12
12
  The above copyright notice and this permission notice shall be included in all
13
13
  copies or substantial portions of the Software.
14
14
 
15
- THE SOFTWARE IS PROVIDED AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
16
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
17
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  SOFTWARE.
22
-
23
- ---
24
-
25
- 📝 Side note from the author:
26
- If this script crashes your terminal or geo-locates your toaster... that's on you.
27
- But hey — it worked flawlessly on my end. 🫠