Có một phần mềm định kỳ cho phép tôi làm bài tập số học tinh thần?


9

Tôi nhận thức được bản chất lười biếng của mình và cần thúc đẩy bản thân thực hiện một số số học tinh thần cơ bản theo thời gian. Do đó, tôi đang tìm kiếm một phần mềm định kỳ yêu cầu tôi thực hiện một bài tập số học tinh thần ngắn (cộng, trừ, nhân, chia).

Tiêu chí:

  • Nó sẽ cho phép tôi tùy chỉnh thời gian
  • Nó nên tích hợp trong Ubuntu Desktop, tức là được ẩn trong nền và chỉ hiển thị (bật lên) trong thời gian tập thể dục

2
Tôi nghi ngờ phần mềm như vậy tồn tại, nhưng có thể được tạo ra rất dễ dàng với một tập lệnh shell hoặc python. Tôi sẽ nấu món gì đó vào ngày mai, xin vui lòng nhắc nhở tôi
Sergiy Kolodyazhnyy

Vâng, bsdgames có số học và như vậy nhưng bạn phải tự động hóa các cửa sổ bật lên định kỳ.
mchid

Gửi @Serg, tôi vui lòng nhắc bạn về thí nghiệm nấu ăn của bạn. :)
orschiro

1
Vì vậy, tôi đã đăng một câu trả lời đang thực hiện, mà tôi sẽ chỉnh sửa khi tôi đi cùng. Hãy xem, cho tôi biết những gì bạn nghĩ, chức năng để thêm hoặc loại bỏ. Cho đến nay đây là một ứng dụng giao diện điều khiển, nhưng cuối cùng nó sẽ biến thành một cửa sổ bật lên nhỏ.
Sergiy Kolodyazhnyy

2
Hóa ra là một câu hỏi hay để làm việc!
Jacob Vlijm

Câu trả lời:


8

1. Phiên bản đơn giản

Kịch bản dưới đây sẽ tạo ra bài tập một cách ngẫu nhiên, + , - , x÷ . Bạn có thể (và nên) đặt số lượng tối đa mà tập lệnh có thể sử dụng, cũng như khoảng thời gian giữa các bài tập.

Bài tập

Các bài tập được trình bày trong cửa sổ nhập Zenity:

nhập mô tả hình ảnh ở đây

nếu câu trả lời sai:

nhập mô tả hình ảnh ở đây

Nếu câu trả lời là đúng:

nhập mô tả hình ảnh ở đây

Kịch bản

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time

# maximum number & interval
max_n = int(sys.argv[1]); pause = int(sys.argv[2])

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """
    n1 = randint(2, max_n); n2 = randint(2, max_n)
    assignments = [
        [str(n1)+" + "+str(n2), n1+n2],
        [str(n1)+" - "+str(n2), n1-n2],
        [str(n1)+" x "+str(n2), n1*n2],
        fix_float(n1),
        ]
    # pick an assignment (type) at random
    assignment = assignments[randint(0, 3)]
    # if the random number is a prime number and the assignment a division...
    assignment = assignment if assignment != None else assignments[1]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
    except (subprocess.CalledProcessError, ValueError):
        pass

while True:
    time.sleep(pause)
    get_assignment()

Cách sử dụng

  1. Sao chép tập lệnh vào một tập tin trống, lưu nó dưới dạng mindpractice.py
  2. Chạy nó với số lượng tối đa được phép và khoảng thời gian (tính bằng giây) giữa các bài tập dưới dạng đối số:

    python3 /path/to/mindpractice.py <max_number> <interval>

    ví dụ

    python3 /path/to/mindpractice.py 1000 300

    để thực hiện các phép tính lên đến số liệu 1000, với thời gian nghỉ 5 phút giữa các bài tập.

  3. Nếu tất cả đều hoạt động tốt, bạn có thể thêm nó vào các ứng dụng khởi động theo cách thông thường hoặc trình khởi chạy để chuyển đổi có thể được thực hiện, mà tôi có thể thêm sau :)

Ghi chú

  • Việc phân chia có thể cần một số lời giải thích. Bạn có thể không muốn tính toán trong phao. Do đó, nếu phép gán là một phép chia, tập lệnh sẽ tra cứu các số có thể được chia cho và chọn một số (ngẫu nhiên). Nếu số (chính) hóa ra là số nguyên tố, phép gán được thay đổi thành loại khác.

2. Nhiều lựa chọn hơn

Khi bạn bắt đầu tính toán, bạn sẽ thấy rằng việc chia tối đa cho các số liệu (giả sử) 100 dễ dàng hơn nhiều so với nhân số lên tới 100.

Với tập lệnh bên dưới, bạn có thể (và nên) đặt tối đa số cho mỗi loại bài tập (xem hướng dẫn bên dưới tập lệnh).

Kịch bản

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time

levels = sys.argv[1:]
pause = [int(arg.replace("p:", "")) for arg in levels if "p:" in arg][0]

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """
    # pick an assignment (type) at random
    track = randint(0, 3)
    arg = ["a:", "s:", "m:", "d:"][track]
    max_n = [int(item.replace(arg, "")) for item in levels if arg in item][0]

    n1 = randint(2, max_n); n2 = randint(2, max_n)
    assignments = [
        [str(n1)+" + "+str(n2), n1+n2],
        [str(n1)+" - "+str(n2), n1-n2],
        [str(n1)+" x "+str(n2), n1*n2],
        fix_float(n1),
        ]
    assignment = assignments[track]     
    # if the random number is a prime number and the assignment a division...
    assignment = assignment if assignment != None else assignments[1]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
    except (subprocess.CalledProcessError, ValueError):
        pass

while True:
    time.sleep(pause)
    get_assignment()

Cách sử dụng

  • Thiết lập tập lệnh chính xác như tập lệnh đầu tiên, nhưng chạy tập lệnh với các đối số (theo bất kỳ thứ tự nào, tập lệnh sẽ liên kết đúng các đối số với mục bên phải):

    • p: tạm dừng (nghỉ giữa các bài tập, tính bằng giây))
    • s: trừ (số tối đa để tính với)
    • a: thêm (số tối đa)
    • m: nhân (số tối đa)
    • d: chia (số tối đa)

    Ví dụ:

    python3 '/home/jacob/Desktop/num.py' a:10 d:100 s:10 m:10 p:300

    để hiển thị một bài tập cứ sau năm phút, số lượng lên tới 10, ngoại trừ chia cho hình 100.


3. Hãy mang đi một chút

Có thể xem một số thống kê

Phiên bản dưới đây cho bạn thấy số liệu thống kê sau mỗi 10 bài tập:

nhập mô tả hình ảnh ở đây

Ngoài ra (có thể hữu ích khi sử dụng cho trẻ em), bạn có thể thấy những gì đã sai trong 100 bài tập được trả lời sai cuối cùng. Trong một tệp ẩn, cả bài tập và câu trả lời (không chính xác) của chúng đều được viết:

nhập mô tả hình ảnh ở đây

Logfile này được đặt:

~/.calculog

Kịch bản

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time
import os

log = os.environ["HOME"]+"/.calculog"

levels = sys.argv[1:]
pause = [int(arg.replace("p:", "")) for arg in levels if "p:" in arg][0]

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """
    # pick an assignment (type) at random
    track = randint(0, 3)
    arg = ["a:", "s:", "m:", "d:"][track]
    max_n = [int(item.replace(arg, "")) for item in levels if arg in item][0]

    n1 = randint(2, max_n); n2 = randint(2, max_n)
    assignments = [
        [str(n1)+" + "+str(n2), n1+n2],
        [str(n1)+" - "+str(n2), n1-n2],
        [str(n1)+" x "+str(n2), n1*n2],
        fix_float(n1),
        ]
    assignment = assignments[track]     
    # if the random number is a prime number and the assignment a division...
    assignment = assignment if assignment != None else assignments[1]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
            return "ok"
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
            open(log, "+a").write(assignment[0]+"\t\t"+str(answer)+"\n")
            try:
                history = open(log).read().splitlines()
                open(log, "wt").write(("\n").join(history[-100:])+"\n")     
            except FileNotFoundError:
                pass 
            return "mistake"
    except (subprocess.CalledProcessError, ValueError):
        return None

results = []
while True:
    time.sleep(pause)
    results.append(get_assignment())
    if len(results) >= 10:
        score = results.count("ok")
        subprocess.call([
            "zenity", "--info",
            '--title=Latest scores',
            '--text='+str(score)+' out of 10',
            '--width=160',
            ])
        results = []

Cách sử dụng

Cách sử dụng khá giống với tùy chọn 2, nhưng bạn sẽ có sẵn tệp logfile và điểm số sau mỗi 10 bài tập.


4. Phiên bản cuối cùng

Phiên bản bên dưới giống như tùy chọn 3 (bao gồm tệp nhật ký và báo cáo), nhưng có một số tính năng bổ sung:

  • thêm tính toán căn bậc hai

    nhập mô tả hình ảnh ở đây

  • thêm bằng cách sử dụng một phạm vi số, thay vì chỉ đơn giản là đặt tối đa

  • thêm tùy chọn để chỉ chạy các loại tính toán cụ thể (ví dụ: chỉ chia và nhân).
  • nhớ các đối số mà nó đã được chạy với lần trước, khi chạy mà không có đối số (chỉ lần đầu tiên, các đối số phải được đặt). Nếu không có đối số nào được đặt trong lần chạy đầu tiên, tập lệnh sẽ gửi một thông báo:

    nhập mô tả hình ảnh ở đây

Kịch bản

#!/usr/bin/env python3
from random import randint
import sys
import subprocess
import time
import os

"""
Use this script to practice head count. Some explanation might be needed:
The script can be used for the following types of calculating:

Type          argument example      explanation
-------------------------------------------------------------------------------
add           a:30-100              to add in numbers from 30-100
subtract      s:10-100              to subtract in numbers from 10-100
multiply      m:10-20               to multiply in numbers from 10-20
divide        d:200-400             to divide in numbers from 200-400
square root   r:1-1000              to find square root in numbers from 1-1000

N.B.
-------------------------------------------------------------------------------
- The argument p: (pause in seconds; break between the assignments) *must* be
  set, for example: p:300 to launch an assignment every 5 minutes
- A calculation type will only run *if* the argument is set for the
  corresponding type. An example: python3 /path/to/script p:60 s:30-60
  will run a subtract- assignment every minute.

Miscellaneous information:
-------------------------------------------------------------------------------
- On first run, arguments *must* be set. After first run, when no arguments
  are used the last set arguments will run, until the script is run with a new
  set of arguments.
- A log file of the last 100 incorrectly answered questions is kept in
  ~/.calculog
- After 10 assignments, the score of the last 10 pops up.
"""

log = os.environ["HOME"]+"/.calculog"
prefs = os.environ["HOME"]+"/.calcuprefs"
levels = sys.argv[1:]

if levels:
    open(prefs, "wt").write(str(levels))
else:
    try:
        levels = eval(open(prefs).read())
    except FileNotFoundError:
        subprocess.call([
            "zenity", "--info",
            '--title=Missing arguments',
            '--text=On first run, the script needs to be run with arguments\n'
            ])

def fix_float(n):
    """
    if the assignment is a division, the script divides the random number by a
    number (integer) it can be divided by. it looks up those numbers, and picks
    one of them (at random). if the number is a prime number the assignment is
    changed into another type
    """
    try:
        divs = [i for i in range(2, n) if n%i == 0]
        pick = randint(1, len(divs))
        div_by = divs[pick-1]
        return [str(n)+" : "+str(div_by), int(n/div_by)]
    except (ValueError, IndexError):
        pass

def fix_sqr(f1, f2):
    """
    If the assignment is calculating a square root, this function finds the sets
    of numbers (integers) that make a couple, within the given range.
    """
    q = f1; r = q**(.5); sets = []
    while q < f2:
        r = q**(.5)
        if r == int(r):
            sets.append([int(r), int(q)])
        q = q+1
    if sets:
        pick = sets[randint(0, len(sets)-1)]
        return ["√"+str(pick[1]), pick[0]]

def get_assignment():
    """
    get a random number within the user defined range, make the assignment and
    the textual presentation
    """ 
    args = ["a:", "s:", "m:", "d:", "r:"]
    indc = []
    for i, item in enumerate(args):
        if item in str(levels):
            indc.append(i)

    index = indc[randint(0, len(indc)-1)]
    name = args[index]

    minmax = [
        [int(n) for n in item.replace(name, "").split("-")] \
        for item in levels if name in item][0]

    assignment = None
    # if the random number is a prime number *and* the assignment a division 
    # or a square root...
    while assignment == None:
        n1 = randint(minmax[0], minmax[1]); n2 = randint(minmax[0], minmax[1])
        assignment = [
            [str(n1)+" + "+str(n2), n1+n2],
            [str(n1)+" - "+str(n2), n1-n2],
            [str(n1)+" x "+str(n2), n1*n2],
            fix_float(n1),
            fix_sqr(minmax[0], minmax[1]),
            ][index]
    # run the interface job
    try:
        answer = int(subprocess.check_output(["/bin/bash", "-c",
            'zenity --entry --title="Think hard:" --text='+'"'+assignment[0]+'"'
            ]).decode("utf-8"))
        if answer == assignment[1]:
            subprocess.Popen(["notify-send", "Coolcool"])
            return "ok"
        else:
            subprocess.Popen([
                "notify-send", "Oooops, "+assignment[0]+\
                " = "+str(assignment[1])])
            open(log, "+a").write(assignment[0]+"\t\t"+str(answer)+"\n")
            try:
                history = open(log).read().splitlines()
                open(log, "wt").write(("\n").join(history[-100:])+"\n")     
            except FileNotFoundError:
                pass 
            return "mistake"
    except (subprocess.CalledProcessError, ValueError):
        return None

if levels:
    pause = [int(arg.replace("p:", "")) for arg in levels if "p:" in arg][0]
    [levels.remove(item) for item in levels if "p:" in item]
    results = []
    while True:
        time.sleep(pause)
        results.append(get_assignment())
        if len(results) >= 10:
            score = results.count("ok")
            subprocess.call([
                "zenity", "--info",
                '--title=Latest scores',
                '--text='+str(score)+' out of 10',
                '--width=160',
                ])
            results = []

Cách sử dụng

  • Sao chép tập lệnh vào một tập tin trống, lưu nó (một lần nữa) dưới dạng mindpractice.py. Chạy nó với các tùy chọn sau (làm ví dụ)

    Phải được thiết lập:

    p:300                to set the interval between assignments to 5 minutes

    Tùy chọn (thực hiện lựa chọn):

    a:30-100             to add in numbers from 30-100 (optional)
    s:10-100             to subtract in numbers from 10-100
    m:10-20              to multiply in numbers from 10-20
    d:200-400            to divide in numbers from 200-400
    r:1-1000             to find square root in numbers from 1-1000
  • Lệnh ví dụ:

    python3 '/path/to/mindpractice.py' p:300 d:10-100 s:10-30  r:300-600

    để thiết lập:

    p:300                to set the interval between assignments to 5 minutes
    d:10-100             to divide in numbers from 10-100
    s:10-30              to subtract in numbers from 10-30
    r:300-600            to calculate square roots from 300-600

    trong khi thêmnhân không được sử dụng.

Sau đó, lần sau, nếu tập lệnh được chạy với:

python3 '/path/to/mindpractice.py'

Nó sẽ ghi nhớ các đối số được sử dụng cuối cùng


Sử dụng phiên bản phục vụ tốt nhất nhu cầu của bạn ...



Phiên bản này đang hoạt động rất tốt cho đến nay. Cảm ơn bạn rất nhiều!
orschiro

1
@orschiro đã thêm một phiên bản mở rộng, để phân biệt độ khó.
Jacob Vlijm

tệp nhật ký là một ý tưởng rất hay! Tôi hiện đang cố gắng để có được đầu của tôi xung quanh một số phép nhân và chia ba chữ số. Họ không đơn giản như vậy. :)
orschiro

chỉ là một ý tưởng: Đôi khi tôi quá tập trung vào công việc đến nỗi tôi bỏ qua Think Hardcửa sổ để hoàn thành công việc trước đó (ví dụ: viết xong một câu). Sau đó tôi quên mất cửa sổ. Có thể sau 5 phút, Think Hardcửa sổ sẽ tự động lấy lại tiêu điểm?
orschiro

1
@orschiro hoàn toàn! Tôi vẫn đang nhai một phiên bản GUI hoàn toàn (không cần thiết lập bất cứ thứ gì từ dòng lệnh, thậm chí không phải lần chạy đầu tiên), nhưng tôi không chắc họ sẽ cho phép chúng tôi thêm nhiều mét vào câu trả lời :)
Jacob Vlijm

3

Giới thiệu:

Ứng dụng sau đây tạo ra các biểu thức số nguyên ngẫu nhiên được đánh giá bởi người dùng. Phạm vi của các biểu thức được tạo ngẫu nhiên tùy thuộc vào cài đặt của người dùng trong cửa sổ bật lên chính. Khi nhấp vào Lets Beginnút, phiên bắt đầu vô thời hạn, cho đến khi người dùng nhấn nút Hủy.

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Mã nguồn:

#!/usr/bin/env python

# Author: Serg Kolo
# Date: Jan 30,2016
# Purpose: A graphical utility for practicing
#          random arithmetic operations
# Written for: http://askubuntu.com/q/725287/295286

#    Copyright: Serg Kolo , 2016
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import time
import random
from PyQt4 import QtGui


class mathApp(QtGui.QWidget):
   def __init__(self):
       super(mathApp,self).__init__()
       self.mainMenu()

   def mainMenu(self):
      self.setGeometry(300, 300, 400, 200)

      self.btn = QtGui.QPushButton("Let's begin",self)
      self.btn.move(20,150)
      self.btn.clicked.connect(self.askQuestions)

      self.lbl1 = QtGui.QLabel(self)
      self.lbl1.move(20,25)
      self.lbl1.setText("Numbers From")


      self.lbl2 = QtGui.QLabel(self)
      self.lbl2.move(20,55)
      self.lbl2.setText("Numbers To")

      self.lbl2 = QtGui.QLabel(self)
      self.lbl2.move(20,85)
      self.lbl2.setText("Repeat (seconds)")

      self.le1 = QtGui.QLineEdit(self)
      self.le1.move(150,20)

      self.le2 = QtGui.QLineEdit(self)
      self.le2.move(150,50)

      self.le3 = QtGui.QLineEdit(self)
      self.le3.move(150,80)

      self.lbl3 = QtGui.QLabel(self)
      self.lbl3.move(20,105)

      self.setWindowTitle('Random Integer Arithmetic')

      self.show()

   def askQuestions(self):
       rangeStart = int(self.le1.text())
       rangeEnd = int(self.le2.text())
       sleepTime = int(self.le3.text())
       done=False
       while not done:
          self.show()
          expression = self.generateOperation(rangeStart,rangeEnd)
          correctAnswer = eval(expression)

          prompt = QtGui.QInputDialog() 
          text,ok = prompt.getText(self,"Don't think too hard",expression) 
          if ok:
             if int(text) == correctAnswer:                
                self.showAnswer("CORRECT,YOU ROCK !")
             else :
                self.showAnswer("Nope");
          else:
              done=True

          if done==True:
              self.close()
          time.sleep(sleepTime)


   def generateOperation(self,start,end):
      a = random.randint(start,end)
      b = random.randint(start,end)
      oplist = ['+','-','/','*']
      op = oplist[random.randint(0,3)]
      expr = str(a) + op + str(b) + ''
      return expr

   def showAnswer(self,result):
       popup = QtGui.QMessageBox()
       popup.setText(result)
       popup.exec_()


def main():
   root = QtGui.QApplication(sys.argv)
   app = mathApp()
   sys.exit(root.exec_())

if __name__ == '__main__':
   main()

Kính gửi @Serg, tôi cũng muốn cảm ơn cá nhân bạn về phiên bản GUI mở rộng của bạn. Một câu hỏi, tôi chỉ có bài tập 15/14 = 1. Tôi không chắc chắn một bài tập như vậy hữu ích như thế nào. Bạn nghĩ sao?
orschiro

@orschiro đây là integer arithmetic. Điều đó có nghĩa là kết quả chỉ là một phần, không có phần còn lại. Nếu bạn muốn, tôi cũng có thể thử thực hiện decimalsố học. Ngoài ra, vui lòng cho tôi biết loại tùy chọn nào bạn muốn tôi thực hiện và thêm. Hiện tại, tôi đang cố gắng thực hành agile developmentphương pháp và giao tiếp với khách hàng là chìa khóa trong phương pháp đó. Làm ơn cho tôi biết.
Sergiy Kolodyazhnyy

thật tuyệt khi nghe vậy! Tôi rất muốn cung cấp cho bạn nhiều phản hồi hơn, ví dụ như tích hợp tốt hơn vào Ubuntu Desktop (chạy tập lệnh nhiều hơn trong nền, tức là giảm thiểu sau khi người dùng nhập liệu). Làm thế nào tôi có thể cung cấp cho bạn thông tin phản hồi tốt nhất?
orschiro
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.