typing-cli 0.3.2__tar.gz → 0.3.3__tar.gz
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.
- {typing_cli-0.3.2/src/typing_cli.egg-info → typing_cli-0.3.3}/PKG-INFO +7 -1
- {typing_cli-0.3.2 → typing_cli-0.3.3}/README.md +6 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/pyproject.toml +2 -2
- {typing_cli-0.3.2 → typing_cli-0.3.3/src/typing_cli.egg-info}/PKG-INFO +7 -1
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typing_cli.egg-info/SOURCES.txt +5 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/__init__.py +1 -1
- typing_cli-0.3.3/src/typingtest/data/code/go.json +13 -0
- typing_cli-0.3.3/src/typingtest/data/code/javascript.json +17 -0
- typing_cli-0.3.3/src/typingtest/data/code/python.json +20 -0
- typing_cli-0.3.3/src/typingtest/data/code/rust.json +13 -0
- typing_cli-0.3.3/src/typingtest/data/code/typescript.json +17 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/LICENSE +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/setup.cfg +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typing_cli.egg-info/dependency_links.txt +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typing_cli.egg-info/entry_points.txt +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typing_cli.egg-info/requires.txt +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typing_cli.egg-info/top_level.txt +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/__main__.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/core/__init__.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/core/config.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/core/generator.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/core/stats.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/core/tracker.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/core/updater.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/data/languages/english.json +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/data/languages/french.json +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/__init__.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/app.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/screens/__init__.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/screens/history.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/screens/result.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/screens/splash.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/screens/typing_screen.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/widgets/__init__.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/widgets/character.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/widgets/stats_bar.py +0 -0
- {typing_cli-0.3.2 → typing_cli-0.3.3}/src/typingtest/ui/widgets/typing_area.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typing-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: A beautiful CLI typing test to practice your typing speed
|
|
5
5
|
Author: lecoffre
|
|
6
6
|
License: MIT
|
|
@@ -95,6 +95,12 @@ You can also update manually:
|
|
|
95
95
|
pip install --user --upgrade typing-cli
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
+
## 🗑️ Uninstall
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip uninstall typing-cli -y
|
|
102
|
+
```
|
|
103
|
+
|
|
98
104
|
## ⌨️ Keyboard Shortcuts
|
|
99
105
|
|
|
100
106
|
| Shortcut | Action |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "typing-cli"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.3"
|
|
8
8
|
description = "A beautiful CLI typing test to practice your typing speed"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -45,7 +45,7 @@ typing-test = "typingtest.__main__:main"
|
|
|
45
45
|
where = ["src"]
|
|
46
46
|
|
|
47
47
|
[tool.setuptools.package-data]
|
|
48
|
-
typingtest = ["data/languages/*.json", "ui/css/*.tcss"]
|
|
48
|
+
typingtest = ["data/languages/*.json", "data/code/*.json", "ui/css/*.tcss"]
|
|
49
49
|
|
|
50
50
|
[tool.ruff]
|
|
51
51
|
target-version = "py310"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typing-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: A beautiful CLI typing test to practice your typing speed
|
|
5
5
|
Author: lecoffre
|
|
6
6
|
License: MIT
|
|
@@ -95,6 +95,12 @@ You can also update manually:
|
|
|
95
95
|
pip install --user --upgrade typing-cli
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
+
## 🗑️ Uninstall
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip uninstall typing-cli -y
|
|
102
|
+
```
|
|
103
|
+
|
|
98
104
|
## ⌨️ Keyboard Shortcuts
|
|
99
105
|
|
|
100
106
|
| Shortcut | Action |
|
|
@@ -15,6 +15,11 @@ src/typingtest/core/generator.py
|
|
|
15
15
|
src/typingtest/core/stats.py
|
|
16
16
|
src/typingtest/core/tracker.py
|
|
17
17
|
src/typingtest/core/updater.py
|
|
18
|
+
src/typingtest/data/code/go.json
|
|
19
|
+
src/typingtest/data/code/javascript.json
|
|
20
|
+
src/typingtest/data/code/python.json
|
|
21
|
+
src/typingtest/data/code/rust.json
|
|
22
|
+
src/typingtest/data/code/typescript.json
|
|
18
23
|
src/typingtest/data/languages/english.json
|
|
19
24
|
src/typingtest/data/languages/french.json
|
|
20
25
|
src/typingtest/ui/__init__.py
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Go",
|
|
3
|
+
"snippets": [
|
|
4
|
+
"func fibonacci(n int) int {\n\tif n <= 1 {\n\t\treturn n\n\t}\n\treturn fibonacci(n-1) + fibonacci(n-2)\n}",
|
|
5
|
+
"type Stack struct {\n\titems []interface{}\n}\n\nfunc (s *Stack) Push(item interface{}) {\n\ts.items = append(s.items, item)\n}\n\nfunc (s *Stack) Pop() interface{} {\n\tif len(s.items) == 0 {\n\t\treturn nil\n\t}\n\titem := s.items[len(s.items)-1]\n\ts.items = s.items[:len(s.items)-1]\n\treturn item\n}",
|
|
6
|
+
"func binarySearch(arr []int, target int) int {\n\tlow, high := 0, len(arr)-1\n\tfor low <= high {\n\t\tmid := (low + high) / 2\n\t\tif arr[mid] == target {\n\t\t\treturn mid\n\t\t} else if arr[mid] < target {\n\t\t\tlow = mid + 1\n\t\t} else {\n\t\t\thigh = mid - 1\n\t\t}\n\t}\n\treturn -1\n}",
|
|
7
|
+
"func wordCount(text string) map[string]int {\n\tcounts := make(map[string]int)\n\twords := strings.Fields(text)\n\tfor _, word := range words {\n\t\tcounts[word]++\n\t}\n\treturn counts\n}",
|
|
8
|
+
"type Server struct {\n\taddr string\n\tport int\n}\n\nfunc NewServer(addr string, port int) *Server {\n\treturn &Server{addr: addr, port: port}\n}\n\nfunc (s *Server) Start() error {\n\tlistener, err := net.Listen(\"tcp\", fmt.Sprintf(\"%s:%d\", s.addr, s.port))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer listener.Close()\n\treturn nil\n}",
|
|
9
|
+
"func isPalindrome(s string) bool {\n\trunes := []rune(strings.ToLower(s))\n\tfor i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {\n\t\tif runes[i] != runes[j] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}",
|
|
10
|
+
"func fetchURL(url string) ([]byte, error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\treturn io.ReadAll(resp.Body)\n}",
|
|
11
|
+
"func merge(ch1, ch2 <-chan int) <-chan int {\n\tout := make(chan int)\n\tgo func() {\n\t\tdefer close(out)\n\t\tfor ch1 != nil || ch2 != nil {\n\t\t\tselect {\n\t\t\tcase v, ok := <-ch1:\n\t\t\t\tif !ok { ch1 = nil } else { out <- v }\n\t\t\tcase v, ok := <-ch2:\n\t\t\t\tif !ok { ch2 = nil } else { out <- v }\n\t\t\t}\n\t\t}\n\t}()\n\treturn out\n}"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "JavaScript",
|
|
3
|
+
"snippets": [
|
|
4
|
+
"function debounce(fn, delay) {\n let timer;\n return function (...args) {\n clearTimeout(timer);\n timer = setTimeout(() => fn.apply(this, args), delay);\n };\n}",
|
|
5
|
+
"class LinkedList {\n constructor() {\n this.head = null;\n this.size = 0;\n }\n\n add(value) {\n const node = { value, next: this.head };\n this.head = node;\n this.size++;\n }\n}",
|
|
6
|
+
"const flatten = (arr) => {\n return arr.reduce((acc, item) => {\n return acc.concat(\n Array.isArray(item) ? flatten(item) : item\n );\n }, []);\n};",
|
|
7
|
+
"async function fetchJSON(url) {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP error: ${response.status}`);\n }\n return response.json();\n}",
|
|
8
|
+
"const pipe = (...fns) => (x) =>\n fns.reduce((acc, fn) => fn(acc), x);\n\nconst double = (x) => x * 2;\nconst addOne = (x) => x + 1;\nconst result = pipe(double, addOne)(5);",
|
|
9
|
+
"const groupBy = (arr, key) => {\n return arr.reduce((groups, item) => {\n const val = item[key];\n groups[val] = groups[val] || [];\n groups[val].push(item);\n return groups;\n }, {});\n};",
|
|
10
|
+
"function* range(start, end, step = 1) {\n for (let i = start; i < end; i += step) {\n yield i;\n }\n}\n\nconst nums = [...range(0, 10, 2)];",
|
|
11
|
+
"const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n entry.target.classList.add('visible');\n }\n });\n },\n { threshold: 0.5 }\n);",
|
|
12
|
+
"const memoize = (fn) => {\n const cache = new Map();\n return (...args) => {\n const key = JSON.stringify(args);\n if (cache.has(key)) return cache.get(key);\n const result = fn(...args);\n cache.set(key, result);\n return result;\n };\n};",
|
|
13
|
+
"try {\n const data = JSON.parse(input);\n const { name, age } = data;\n console.log(`${name} is ${age} years old`);\n} catch (err) {\n console.error('Invalid JSON:', err.message);\n}",
|
|
14
|
+
"const EventBus = {\n events: {},\n on(event, fn) {\n this.events[event] = this.events[event] || [];\n this.events[event].push(fn);\n },\n emit(event, ...args) {\n (this.events[event] || []).forEach(fn => fn(...args));\n }\n};",
|
|
15
|
+
"const deepClone = (obj) => {\n if (obj === null || typeof obj !== 'object') return obj;\n const clone = Array.isArray(obj) ? [] : {};\n for (const key in obj) {\n clone[key] = deepClone(obj[key]);\n }\n return clone;\n};"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Python",
|
|
3
|
+
"snippets": [
|
|
4
|
+
"def fibonacci(n):\n if n <= 1:\n return n\n return fibonacci(n - 1) + fibonacci(n - 2)",
|
|
5
|
+
"class Stack:\n def __init__(self):\n self.items = []\n\n def push(self, item):\n self.items.append(item)\n\n def pop(self):\n return self.items.pop()",
|
|
6
|
+
"def binary_search(arr, target):\n low, high = 0, len(arr) - 1\n while low <= high:\n mid = (low + high) // 2\n if arr[mid] == target:\n return mid\n elif arr[mid] < target:\n low = mid + 1\n else:\n high = mid - 1\n return -1",
|
|
7
|
+
"from typing import List\n\ndef merge_sort(arr: List[int]) -> List[int]:\n if len(arr) <= 1:\n return arr\n mid = len(arr) // 2\n left = merge_sort(arr[:mid])\n right = merge_sort(arr[mid:])\n return merge(left, right)",
|
|
8
|
+
"def is_palindrome(s: str) -> bool:\n cleaned = ''.join(c.lower() for c in s if c.isalnum())\n return cleaned == cleaned[::-1]",
|
|
9
|
+
"import json\nfrom pathlib import Path\n\ndef load_config(path: str) -> dict:\n data = Path(path).read_text()\n return json.loads(data)",
|
|
10
|
+
"class LinkedList:\n def __init__(self, val=0, next=None):\n self.val = val\n self.next = next\n\n def to_list(self):\n result = []\n node = self\n while node:\n result.append(node.val)\n node = node.next\n return result",
|
|
11
|
+
"def flatten(nested: list) -> list:\n result = []\n for item in nested:\n if isinstance(item, list):\n result.extend(flatten(item))\n else:\n result.append(item)\n return result",
|
|
12
|
+
"from functools import lru_cache\n\n@lru_cache(maxsize=None)\ndef count_ways(n: int) -> int:\n if n <= 0:\n return 1\n if n < 0:\n return 0\n return count_ways(n - 1) + count_ways(n - 2)",
|
|
13
|
+
"with open('data.csv', 'r') as f:\n reader = csv.reader(f)\n headers = next(reader)\n for row in reader:\n process(row)",
|
|
14
|
+
"def decorator(func):\n def wrapper(*args, **kwargs):\n print(f'Calling {func.__name__}')\n result = func(*args, **kwargs)\n print(f'Done: {result}')\n return result\n return wrapper",
|
|
15
|
+
"async def fetch_data(url: str) -> dict:\n async with aiohttp.ClientSession() as session:\n async with session.get(url) as resp:\n return await resp.json()",
|
|
16
|
+
"try:\n result = int(user_input)\n if result < 0:\n raise ValueError('Must be positive')\nexcept ValueError as e:\n print(f'Error: {e}')\nfinally:\n print('Done')",
|
|
17
|
+
"nums = [1, 2, 3, 4, 5, 6, 7, 8]\nevens = [x for x in nums if x % 2 == 0]\nsquares = {x: x**2 for x in nums}\ntotal = sum(x**2 for x in evens)",
|
|
18
|
+
"class Counter:\n def __init__(self):\n self._count = 0\n\n @property\n def count(self):\n return self._count\n\n def increment(self):\n self._count += 1"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Rust",
|
|
3
|
+
"snippets": [
|
|
4
|
+
"fn fibonacci(n: u32) -> u32 {\n match n {\n 0 => 0,\n 1 => 1,\n _ => fibonacci(n - 1) + fibonacci(n - 2),\n }\n}",
|
|
5
|
+
"struct Point {\n x: f64,\n y: f64,\n}\n\nimpl Point {\n fn new(x: f64, y: f64) -> Self {\n Point { x, y }\n }\n\n fn distance(&self, other: &Point) -> f64 {\n ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()\n }\n}",
|
|
6
|
+
"fn binary_search(arr: &[i32], target: i32) -> Option<usize> {\n let mut low = 0;\n let mut high = arr.len();\n while low < high {\n let mid = low + (high - low) / 2;\n match arr[mid].cmp(&target) {\n Ordering::Equal => return Some(mid),\n Ordering::Less => low = mid + 1,\n Ordering::Greater => high = mid,\n }\n }\n None\n}",
|
|
7
|
+
"enum Shape {\n Circle(f64),\n Rectangle(f64, f64),\n Triangle(f64, f64),\n}\n\nimpl Shape {\n fn area(&self) -> f64 {\n match self {\n Shape::Circle(r) => std::f64::consts::PI * r * r,\n Shape::Rectangle(w, h) => w * h,\n Shape::Triangle(b, h) => 0.5 * b * h,\n }\n }\n}",
|
|
8
|
+
"use std::collections::HashMap;\n\nfn word_count(text: &str) -> HashMap<&str, usize> {\n let mut counts = HashMap::new();\n for word in text.split_whitespace() {\n *counts.entry(word).or_insert(0) += 1;\n }\n counts\n}",
|
|
9
|
+
"fn flatten<T: Clone>(nested: &[Vec<T>]) -> Vec<T> {\n nested.iter().flat_map(|v| v.clone()).collect()\n}",
|
|
10
|
+
"struct Stack<T> {\n items: Vec<T>,\n}\n\nimpl<T> Stack<T> {\n fn new() -> Self {\n Stack { items: Vec::new() }\n }\n\n fn push(&mut self, item: T) {\n self.items.push(item);\n }\n\n fn pop(&mut self) -> Option<T> {\n self.items.pop()\n }\n}",
|
|
11
|
+
"fn is_palindrome(s: &str) -> bool {\n let cleaned: String = s.chars()\n .filter(|c| c.is_alphanumeric())\n .map(|c| c.to_lowercase().next().unwrap())\n .collect();\n cleaned == cleaned.chars().rev().collect::<String>()\n}"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "TypeScript",
|
|
3
|
+
"snippets": [
|
|
4
|
+
"function fibonacci(n: number): number {\n if (n <= 1) return n;\n return fibonacci(n - 1) + fibonacci(n - 2);\n}",
|
|
5
|
+
"interface User {\n id: number;\n name: string;\n email: string;\n isActive: boolean;\n}\n\nfunction greet(user: User): string {\n return `Hello, ${user.name}!`;\n}",
|
|
6
|
+
"class Stack<T> {\n private items: T[] = [];\n\n push(item: T): void {\n this.items.push(item);\n }\n\n pop(): T | undefined {\n return this.items.pop();\n }\n\n get size(): number {\n return this.items.length;\n }\n}",
|
|
7
|
+
"const binarySearch = (arr: number[], target: number): number => {\n let low = 0;\n let high = arr.length - 1;\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n if (arr[mid] === target) return mid;\n if (arr[mid] < target) low = mid + 1;\n else high = mid - 1;\n }\n return -1;\n};",
|
|
8
|
+
"type Result<T, E> = \n | { ok: true; value: T }\n | { ok: false; error: E };\n\nfunction divide(a: number, b: number): Result<number, string> {\n if (b === 0) return { ok: false, error: 'Division by zero' };\n return { ok: true, value: a / b };\n}",
|
|
9
|
+
"async function fetchData<T>(url: string): Promise<T> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n return response.json() as Promise<T>;\n}",
|
|
10
|
+
"const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n delay: number\n): ((...args: Parameters<T>) => void) => {\n let timer: ReturnType<typeof setTimeout>;\n return (...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => fn(...args), delay);\n };\n};",
|
|
11
|
+
"enum Direction {\n Up = 'UP',\n Down = 'DOWN',\n Left = 'LEFT',\n Right = 'RIGHT',\n}\n\nfunction move(dir: Direction): void {\n console.log(`Moving ${dir}`);\n}",
|
|
12
|
+
"const nums: number[] = [1, 2, 3, 4, 5];\nconst doubled = nums.map(x => x * 2);\nconst evens = nums.filter(x => x % 2 === 0);\nconst sum = nums.reduce((acc, x) => acc + x, 0);",
|
|
13
|
+
"class EventEmitter {\n private listeners: Map<string, Function[]> = new Map();\n\n on(event: string, fn: Function): void {\n const fns = this.listeners.get(event) || [];\n fns.push(fn);\n this.listeners.set(event, fns);\n }\n\n emit(event: string, ...args: any[]): void {\n const fns = this.listeners.get(event) || [];\n fns.forEach(fn => fn(...args));\n }\n}",
|
|
14
|
+
"function groupBy<T>(arr: T[], key: keyof T): Record<string, T[]> {\n return arr.reduce((acc, item) => {\n const k = String(item[key]);\n (acc[k] = acc[k] || []).push(item);\n return acc;\n }, {} as Record<string, T[]>);\n}",
|
|
15
|
+
"const memoize = <T extends (...args: any[]) => any>(fn: T): T => {\n const cache = new Map<string, ReturnType<T>>();\n return ((...args: any[]) => {\n const key = JSON.stringify(args);\n if (cache.has(key)) return cache.get(key)!;\n const result = fn(...args);\n cache.set(key, result);\n return result;\n }) as T;\n};"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|