Nó sẽ là một ý tưởng tồi để định kỳ chạy các trình định dạng mã trên một kho lưu trữ?


68

Tôi đang nghĩ đến việc tạo một công việc định kỳ để kiểm tra mã, chạy các trình định dạng mã trên nó và nếu có bất cứ điều gì thay đổi, hãy cam kết các thay đổi và đẩy chúng trở lại.

Hầu hết các dự án sử dụng bộ lọc tự động đặt chúng vào một git hook, nhưng thực hiện nó tự động cứ sau vài giờ sẽ loại bỏ gánh nặng cho mỗi nhà phát triển để cài đặt hook git.

Tôi vẫn sẽ khuyến khích mọi người viết mã sạch, được định dạng tốt và có thể tôi có thể hệ thống tự động ping devs khi mã họ viết được định dạng lại, để họ biết phải làm gì trong tương lai.


105
Có một lỗi logic ở đây. Phương pháp này sẽ không khuyến khích mọi người viết mã được định dạng tốt; thay vào đó, nó sẽ khuyến khích mọi người không định dạng và dựa vào hệ thống thay vào đó! Nếu mối quan tâm của bạn là cơ sở mã là mạch lạc, thì không sao. Mục tiêu của bạn là đào tạo các lập trình viên viết sạch sẽ, đó là một lỗi rất lớn.
Kilian Foth

52
Ngoài ra, với việc xem xét hiệu ứng này sẽ có trên các tính năng như đổ lỗi - đặc biệt là nếu trình định dạng tạo ra nhiều thay đổi, nếu hầu hết các dòng trong tệp được đánh dấu là bị thay đổi bởi trình định dạng, bạn sẽ mất một số giá trị.
Neil P

13
Tôi đã gặp sự cố với một bộ lọc tự động không được cập nhật đúng cách và phá vỡ mã của tôi. Một cái gì đó để giữ trong tâm trí.
isaacg

22
Nếu nó quan trọng với bạn, bạn có thể thất bại trong quá trình xây dựng khi mã không được định dạng chính xác. Đó là một chút khắc nghiệt nhưng một đánh giá ngang hàng thích hợp sẽ ít nhiều làm điều tương tự.
Erno

18
Đây là một ý tưởng tuyệt vời nếu mục tiêu của bạn là khiến mọi người ghét bạn. Nó đạt được rất ít, nhưng chắc chắn sẽ gây ra những vấn đề không lường trước được.
TonyK

Câu trả lời:


130

Nghe có vẻ hay, nhưng tôi muốn có những người chịu trách nhiệm thực hiện thay đổi mã chứ không phải bot.

Bên cạnh đó, bạn muốn chắc chắn rằng những thay đổi đó không phá vỡ bất cứ điều gì. Ví dụ, chúng ta có một quy tắc sắp xếp các thuộc tính và phương thức theo thứ tự abc. Điều này có thể có tác động đến chức năng , ví dụ như thứ tự dữ liệu và phương thức trong các tệp WSDL của hợp đồng WCF.


50
Ngoài ra, nó phá vỡ VCS. Bạn sẽ không thể biết ai đã viết một dòng dễ dàng với sự đổ lỗi và nếu có xung đột, VCS của bạn sẽ không thể biết các thay đổi của công cụ chỉ dành cho kiểu dáng và nên được loại bỏ mọi lúc.
Pierre.Sassoulas

2
Một chủ đề liên quan tiếp tuyến đang thực thi một số "hành động lưu" nhất định trong IDE như làm cho các trường cuối cùng nếu có thể. Đó là một vấn đề bởi vì (ít nhất là trong Java) rất nhiều khung công tác đặt chúng thông qua sự phản chiếu (ví dụ: Spring và Hibernate).
Thuyền trưởng Man

20
@JeffO git blamekhông chỉ tìm ra lỗi của ai, đó là tìm lỗi khi một thứ gì đó được thêm / xóa, điều này có thể hữu ích vì một số lý do.
Pokechu22

2
"Chúng tôi có một quy tắc đặt hàng các thuộc tính và phương pháp theo thứ tự abc" Boy, nghe có vẻ khủng khiếp! Bạn sẽ phải liên tục hy vọng trên tất cả các tập tin
Alexander

1
Ngoài ra, đối với Java, sự kết hợp của trình kiểm tra kiểu tìm kiếm các dẫn xuất từ ​​kiểu đã thỏa thuận (thậm chí có thể là cảnh báo biên dịch) và IDE được định cấu hình để định dạng kiểu đã thỏa thuận giúp dễ dàng phát hiện và sửa lỗi. Điều quan trọng là mã giải quyết (vì thiếu một từ tốt hơn) khi nó thực sự thay đổi chức năng - không phải khi bot định dạng lại nó.
Thorbjørn Ravn Andersen

72

Thay vào đó, tôi sẽ cố gắng làm cho mọi người trong nhóm dễ dàng áp dụng định dạng mã tự động theo tiêu chuẩn của nhóm của bạn trực tiếp bên trong trình soạn thảo hoặc IDE của bạn , cho tệp mã nguồn hiện tại (hoặc các phần được chọn của nó). Điều này cho phép các thành viên trong nhóm của bạn kiểm soát nhiều hơn về cách thức và thời điểm định dạng diễn ra, hãy để họ kiểm tra mã trước khi nó được cam kết ở dạng cuối cùng và kiểm tra nó sau khi định dạng diễn ra , không phải trước đó.

Nếu tất cả hoặc hầu hết các thành viên trong nhóm của bạn sử dụng cùng một trình soạn thảo, điều này không quá khó. Nếu mọi người sử dụng một cách khác nhau, thì cách tiếp cận của bạn có thể là giải pháp tốt thứ hai, miễn là nhóm hỗ trợ điều này. Tuy nhiên, tôi khuyên bạn nên cài đặt các biện pháp an toàn bổ sung, như xây dựng hàng đêm và kiểm tra tự động được chạy sau mỗi lần sửa đổi mã tự động.


7
"Một công cụ định dạng trong tay bạn chắc chắn 100% nó không phá vỡ bất cứ thứ gì" - Khi nào bạn đã từng chạy vào một đoạn mà bạn đã từng, thật lòng, chắc chắn 100% sẽ không bao giờ phá vỡ?
Zibbobz

2
@Zibbobz: bất kỳ công cụ nào chúng tôi đang sử dụng để chỉnh sửa mã, biên dịch và liên kết nó, và cả VCS, đều có thể có lỗi, nhưng điều đó không ngăn chúng tôi cố gắng phát triển các chương trình làm việc ;-) Nhưng hãy xem bản chỉnh sửa của tôi.
Doc Brown

Tôi chấp nhận chỉnh sửa - nếu chỉ vì một ounce thận trọng đáng giá một pound gỡ lỗi. ;)
Zibbobz

@Zibbobz Khá thường xuyên! Lưu ý rằng chắc chắn 100% về một cái gì đó không có nghĩa là nó có 100% cơ hội là sự thật.
dùng253751

@immibis: bạn có thể đã bỏ lỡ rằng bình luận đề cập đến một câu tôi đã xóa khỏi câu trả lời của tôi vài ngày trước.
Doc Brown

37

Đó là một ý tưởng tồi, không chỉ vì nó không khuyến khích mọi người viết mã đàng hoàng, mà còn bởi vì việc định dạng lại sẽ hiển thị khi thay đổi mã trong VCS của bạn (bạn sử dụng một cách tôi hy vọng), che dấu dòng phát triển lịch sử của mã. Thậm chí tệ hơn, mọi hành động định dạng mã (thực sự là mọi thay đổi đối với mã) đều có khả năng đưa ra các lỗi, cho dù đó là thủ công hay tự động. Vì vậy, trình định dạng của bạn bây giờ có thể giới thiệu các lỗi trong mã của bạn mà sẽ không trải qua các đánh giá mã, kiểm tra đơn vị, kiểm tra tích hợp, v.v. cho đến khi có thể vài tháng sau.


10
Tôi nghĩ rằng nếu anh ta nói về việc bot kiểm tra mọi thứ trong và ngoài kho lưu trữ, thì VCS có được đưa ra không?
StarWeaver

11
@ StarWeaver bạn nghĩ. Nhưng tôi đã làm việc ở những nơi mà "kho lưu trữ mã" là một thư mục được bảo vệ chỉ có thể truy cập bằng một phần mềm chạy dưới tài khoản người dùng của chính nó, không có kiểm soát phiên bản nào ngoại trừ bản sao lưu hàng tuần của thư mục dưới tên thư mục được đánh dấu thời gian.
jwenting

14
Đó là tôi sẽ gặp ác mộng bây giờ>.>
StarWeaver

7
@ StarWeaver tại sao bạn nghĩ tôi vẫn còn nhớ môi trường đó 14 năm sau;)
jwenting

28

Tôi có xu hướng tin rằng đó là một ý tưởng tốt (để tự động chạy các trình định dạng mã), nhưng đó chỉ là ý kiến ​​của tôi.

Tôi sẽ không chạy chúng định kỳ, nhưng nếu có thể trước khi kiểm soát phiên bản cam kết.

Với git , một hook pre-commit làm điều đó sẽ hữu ích. Trong nhiều dự án C hoặc C ++ được xây dựng với một số Makefile , tôi đang thêm một số indentmục tiêu (chạy mã định dạng mã thích hợp như indenthoặc astyle) và mong muốn những người đóng góp chạy make indentthường xuyên. BTW, bạn thậm chí có thể thêm một số makequy tắc để đảm bảo rằng các git hook đã được cài đặt (hoặc để cài đặt chúng).

Nhưng thực sự, nó là một vấn đề xã hội hơn là một vấn đề kỹ thuật . Bạn muốn nhóm của bạn cam kết mã được định dạng rõ ràng và độc đáo, và đó là một quy tắc xã hội của dự án của bạn. (Không phải lúc nào cũng có câu trả lời kỹ thuật cho mọi vấn đề xã hội).

Kiểm soát phiên bản chủ yếu là một số công cụ để giúp liên lạc giữa các nhà phát triển con người (bao gồm cả chính bạn vài tháng kể từ bây giờ). Phần mềm của bạn không cần VC hoặc định dạng, nhưng nhóm của bạn thì có.

BTW, các cộng đồng khác nhau và các ngôn ngữ lập trình khác nhau có quan điểm khác nhau về định dạng mã. Ví dụ, Go chỉ có một kiểu định dạng mã, nhưng C hoặc C ++ có rất nhiều kiểu.


Đúng, nhưng điều đó có nghĩa là mọi nhà phát triển cần cài đặt hook hook.
bigblind

17
Vâng, nhưng đó là một quy tắc xã hội, và bạn cần một vài trong số họ. Bạn không thể tìm thấy một giải pháp kỹ thuật cho mọi vấn đề xã hội. Bạn cần thuyết phục mọi người. Ngoài ra, mọi nhà phát triển cần cài đặt một số trình biên dịch và hệ thống kiểm soát phiên bản.
Basile Starynkevitch

Đúng vậy, vì vậy bạn đang nói quy tắc xã hội là phải cài đặt git hook, tốt hơn một hệ thống tự động phải không? (câu hỏi nghiêm túc, không có ý nghĩa như một lời hùng biện, giọng điệu khó truyền tải trên internet :))
bigblind

15
Vâng, tôi đang nói rằng.
Basile Starynkevitch

17

Tôi nghĩ đó là một ý tưởng tồi. Nhiều câu trả lời đã bao hàm rằng nó làm hỏng lịch sử bằng cách gây khó khăn cho việc xác định ai thực sự đã thêm một dòng và nó khuyến khích mọi người chỉ cần cam kết bất cứ điều gì và bot định dạng sẽ xử lý nó.

Một cách tiếp cận tốt hơn sẽ là kết hợp trình kiểm tra định dạng vào công cụ xây dựng của bạn. (Trong Java có Checkstyle ) Sau đó, chỉ cho phép mọi người hợp nhất các nhánh của họ với nhánh chính nếu quá trình xây dựng vượt qua (bao gồm cả định dạng).

Nếu bạn cho phép mọi người cam kết thẳng vào nhánh chính (ví dụ như trong Subversion) thì bạn vẫn cần đảm bảo mọi người đều có kỷ luật chỉ cam kết mã được định dạng (hoặc máy chủ chỉ chấp nhận các cam kết sau khi một số kiểm tra đã được chạy ).


2
nhưng hãy chắc chắn rằng trình kiểm tra kiểu là lành mạnh và không thực thi những điều kỳ lạ đi ngược lại với bất kỳ thực hành được chấp nhận (và chấp nhận) nào (và vâng, tôi đã thấy như vậy). Sau đó, bạn cũng có thể có máy chủ xây dựng bị lỗi xây dựng tự động khi trình kiểm tra kiểu ném lỗi (mới).
jwenting

2
Tôi đã thấy nhiều trường hợp trong đó định dạng tự động tạo ra mã không thể đọc được. Đặc biệt là đối với rất nhiều parens đóng (có thể để một số trong số chúng trên các dòng riêng biệt, nhưng robot không quan tâm). Một ví dụ khác là tự động phân tách các chuỗi Java dài (chúng dài vì chúng chứa các truy vấn SQL, nhưng robot không có ý tưởng.).
18446744073709551615

@ 18446744073709551615 Tôi không đề xuất định dạng tự động, tôi đề nghị kiểm tra tự động . Quy tắc của bạn có thể cho phép những điều đó.
Thuyền trưởng Man

16

Nói chung, tôi nghĩ đó là một ý tưởng tồi. Về nguyên tắc, đó là một ý tưởng hợp lệ, nhưng nó có thể có vấn đề trong thực tế. Việc trình định dạng mã phá vỡ mã của bạn là một khả năng thực sự và chỉ cần một lần chạy định dạng để các nhà phát triển của bạn phản hồi với sự thù địch (có thể là hợp lý) (ví dụ: "Trình định dạng mã tệ hại của bạn đã phá vỡ bản dựng, hãy tắt ngay bây giờ! " ).

Cũng giống như khuyến nghị của @ BasileStarynkevitch, chúng tôi sử dụng móc nhận sau máy chủ git để gửi "email tư vấn" về kiểu mã.

Nếu tôi đẩy một cam kết có vi phạm kiểu, máy chủ nguồn gốc git sẽ gửi cho tôi một email thông báo cho tôi rằng tôi đã vi phạm các nguyên tắc về kiểu và khuyên tôi nên sửa mã của mình. Tuy nhiên, nó không thực thi điều này bởi vì có thể có những lý do hợp lệ để phá vỡ kiểu nhà (ví dụ, chuỗi dài vượt quá giới hạn chiều dài dòng).

Nếu đó là một vấn đề mang tính hệ thống gây hại cho cơ sở mã, thì có lẽ đã đến lúc bắt đầu đưa ra các vấn đề về kiểu mã trong các đánh giá mã. Kiểu mã kém có thể che giấu các lỗi và làm cho mã khó đọc hơn, do đó nó có thể là một vấn đề xem xét mã hợp lệ.

Để thêm vào khía cạnh "vấn đề xã hội" của mọi thứ, có thể đáng khuyến khích mọi người sửa chữa các khuyết điểm về mỹ phẩm và phong cách khi họ tìm thấy chúng. Chúng tôi có một thông điệp cam kết tiêu chuẩn "Mỹ phẩm." để sửa lỗi kiểu mã mà các nhà phát triển khác biết không chứa các thay đổi vi phạm.

Như @DocBrown nói, một tùy chọn khác là thực thi kiểu mã trong IDE của bạn. Chúng tôi sử dụng CodeMaid với Visual Studio để sửa nhiều lỗi kiểu phổ biến. Nó sẽ chạy khi lưu các tệp mã, có nghĩa là mã kiểu xấu thậm chí không bao giờ được đưa vào repo ... trên lý thuyết :-).


Tôi đã nâng cấp cái này, bởi vì nó trực tiếp giải quyết cả hai mặt (mong muốn mã tốt hơn + an toàn khỏi phá vỡ bản dựng). Tuy nhiên, sau khi cơ sở mã ở trạng thái thực sự tốt, tôi sẽ coi "ý tưởng tồi" là từ ngữ mạnh mẽ để tự động hóa các thay đổi trong tương lai.
donjuedo

10

Vâng, tôi nghĩ đó là một ý tưởng tồi. Đừng hiểu sai ý tôi, lý do để làm điều đó nghe có vẻ tuyệt vời, nhưng kết quả vẫn có thể là khủng khiếp.

Bạn sẽ có xung đột hợp nhất khi kéo một nhánh được theo dõi, ít nhất tôi sợ đó là trường hợp, mặc dù tôi có thể sai.

Tôi không muốn kiểm tra nó ngay bây giờ tại nơi làm việc, nhưng bạn nên tự mình thử nó.

Trong thực tế, bạn chỉ có thể kiểm tra một cam kết gần đây. Tạo một chi nhánh mới, cam kết một cái gì đó nhỏ nhặt, chọn anh đào hoặc hợp nhất mà không có tự động.

Sau đó chạy tập lệnh của bạn, kéo và nếu kết quả của bạn là một mớ hỗn độn khủng khiếp, thì bạn chắc chắn không nên làm điều này, vào ban ngày.

Thay vào đó, bạn có khả năng có thể đưa nó vào một bản dựng hàng đêm hoặc một bản dựng hàng tuần.

Nhưng ngay cả một đêm có thể là một ý tưởng tồi.

Bạn có thể chạy nó hàng tuần, khi bạn chắc chắn sẽ không có xung đột hợp nhất nào phát sinh vì mọi thứ đã kết thúc vào thứ hai.

Nếu không thì chạy 1-2 lần một năm vào mùa lễ, khi xung đột hợp nhất sẽ không xảy ra.

Nhưng giải pháp có thể phụ thuộc vào mức độ ưu tiên của bạn đối với kiểu mã.

Tôi nghĩ rằng việc tạo một kịch bản thiết lập tự động tạo kho git và đặt các hook cho dự án sẽ tốt hơn.

Hoặc bạn có thể bao gồm tập lệnh thiết lập hook trong một thư mục cho các nhà phát triển của bạn trong dự án và chỉ cần kiểm tra nó vào git.


7

Một cái gì đó tôi chưa từng thấy được đề cập là thực tế là đôi khi có những lý do chính đáng để không định dạng một cái gì đó theo một bộ quy tắc. Đôi khi sự rõ ràng của mã được cải thiện bằng cách đi ngược lại một hướng dẫn cụ thể mà 99% thời gian có ý nghĩa. Con người cần thực hiện cuộc gọi đó. Trong những trường hợp đó, định dạng mã tự động sẽ kết thúc làm cho mọi thứ khó đọc hơn.


Hoàn toàn đồng ý. Ví dụ: căn chỉnh các định danh biến ở bên trái, tất cả các dấu bằng trong một cột và tất cả các giá trị ở bên phải của các dấu bằng. Một trình định dạng sẽ làm giảm khả năng đọc trong trường hợp này bằng cách giảm từng tab / khoảng trắng xuống một khoảng trống. Tất nhiên các quy tắc định dạng có thể được viết để ngăn chặn điều này nhưng sau đó bạn cần một nhà phát triển được chỉ định để viết trình định dạng mã. Có vẻ như một ý tưởng tồi xung quanh. Thông qua các quy ước nội bộ tốt hơn và thực thi trong quá trình xem xét mã.
ThisClark

7

Đó là một ý tưởng khủng khiếp.

Nếu một trong những đồng nghiệp phát triển của tôi thực hiện các thay đổi miễn phí cho các tệp nguồn, nó sẽ không vượt qua đánh giá mã. Nó chỉ làm cho cuộc sống khó khăn hơn cho tất cả mọi người. Thay đổi mã cần thay đổi, không có gì khác. Thay đổi vô nghĩa dẫn đến xung đột hợp nhất, có thể dẫn đến lỗi và chỉ tạo ra công việc vô nghĩa.

Nếu bạn muốn làm điều này một cách thường xuyên, điều đó thật tồi tệ.

Và sau đó là câu hỏi về loại thay đổi mà trình định dạng mã thực hiện. Tôi sử dụng định dạng tự động trong trình chỉnh sửa của mình, nó hoạt động khá tốt và tôi có thể cải thiện mọi thứ khi định dạng tự động kém hoàn hảo. Nếu bạn sử dụng một trình định dạng mã vượt xa điều đó, bạn sẽ không cải thiện mã, bạn sẽ làm cho nó tồi tệ hơn.

Và sau đó là vấn đề xã hội. Có những người muốn buộc mọi người sử dụng kiểu mã của họ, và có những người linh hoạt hơn. Một cái gì đó như thế này có thể sẽ được đề xuất bởi loại nhà phát triển "grammer-nazi" (đánh vần có chủ đích), những người muốn áp đặt phong cách của họ lên mọi người khác. Mong đợi một phản ứng dữ dội, và mong đợi các nhà phát triển linh hoạt, thường dễ dàng đặt chân xuống.


4

Bạn không đề cập đến VCS bạn sử dụng nhưng tùy thuộc vào tùy chọn khác là có một móc phía máy chủ. Một VCS như git hỗ trợ điều đó. Bạn có thể cài đặt một hook phía sever chạy bộ định dạng trên phiên bản đang được đẩy và sau đó so sánh tệp được định dạng với phiên bản đang được đẩy. Nếu chúng khác nhau, nhà phát triển đã không sử dụng định dạng chính xác và máy chủ có thể từ chối việc đẩy. Điều này sẽ buộc các nhà phát triển của bạn chỉ đẩy mã với định dạng mong muốn, do đó khuyến khích họ viết mã sạch ngay từ đầu, điều đó sẽ khiến các nhà phát triển chịu trách nhiệm kiểm tra mã được định dạng chính xác và giúp các nhà phát triển của bạn khỏi phải cài đặt thủ công móc.


Đây là những gì Go làm, ví dụ, ngoại trừ sử dụng Mercurial. Đẩy một cái gì đó không bất biến theo go fmtsẽ tự động bị từ chối.
Jörg W Mittag

1

Đó là sự đánh đổi giữa một định dạng mã sạch hơn và chính xác hơn và dễ hiểu hơn về lịch sử git. Phụ thuộc vào bản chất của dự án của bạn và tần suất bạn lặn trong lịch sử git hoặc đổ lỗi để hiểu những gì đang xảy ra. Nếu bạn đang làm việc trên một cái gì đó mới và không phải duy trì khả năng tương thích ngược, lịch sử thường không đóng vai trò quan trọng.


1

Ý tưởng này tương tự như một số câu trả lời khác, nhưng tôi không thể nhận xét đề xuất của mình.

Một tùy chọn là đặt bí danh (hoặc hook hoặc bất cứ thứ gì) cho hàm commit, chạy bộ định dạng mã trên mã được cam kết trước khi nó được cam kết.

Nó có thể có 2 (hoặc nhiều hơn) kết quả:

1) Hiển thị cho người dùng các thay đổi được đề xuất và yêu cầu phê duyệt để áp dụng và cam kết các thay đổi.

2) Bỏ qua các thay đổi được đề xuất và cam kết mã gốc.

Bạn cũng có thể thêm linh hoạt hơn cho các tùy chọn này, như khả năng chỉnh sửa các thay đổi được đề xuất trong tùy chọn 1. Một ý tưởng khác (Tùy thuộc vào mức độ bạn muốn đẩy các tiêu chuẩn mã hóa này) là để hệ thống gửi cho bạn một báo cáo nào đó khi tùy chọn 2 được chọn.

Đây có thể là một sự cân bằng tốt của việc tự động kiểm tra tất cả các mã như bạn muốn, trong khi vẫn cho phép linh hoạt cho các nhà phát triển phù hợp với nhu cầu của họ. Nó cũng cho phép tùy chọn không 'tự động từ chối' mã với các khác biệt về định dạng như được đề cập trong các câu trả lời khác. Với 'Tôi đã xem xét và phê duyệt chỉnh sửa định dạng tự động; tùy chọn cam kết, nó vẫn giữ trách nhiệm cá nhân cho mỗi nhà phát triển hoạt động và không gây rối với VCS.


0

Tôi sẽ không làm điều đó trên kho lưu trữ nhưng tôi sẽ lưu nó nếu công cụ hỗ trợ. Eclipse là một và ngoài ra tôi sẽ làm sạch mã bao gồm cả sắp xếp.

Phần hay là nó là một phần của dự án nên mọi nhà phát triển sẽ lấy nó cho dự án của họ.

Vì một sự hợp nhất tiền thưởng bổ sung sẽ được đơn giản hóa đáng kể vì mọi thứ sẽ không được nhảy xung quanh.

Mã đánh giá sẽ ngăn chặn bất kỳ những người sai lầm.

Một nơi khác tôi sẽ làm nó là một phần của bản dựng. Trong trường hợp của tôi, tôi có các bản dựng maven sẽ định dạng lại XML và dọn sạch các tệp pom và định dạng lại mã.

Theo cách đó, khi các nhà phát triển sẵn sàng đẩy nó, tất cả sẽ được dọn sạch cho yêu cầu kéo của họ.

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.