diff --git a/.gitignore b/.gitignore
index de7246cf582f7ec3bf895bee5c1ad412a6f0d286..97e1e751af0c3582108b0f646ceb23139ff88a38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@
 .DS_Store
 __pycache__
 *.pyc
-*.zip
\ No newline at end of file
+*.zip
+.python-version
\ No newline at end of file
diff --git a/requirement.txt b/requirements.txt
similarity index 100%
rename from requirement.txt
rename to requirements.txt
diff --git a/src/tree.py b/src/tree.py
index d1f06469f5456ed8602fc8da6ae66dbeeb251cc8..6c183e1cd2aebc5f05d985fbd7dd696276b69da9 100644
--- a/src/tree.py
+++ b/src/tree.py
@@ -4,7 +4,7 @@ import os
 import re
 import sys
 import uuid
-import re
+
 import git
 
 id_set = set()
@@ -16,12 +16,21 @@ handler.setFormatter(formatter)
 logger.addHandler(handler)
 repo = git.Repo(".")
 
+
 def user_name():
     return repo.config_reader().get_value("user", "name")
 
+
+_DEFAULT_ENCODING = 'utf-8'
+
+
+def read_text(filepath):
+    with open(filepath, 'r', encoding='utf-8') as f:
+        return f.read()
+
+
 def load_json(p):
-    with open(p, 'r') as f:
-        return json.loads(f.read())
+    return json.loads(read_text(p))
 
 
 def dump_json(p, j, exist_ok=False, override=False):
@@ -177,7 +186,7 @@ class TreeWalker:
             posted = os.path.join(base, f"{index + 1}.{title}")
             if origin != posted:
                 self.logger.info(f"rename [{origin}] to [{posted}]")
-            os.rename(origin, posted)
+                os.rename(origin, posted)
         return children
 
     def ensure_chapters(self):
@@ -338,8 +347,7 @@ class TreeWalker:
         _, mfile = os.path.split(meta_path)
         meta = None
         if os.path.exists(meta_path):
-            with open(meta_path) as f:
-                content = f.read()
+            content = read_text(meta_path)
             if content:
                 meta = json.loads(content)
                 if "exercise_id" not in meta: