API là gì?
Một giao diện lập trình ứng dụng (API - Application Programming Interface) là một tập các lệnh và các tiêu chuẩn lập trình để truy cập ứng dụng phần mềm. Với API, bạn có thể thiết kế các sản phẩm được hỗ trợ bởi dịch vụ mà API cung cấp.HTML5 có một số API mới. Ví dụ:
- Một API vẽ 2D được dùng với phần tử canvas mới để biểu diễn các biểu đồ hoặc hình ảnh trực quan khác.
- Một cơ cấu bộ nhớ đệm API để hỗ trợ các ứng dụng web không nối mạng.
- Một API để phát video và âm thanh được dùng với các phần tử video và âm thanh mới.
- Một history API giúp dễ dàng truy cập lịch sử duyệt web và cho phép các trang web thêm vào nó.
- Một API kéo-và-thả để sử dụng với các thuộc tính
draggable
(có khả năng kéo). - Một API chỉnh sửa để sử dụng với thuộc tính
contenteditable
(có khả năng chỉnh sửa nội dung). - Lưu trữ phía máy khách với các API JavaScript cho các cặp giá trị-khóa và các cơ sở dữ liệu SQL nhúng.
Kinh doanh ở khắp mọi nơi: Định vị địa lý
Bạn sử dụng Geolocation API (API Định vị địa lý) để xác định và chia sẻ các vị trí địa lý. API này trả về các tọa độ kinh độ và vĩ độ — thông tin mà các doanh nghiệp có thể sử dụng để cung cấp dịch vụ trong vùng gần đúng tọa độ. Những dịch vụ này thường được gọi là các dịch vụ dựa vào vị trí (LBS - Location-Based Services).LBS đề cập đến các nguồn dữ liệu địa lý được dùng để xác định vị trí vật lý của thiết bị đang được theo dõi và, do đó, con người có liên quan đến vị trí đó. Chức năng này cung cấp cho các bên quan tâm cơ hội để tương tác với cá nhân đó dựa vào thị trường với một số điểm trung tâm-định vị địa lý quan tâm.
Kinh doanh thực sự liên quan đến việc tạo ra chất lượng, tiện ích, và giá trị cho các khách hàng, trong khi đồng thời tạo ra lợi ích kinh tế và tài chính cho các bên liên quan, các chủ nợ, các cổ đông, các nhân viên, và các nhà cung cấp. LBS có hỗ trợ - Định vị địa lý giúp việc bám sát và theo dõi một gói bưu kiện hay một người dễ dàng hơn khi sử dụng một thiết bị không có trình duyệt hoặc có trình duyệt. Về thương mại, việc định vị địa lý có liên quan đến tất cả việc sử dụng các tài sản địa lý để xác định nơi một người nào đó hoặc một cái gì đó có ở vị trí đó, rồi bán tập thông tin cụ thể đó cho bất kỳ ai muốn sử dụng nó cho các mục đích xã hội, thương mại, hoặc các mục đích khác, dựa vào sự cho phép hợp pháp từ chủ sở hữu thông tin để làm như vậy.
Định vị địa lý hoạt động như thế nào
Geolocation API (API Định vị địa lý) được dựa vào một đặc tính của đối tượngnavigator
chung: navigator.geolocation
. Đối tượng JavaScript navigator
cung cấp thông tin có ích về trình duyệt và hệ thống của khách truy cập. Việc định vị địa lý có thể xác định vĩ độ và kinh độ bằng các địa chỉ IP, cơ sở dữ liệu dựa trên-web, các kết nối mạng không dây, và công nghệ phép đo tam giác hoặc GPS (Hệ thống định vị toàn cầu). Cần lưu ý rằng độ chính xác của thông tin định vị địa lý được cung cấp khác nhau dựa trên các phương tiện thu nhận thông tin. Đôi khi, và ở một số địa điểm, bạn có thể không có khả năng nhận được một kết quả định vị đầy đủ hoặc bất kỳ dữ liệu nào. Các kịch bản lệnh có thể sử dụng đối tượng
navigator.geolocation
để xác định thông tin vị trí liên quan đến thiết bị lưu trữ của người dùng. Sau khi lấy ra thông tin vị trí, hãy tạo một đối tượng vị trí và đặt nó chung với dữ liệu. Đối tượng
navigator.geolocation
có ba phương thức:getCurrentPosition()
watchPosition()
clearWatch()
Phương thức getCurrentPosition()
Phương thứcgetCurrentPosition()
lấy ra vị trí hiện tại của người dùng, nhưng chỉ một lần. Khi được một kịch bản lệnh gọi, phương thức này cố gắng thu nhận vị trí hiện tại của thiết bị lưu trữ theo cách không đồng bộ. Truyền thông không đồng bộ có nghĩa là người gửi và người nhận không đồng thời được tham gia vào truyền thông. Sử dụng truyền thông không đồng bộ cho phép trình duyệt tiếp tục các hoạt động khác sao cho nó không phải chờ đợi một phản hồi từ thực thể đang thu nhận. Phương thức
getCurrentPosition()
có thể có đến ba đối số: geolocationSuccess
. Gọi lại với vị trí hiện tại (bắt buộc)geolocationError
. Gọi lại nếu có một lỗi (tùy chọn)geolocationOptions
. Các tùy chọn định vị địa lý (tùy chọn)
navigator.geolocation.getCurrentPositon()
trả về vị trí hiện tại của thiết bị lưu trữ theo cuộc gọi lại geolocationSuccess
với một đối tượng Position
làm tham số. Nếu có lỗi, hàm geolocationError
được gọi ra với một đối tượng PositionError
. Bạn có thể thiết lập ba đặc tính cho geolocationOptions
: enableHighAccuracy
, timeout
, và maximumAge
. Các đặc tính tùy chọn này có khả năng chính xác cao, nếu thiết bị hỗ trợ, tương ứng là, một khoảng thời gian chờ để trả về một vị trí, và một khoảng thời gian tối đa để có thể sử dụng một vị trí đã lưu trữ. Phương thức
getCurrentPosition()
được gọi như được hiển thị dưới đây:void navigator.geolocation.getCurrentPosition(
geolocationSuccess, geolocationError, geolocationOptions);
Phương thức watchPosition()
Phương thứcwatchPosition()
thăm dò vị trí người dùng một cách thường xuyên, theo dõi để xem liệu vị trí người dùng đã thay đổi chưa. Nó có thể có đến ba đối số. Khi
watchPosition
được gọi, nó bắt đầu một quá trình theo dõi không đồng bộ liên quan đến việc thu nhận một đối tượng Position
mới và tạo watchID
. Nếu việc thu nhận này thành công, geolocationSuccess
liên quan tới một đối tượng Position
làm đối số được gọi ra. Dựa vào lỗi liên quan đến một phương thức được gọi ra với một đối số geolocationError
khác không, phương thức này tạo geolocationError
với một đối tượng PositionError
làm đối số. Khi vị trí thiết bị thay đổi, một lời gọi lại thích hợp với đối tượng Position
mới được gọi ra. Phương thức
watchPosition()
được gọi như được hiển thị dưới đây:long navigator.geolocation.watchPosition(
geolocationSuccess, geolocationError, geolocationOptions);
Phương thức clearWatch()
Phương thứcclearWatch()
có tác dụng kết thúc một phương thức watchPosition()
đang diễn ra. Phương thức này có thể chỉ có một đối số. Khi được gọi, nó tìm đối số watchID
đã khởi động trước đây và ngưng ngay nó lại. Phương thức
clearWatch()
được gọi như được hiển thị dưới đây:void navigator.geolocation.clearWatch(watchID)
Dữ liệu định vị địa lý: Đối tượng Position
Geolocation API trả về một đối tượngPosition
(vị trí địa lý). Đối tượng này có hai đặc tính: timestamp
và coords
. Đặc tính timestamp
(dấu thời gian) cho biết thời điểm tạo ra dữ liệu định vị địa lý. Đặc tính coords
(các tọa độ) có bảy thuộc tính: coords.latitude
. Vĩ độ ước tínhoords.longitude
. Kinh độ ước tínhcoords.altitude
. Độ cao ước tínhcoords.accuracy
. Độ chính xác của vĩ độ và kinh độ được cung cấp ước tính theo métcoords.altitudeAccuracy
. Độ chính xác của độ cao được cung cấp ước tính theo métcoords.heading
. Hướng di chuyển hiện tại đối với thiết bị đang lưu trữ trên máy chủ theo độ, tính theo chiều kim đồng hồ liên quan đến cực Bắc thựccoords.speed
. Tốc độ dưới đất hiện tại của thiết bị theo mét/giây
coords.latitude
, coords.longitude
, và coords.accuracy
. Các thuộc tính còn lại trả về null
(không), tùy thuộc vào các khả năng của thiết bị của bạn và máy chủ định vị tầng sau mà nó trao đổi. Các thuộc tính heading
và speed
(tốc độ) được tính toán dựa trên vị trí trước đó của người dùng, nếu có thể.Các trình làm việc trên nền web đến giải cứu
Web workers (Các trình làm việc trên nền web) khắc phục các vấn đề gây ra bởi tính đồng thời. Web workers là câu trả lời của họ HTML5 cho vấn đề đơn-luồng của JavaScript: Chúng chạy các quá trình trên một luồng riêng biệt từ trang chính, bảo vệ trang với các chức năng chính, chẳng hạn như duy trì một giao diện người dùng ổn định.Một web worker là một tệp JavaScript được nạp và được thực hiện trong nền. Các web worker này cho phép bạn tải một tệp JavaScript động, và sau đó thực hiện một kịch bản lệnh bằng cách sử dụng một quá trình nền mà không ảnh hưởng đến giao diện người dùng. Các web worker có quyền truy cập hạn chế và chỉ được phép truyền qua các chuỗi. Vì web worker không sử dụng luồng giao diện người dùng của trình duyệt, nên chúng không được phép truy cập vào DOM. Các worker có thể sử dụng cả hai tham chiếu
self
và this
cho phạm vi chung của worker. Truyền dẫn của worker và trang cha mẹ đạt được bằng cách sử dụng một mô hình sự kiện và phương thức postMessage()
. Vì Web workers có cách hoạt động đa luồng, nên chúng chỉ có thể truy cập một tập con của các tính năng của JavaScript. Web workers có thể:
- Truy cập đối tượng navigator.
- Sử dụng đối tượng vị trí chỉ-đọc.
- Thực hiện
XMLHttpRequest
để gửi các yêu cầu HTTP hoặc HTTPS. - Thiết lập một thời gian hoặc khoảng thời gian cho một hoạt động bằng cách sử dụng
setTimeout()/clearTimeout()
vàsetInterval()/clearInterval()
. - Truy cập bộ nhớ ứng dụng.
- Nhập khẩu kịch bản lệnh bên ngoài bằng cách sử dụng phương thức
importScripts()
. - Sinh ra các Web worker khác (worker con - subworker - phải có cùng nguồn gốc như trang chính và được đặt trong cùng một vị trí như worker mẹ).
Web worker chuyên dụng
Một web worker chuyên dụng được liên kết đến kịch bản lệnh tạo ra nó, và nó có thể truyền thông với các thành phần worker hoặc trình duyệt khác. Tuy nhiên, nó không thể truyền thông với các DOM.Một web worker chuyên dụng được tạo ra bằng cách chuyển một tên tệp JavaScript tới một cá thể worker mới. Bạn tạo ra một worker mới khi sử dụng hàm tạo
Worker()
bằng cách chỉ rõ địa chỉ URI của kịch bản lệnh đang thực hiện của worker. Để tạo ra một worker chuyên dụng, hãy nhập mã được hiển thị dưới đây, mã này tạo ra một đối tượng Worker chuyên dụng mới Worker
: var worker = new Worker('worker.js');
Các web worker chia sẻ
Các web worker chia sẻ, giống như các worker chuyên dụng, không thể truy cập vào DOM và chỉ có quyền truy cập hạn chế vào các đặc tính cửa sổ. Các web worker chia sẻ chỉ có thể truyền thông với các web worker chia sẻ khác của cùng một miền. Các worker này được tạo ra bằng cách chuyển một tên JavaScript tới một cá thể worker chia sẻ mới..Các kịch bản lệnh trang có thể truyền thông với các web worker chia sẻ. Tuy nhiên, không giống như các web worker chuyên dụng, bạn truyền thông bằng cách sử dụng một đối tượng
port
(cổng) và gán cho một trình xử lý sự kiện thông báo. Ngoài ra, bạn phải gọi phương thức start()
của port trước khi sử dụng phương thức postMessage()
đầu tiên. Dựa vào việc nhận được thông báo đầu tiên bằng kịch bản lệnh web worker, web worker chia sẻ gán một trình xử lý sự kiện cho cổng hoạt động. Nói chung, trình xử lý sẽ chạy phương thức
postMessage()
riêng của nó để trả về một thông báo tới mã đang gọi, và sau đó phương thức start()
của port tạo một quá trình thông báo cho phép. Để tạo ra một web worker chia sẻ, bạn phải tạo một đối tượng
SharedWorker
thay cho đối tượng Worker
. Đoạn mã sau đây cho thấy cách tạo một đối tượng SharedWorker
mới: var worker = new SharedWorker('worker.js');
Dựng một trang có cả hai API
Bạn sẽ thiết kế một trang có chứa các mô hình làm việc cơ bản của cả Geolocation API và Web Worker API. Ngoài ra, bạn sử dụng Google Map API (API bản đồ của Google) để đưa ra dữ liệu đã tích lũy làm một bản đồ.Trang này được thiết lập như trong Hình 1. Trang này bao gồm một vùng Header được tạo ra bằng cách sử dụng các thẻ
<header></header>
, một vùng Section được tạo ra bằng cách sử dụng các thẻ <section></section>
, và một vùng Aside được tạo ra bằng cách sử dụng các thẻ <aside></aside>
. Hình 1. Bố trí trang API
Các vùng
<section>
và <aside>
chứa các API. Vùng Section chứa Geolocation API. Vùng Aside chứa web worker, tính các số nguyên tố. Khi được thực hiện, trang web này được hiển thị trong Hình 2. Để xem các dữ liệu định vị địa lý, trước tiên bạn phải đồng ý chia sẻ thông tin của bạn. Web worker khởi động khi nạp trang. Nếu bạn muốn xem các số nguyên tố được tìm thấy, hãy nhấn vào Display Web Worker (Hiển thị trình làm việc trên nền web).
Hình 2. Trang web API
Tệp HTML
Tệp HTML bắt đầu bằng thông tin HTML5 chuẩn như trong Liệt kê 1. Phần<head>
chứa một lời gọi đến Google Maps API, thiết lập giá trị của bộ cảm biến là False (Sai). Việc sử dụng Google Maps API đòi hỏi bạn cho biết ứng dụng của bạn có đang sử dụng một bộ cảm biến, chẳng hạn như GPS, để thiết lập vị trí không. Bạn phải khai báo một giá trị tham số cảm biến là True (Đúng) hay False (Sai) cho ứng dụng Google Maps API của bạn. Cần phải khai báo một giá trị cảm biến. Thẻ <head>
cũng chứa các liên kết đến các tệp JavaScript và sử dụng CSS3 để xử lý các hàm và định dạng trang web. Liệt kê 1. Bắt đầu tệp HTML
<!doctype html>
<html>
<head>
<title>Basic GeoLocation Map & Web Worker Prime Number Calculator</title>
<script src="http://maps.google.com/maps/api/js?sensor=false"
type="text/javascript"></script>
<LINK href="GeolocationWebWorker.css" rel="stylesheet" type="text/css">
<script src="HTML-Part3-GeolocationWebWorker.js" type="text/javascript"></script>
</head>
<body>
chứa một sự kiện onLoad
gọi hàm khởi tạo để định vị vị trí địa lý, như trong Liệt kê 2. Hàm này xác minh xem có thể sử dụng định vị vị trí địa lý trong trình duyệt này không. Hàm khởi tạo này có trong tệp JavaScript. Nếu trình duyệt có thể truyền thông với Geolocation API, bản đồ sẽ được hiển thị. Liệt kê 2. Khởi tạo định vị địa lý
<body onLoad="initGeoApp();">
<header>
<hgroup>
<h1>Geolocation & Web Worker</h1>
<h2>Making it work</h2>
</hgroup>
</header>
<section>
được hiển thị trong Liệt kê 3 có chứa các thông tin kết quả đầu ra hiển thị cho đối tượng navigator.geolocation
. Một canvas bản đồ được tạo ra bằng cách sử dụng các kinh độ và vĩ độ do API trả về. Dữ liệu Position coords
cũng được hiển thị khi sử dụng các thẻ <span></span>
. Liệt kê 3. Bản đồ và vị trí của định vị địa lý
<section>
<p>This is the geolocation example map.</p>
<div id="map_canvas" ></div>
<p>This is the output from the navigator.geolocation object.</p>
<table>
<tr>
<td>accuracy:</td>
<td><span id="accuracyOutput"></span></td>
</tr>
<tr>
<td>altitude:</td>
<td><span id="altitudeOutput"></span></td>
</tr>
<tr>
<td>altitudeAccuracy:</td>
<td><span id="altitudeAccuracyOutput"></span></td>
</tr>
<tr>
<td>heading:</td>
<td><span id="headingOutput"></span></td>
</tr>
<tr>
<td>latitude:</td>
<td><span id="latitudeOutput"></span></td>
</tr>
<tr>
<td>longitude:</td>
<td><span id="longitudeOutput"></span></td>
</tr>
<tr>
<td>speed:</td>
<td><span id="speedOutput"></span></td>
</tr>
</table>
</section>
<aside>
<p>This is the Web Worker. </p>
<p>Prime number calculation result:
<output id="result"></output></p>
<output>
mới để hiển thị tính toán do web worker tạo ra. ID được gán trong thẻ <output>
có cùng mã ID JavaScript sử dụng để xác định tính toán mà nó thực hiện. Các ID (mã định danh) được sử dụng trong các thẻ <span>
và <output>
cho phép truy cập vào DOM. Không có ID tham chiếu, mã JavaScript sẽ không biết sử dụng <span>
hay <output>
. Liệt kê 4 cho thấy kết quả đầu ra từ web worker. Liệt kê 4. Kết quả đầu ra của Web worker
<aside>
<p>This is the Web Worker. </p>
<p>Prime number calculation result:
<output id="result"></output></p>
onClick
được dùng trong thẻ <input>
để trước tiên hiển thị các giá trị đang được web worker Số nguyên tố (Prime Number web worker) tính toán, và sau đó onClick
thứ hai được sử dụng để dừng web worker. Liệt kê 5 cho thấy đoạn mã này. Hàm displayWorker()
làm cho các tính toán của web worker được hiển thị khi nhấn vào nút này. Web worker đã bắt đầu tính các số nguyên tố khi trang đã được nạp. Liệt kê 5. Các đầu vào cho web worker
<input type="button" value="Display Web Worker" onClick="displayWorker();">
<input type="button" value="Stop Web Worker" onClick="stopWorker();">
</aside>
</body>
</html>
Tệp JavaScript
JavaScript là máy phía sau các API được trưng bày trên trang mẫu này. Geolocation API được khởi tạo bằng hàminitGeoApp()
. Đây là hàm được thực hiện bằng sự kiện onLoad()
trong thẻ <body>
: Nó xác định xem trình duyệt của bạn có thể sử dụng định vị địa lý không (xem Liệt kê 6). Nếu trình duyệt của bạn có thể sử dụng định vị địa lý, thì Geolocation API được gọi. Nếu thành công, bản đồ được vẽ bằng cách sử dụng các thuộc tính Position
. Các giá trị của các thuộc tính này sau đó được in dưới bản đồ. Liệt kê 6. Các hàm định vị địa lý
function initGeoApp()
{
if( navigator.geolocation )
{
navigator.geolocation.getCurrentPosition( success, failure);
}
else
{
alert("Your browser does not support geolocation services.");
}
}
document.getElementById
, dựa trên ID mà bạn đã cung cấp trong tệp HTML. document.getElementById
là một phương thức của đối tượng tài liệu và được truy cập bằng document.getElementById
, như trong Liệt kê 7. Các giá trị của các thuộc tính Position
được lưu trữ ở đây sao cho chúng có thể được sử dụng để in các thuộc tính dưới bản đồ được hiển thị. Liệt kê 7. Sử dụng getElementById để nhận được các giá trị coords
var map;
function success(position)
{
document.getElementById("accuracyOutput").innerHTML =
position.coords.accuracy;
document.getElementById("altitudeOutput").innerHTML =
position.coords.aktitude;
document.getElementById("altitudeAccuracyOutput").innerHTML =
position.coords.altitudeAccuracy;
document.getElementById("headingOutput").innerHTML =
position.coords.heading;
document.getElementById("latitudeOutput").innerHTML =
position.coords.latitude;
document.getElementById("longitudeOutput").innerHTML =
position.coords.longitude;
document.getElementById("speedOutput").innerHTML =
position.coords.speed;
LatLng
của Google Map API, như Liệt kê 8 cho thấy. Đối tượng LatLng
của Google Map API cung cấp thông tin tọa độ cần thiết để tạo ra một bản đồ. Bạn có thể thiết lập mức độ phóng to hay thu nhỏ và một số tùy chọn khác để tạo dáng vẻ của bản đồ được đưa ra cho người dùng. Liệt kê 8. Các tùy chọn Bản đồ của Google
var coordinates = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var myOptions =
{
zoom: 14,
center: coordinates,
mapTypeControl: false,
navigationControlOptions: {style: google.maps.NavigationControlStyle.small},
mapTypeId: google.maps.MapTypeId.ROADMAP
};
mapTypeID
, hãy chọn tùy chọn ROADMAP
. Giá trị này trình bày bản đồ sao cho nó xuất hiện như trong Hình 2. Có bốn giá trị có thể: - ROADMAP (Lộ trình)
- HYBRID (Lai)
- SATELLITE (Vệ tinh)
- TERRAIN (Địa hình)
Hình 3. Trang web API với bản đồ lai
Tạo bản đồ bằng cách sử dụng ID
map_canvas
, đó là ID cho <div>
trong tệp HTML: map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
Liệt kê 9. Đặt một điểm đánh dấu bản đồ ban đầu
var marker = new google.maps.Marker({
position: coordinates,
map: map,
title: "You are here."
});
}
function failure()
{
alert("Sorry, could not obtain location");
}
displayWorker()
. Liệt kê 10 cho thấy đoạn mã này. Liệt kê 10. Web worker
var worker = new Worker('PrimeNumberWebWorker.js');
function displayWorker()
{
worker.onmessage = function (event)
{
document.getElementById('result').innerHTML = event.data;
};
}
stopWorker()
, được hiển thị trong Liệt kê 11. Liệt kê 11. Kết thúc worker
function stopWorker()
{
worker.terminate();
}
File web worker
File tệp này là web worker của trình tính số nguyên tố: nó tính tất cả số nguyên tố cho đến khi bị dừng lại. Liệt kê 12 cho thấy đoạn mã này.Liệt kê 12. Tính các số nguyên tố
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
postMessage(n);
}
File CSS3
File tệp CSS3 được hiển thị trong Liệt kê 13 cung cấp định dạng hiển thị trong trang HTML5.Liệt kê 13. Các mô tả CSS3
* {font-family: Arial,Helvetica,sans-serif ;
}
body {
margin: 0 300px 0 300px;
color: #990000;
background-color:#FFFFCC;
}
header > hgroup h1 {
margin: 0 0 3px 0;
padding: 0;
text-align: center;
font-size: 30px;
}
header > hgroup h2 {
margin: 0 0 15px 0;
padding: 0;
text-align: center;
font-style: italic;
font-size: 12px;
}
header p {
margin: 0 0 20px 0 ;
padding: 0;
text-align: center;
font-size: 12px;
}
aside {
width: 200px;
height: 175px;
margin: -450px 0 0 450px;
background-color: #990000;
padding: .5px 0 0 10px ;
color:#FFFFFF;
font-weight:bold;
}
div {
width: 400px;
height: 250px;
}
Kết luận
Phần đăng này đã xem xét các tiện ích của Geolocation API và Web Worker API. Hai API này đã được chọn vì chúng cùng chứng tỏ cả hai cách sử dụng sáng tạo và thực tế của các API. Định vị địa lý là một ví dụ hay về việc sử dụng đặc tả HTML5 trong việc tạo ra các mô hình kinh doanh mới. Tương tự như vậy, vai trò của Web Worker là giải quyết về những vấn đề cố hữu trong vấn đề xảy ra đồng thời của JavaScript.Cả hai API này cùng minh họa một sự kết hợp mô hình sử dụng HTML5 để sử dụng cho thương mại và xã hội. Vì vậy, tiện ích của chúng chứng tỏ sự tạo điều kiện thuận lợi thích hợp và sự quản lý chung của một ứng dụng Internet phong phú của HTML5.
No comments:
Post a Comment