MediaRecorder APIã䜿çšãããã©ãŠã¶ããŒã¹ã®MediaStreamé²ç»ã®äžçãæ¢æ±ããŸãããµãŒããŒãµã€ãã®äŸåé¢ä¿ãªãã«ããã©ãŠã¶ã§çŽæ¥é³å£°ãšæ åããã£ããã£ããæ¹æ³ãåŠã³ããªãããªWebã¢ããªã±ãŒã·ã§ã³ãå®çŸããŸãã
ããã³ããšã³ãMediaStreamé²ç»ïŒãã©ãŠã¶ããŒã¹ã®ã¡ãã£ã¢ãã£ããã£
Webãã©ãŠã¶å
ã§çŽæ¥é³å£°ãæ åããã£ããã£ããæ©èœã¯ãWebã¢ããªã±ãŒã·ã§ã³éçºã«é©åœããããããŸãããMediaRecorder APIãæŽ»çšããããã³ããšã³ãã®MediaStreamé²ç»ã¯ãè€éãªãµãŒããŒãµã€ãåŠçã«é Œãããšãªããã®æ©èœãå®çŸããã匷åãã€å¹ççãªæ¹æ³ãæäŸããŸãããã®ã¢ãããŒãã«ãããç¹ã«ãªã³ã©ã€ã³äŒè°ããããªç·šéããŒã«ãã€ã³ã¿ã©ã¯ãã£ããªãã¥ãŒããªã¢ã«ãªã©ã®ã¢ããªã±ãŒã·ã§ã³ã«ãããŠããªã¢ã«ã¿ã€ã ã®ã€ã³ã¿ã©ã¯ã·ã§ã³ãé
å»¶ã®åæžããããŠãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®åäžãå¯èœã«ãªããŸãã
MediaStream APIãçè§£ãã
ãã©ãŠã¶ããŒã¹ã®ã¡ãã£ã¢ãã£ããã£ã®äžå¿ã«ããã®ãMediaStream APIã§ããMediaStreamã¯ãé³å£°ãæ åãã©ãã¯ãªã©ã®ã¡ãã£ã¢ããŒã¿ã®ã¹ããªãŒã ã衚ããŸããMediaStreamã«ã¢ã¯ã»ã¹ããã«ã¯ãéåžžgetUserMedia()ã¡ãœããã䜿çšããŸãã
getUserMedia()ã¡ãœããã¯ããŠãŒã¶ãŒã«ãã€ã¯ãã«ã¡ã©ãžã®ã¢ã¯ã»ã¹èš±å¯ãæ±ããŸãããŠãŒã¶ãŒãèš±å¯ãäžãããšMediaStreamãªããžã§ã¯ãã§è§£æ±ºãããPromiseãè¿ãããŠãŒã¶ãŒãèš±å¯ãæåŠããå Žåãã¢ã¯ã»ã¹ãå©çšã§ããªãå Žåã¯ãšã©ãŒã§æåŠããŸãã
äŸïŒã«ã¡ã©ã¢ã¯ã»ã¹ãèŠæ±ãã
以äžã¯ããŠãŒã¶ãŒã®ã«ã¡ã©ãžã®ã¢ã¯ã»ã¹ãèŠæ±ããåºæ¬çãªäŸã§ãïŒ
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(function(stream) {
// Stream is available, do something with it
console.log("Camera access granted!");
})
.catch(function(error) {
console.error("Error accessing camera: ", error);
});
説æïŒ
navigator.mediaDevices.getUserMedia({ video: true, audio: false })ïŒãã®è¡ã¯ã«ã¡ã©ïŒvideo: trueïŒãžã®ã¢ã¯ã»ã¹ãèŠæ±ããé³å£°ïŒaudio: falseïŒãæç€ºçã«ç¡å¹ã«ããŸãããããã®ãªãã·ã§ã³ã調æŽããŠãé³å£°ãšæ åã®äž¡æ¹ããŸãã¯é³å£°ã®ã¿ãèŠæ±ããããšãã§ããŸãã.then(function(stream) { ... })ïŒãã®ãããã¯ã¯ããŠãŒã¶ãŒãèš±å¯ãäžããå Žåã«å®è¡ãããŸããstream倿°ã«ã¯MediaStreamãªããžã§ã¯ããä¿æãããŸãã.catch(function(error) { ... })ïŒãã®ãããã¯ã¯ããŠãŒã¶ãŒãèš±å¯ãæåŠãããªã©ããšã©ãŒãçºçããå Žåã«å®è¡ãããŸããè¯ããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæäŸããããã«ããšã©ãŒãé©åã«åŠçããããšãéèŠã§ãã
getUserMedia()ã®æ§æãªãã·ã§ã³
getUserMedia()ã¡ãœããã¯ãã¡ãã£ã¢ã¹ããªãŒã ã®æãŸããç¹æ§ãæå®ã§ãããªãã·ã§ã³ã®å¶çŽãªããžã§ã¯ããåãå
¥ããŸããããã«ã¯æ¬¡ã®ãããªãªãã·ã§ã³ãå«ãŸããŸãïŒ
videoïŒãããªãèŠæ±ããããã®ããŒã«å€ïŒtrue/falseïŒããŸãã¯ããå ·äœçãªãããªå¶çŽïŒäŸïŒè§£å床ããã¬ãŒã ã¬ãŒãïŒã®ããã®ãªããžã§ã¯ããaudioïŒé³å£°ãèŠæ±ããããã®ããŒã«å€ïŒtrue/falseïŒããŸãã¯ããå ·äœçãªé³å£°å¶çŽïŒäŸïŒãšã³ãŒãã£ã³ã»ã¬ãŒã·ã§ã³ããã€ãºæå¶ïŒã®ããã®ãªããžã§ã¯ããwidthïŒãããªã¹ããªãŒã ã®æãŸããå¹ ãheightïŒãããªã¹ããªãŒã ã®æãŸããé«ããframeRateïŒãããªã¹ããªãŒã ã®æãŸãããã¬ãŒã ã¬ãŒãã
äŸïŒç¹å®ã®ã«ã¡ã©è§£å床ãèŠæ±ãã
navigator.mediaDevices.getUserMedia({
video: {
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 480, ideal: 720, max: 1080 }
},
audio: true
})
.then(function(stream) {
// Stream is available
})
.catch(function(error) {
// Handle errors
});
ãã®äŸã§ã¯ãå¹ ã640ãã1920ãã¯ã»ã«ïŒçæ³çã«ã¯1280ïŒãé«ãã480ãã1080ãã¯ã»ã«ïŒçæ³çã«ã¯720ïŒã®ãããªã¹ããªãŒã ãèŠæ±ããŠããŸãããŸããé³å£°ãèŠæ±ããŠããŸãã
MediaRecorder APIã®ç޹ä»
MediaStreamãååŸããããMediaRecorder APIã䜿çšããŠã¡ãã£ã¢ããŒã¿ãé²ç»ã§ããŸããMediaRecorder APIã¯ãé²ç»ã®éå§ã忢ãäžæåæ¢ãåéã®ããã®ã¡ãœãããããã³é²ç»ãããããŒã¿ã«ã¢ã¯ã»ã¹ããããã®ã¡ãœãããæäŸããŸãã
MediaRecorderã€ã³ã¹ã¿ã³ã¹ã®äœæ
MediaRecorderã€ã³ã¹ã¿ã³ã¹ãäœæããã«ã¯ãMediaStreamãªããžã§ã¯ããMediaRecorderã³ã³ã¹ãã©ã¯ã¿ã«æž¡ããŸãïŒ
const mediaRecorder = new MediaRecorder(stream);
ã³ã³ã¹ãã©ã¯ã¿ã«ã¯ãé²ç»ããŒã¿ã®æãŸããMIMEã¿ã€ããªã©ã远å ã®ãªãã·ã§ã³ãæå®ããããšãã§ããŸãïŒ
const options = { mimeType: 'video/webm;codecs=vp9' };
const mediaRecorder = new MediaRecorder(stream, options);
ãµããŒããããŠããMIMEã¿ã€ãïŒ
å©çšå¯èœãªMIMEã¿ã€ãã¯ããã©ãŠã¶ãšããããµããŒãããã³ãŒããã¯ã«äŸåããŸããäžè¬çãªMIMEã¿ã€ãã«ã¯ä»¥äžãå«ãŸããŸãïŒ
video/webm;codecs=vp9video/webm;codecs=vp8video/mp4;codecs=avc1audio/webm;codecs=opusaudio/ogg;codecs=vorbis
ç¹å®ã®MIMEã¿ã€ãããã©ãŠã¶ã§ãµããŒããããŠãããã©ããã確èªããã«ã¯ãMediaRecorder.isTypeSupported()ã¡ãœããã䜿çšã§ããŸãïŒ
if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
console.log('video/webm;codecs=vp9 is supported');
} else {
console.log('video/webm;codecs=vp9 is not supported');
}
MediaRecorderã§ã®ããŒã¿é²ç»
MediaRecorder APIã¯ãé²ç»ããã»ã¹ãç£èŠããããã«ãªãã¹ã³ã§ããããã€ãã®ã€ãã³ããæäŸããŸãïŒ
dataavailableïŒä¿åå¯èœãªããŒã¿ãå©çšå¯èœã«ãªããã³ã«çºçããŸããstartïŒé²ç»ãéå§ããããšçºçããŸããstopïŒé²ç»ã忢ãããšçºçããŸããpauseïŒé²ç»ãäžæåæ¢ãããšçºçããŸããresumeïŒé²ç»ãåéããããšçºçããŸããerrorïŒé²ç»äžã«ãšã©ãŒãçºçããå Žåã«çºçããŸãã
æãéèŠãªã€ãã³ãã¯dataavailableã§ãããã®ã€ãã³ãã¯ãé²ç»ãããããŒã¿ãå«ãBlobãªããžã§ã¯ããæäŸããŸãããããã®Blobãªããžã§ã¯ããèç©ããé²ç»ãå®äºãããšãã«åäžã®Blobã«çµåããããšãã§ããŸãã
äŸïŒæ åã®é²ç»ãšä¿å
let recordedChunks = [];
mediaRecorder.ondataavailable = function(event) {
console.log('data-available: ', event.data.size);
if (event.data.size > 0) {
recordedChunks.push(event.data);
}
};
mediaRecorder.onstop = function() {
console.log('Recording stopped!');
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'recorded-video.webm';
document.body.appendChild(a);
a.click();
setTimeout(() => {
URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 100);
};
mediaRecorder.start();
console.log("Recording started!");
// To stop recording:
// mediaRecorder.stop();
説æïŒ
let recordedChunks = [];ïŒé²ç»ãããããŒã¿ãã£ã³ã¯ãæ ŒçŽããããã®é åãmediaRecorder.ondataavailable = function(event) { ... }ïŒæ°ããããŒã¿ãå©çšå¯èœã«ãªããã³ã«åŒã³åºãããŸããããŒã¿ãrecordedChunksé åã«è¿œå ããŸããmediaRecorder.onstop = function() { ... }ïŒé²ç»ã忢ãããšãã«åŒã³åºãããŸããèç©ããããã£ã³ã¯ããBlobãäœæãããã®Blobã®URLãçæããããŠã³ããŒããªã³ã¯ãäœæããŠããŠã³ããŒããããªã¬ãŒããŸãããŸããçãé å»¶ã®åŸã§äœæãããURLãªããžã§ã¯ããã¯ãªãŒã³ã¢ããããŸããmediaRecorder.start();ïŒé²ç»ããã»ã¹ãéå§ããŸããmediaRecorder.stop();ïŒãããåŒã³åºããŠé²ç»ã忢ããŸãã
é²ç»ããã»ã¹ã®å¶åŸ¡
MediaRecorder APIã¯ãé²ç»ããã»ã¹ãå¶åŸ¡ããããã®ã¡ãœãããæäŸããŸãïŒ
start(timeslice)ïŒé²ç»ãéå§ããŸãããªãã·ã§ã³ã®timesliceåŒæ°ã¯ãdataavailableã€ãã³ããçºçããééïŒããªç§åäœïŒãæå®ããŸããtimesliceãæå®ãããªãå Žåãdataavailableã€ãã³ãã¯é²ç»ã忢ããããšãã«ã®ã¿çºçããŸããstop()ïŒé²ç»ã忢ããŸããpause()ïŒé²ç»ãäžæåæ¢ããŸããresume()ïŒé²ç»ãåéããŸããrequestData()ïŒæåã§dataavailableã€ãã³ããããªã¬ãŒããŸãã
ãã©ãŠã¶ã®äºææ§ãšããªãã£ã«
MediaStreamããã³MediaRecorder APIã¯ãçŸä»£ã®ãã©ãŠã¶ã§åºããµããŒããããŠããŸãããã ããå€ããã©ãŠã¶ã§ã¯ãããã®APIããã€ãã£ãã«ãµããŒããããŠããªãå ŽåããããŸããå€ããã©ãŠã¶ããµããŒãããå¿
èŠãããå Žåã¯ãããªãã£ã«ã䜿çšããŠå¿
èŠãªæ©èœãæäŸã§ããŸãã
ããã€ãã®ããªãã£ã«ãå©çšå¯èœã§ãã以äžãå«ãŸããŸãïŒ
adapter.jsïŒãã®ããªãã£ã«ã¯ãgetUserMedia()ãå«ãWebRTC APIã®ã¯ãã¹ãã©ãŠã¶äºææ§ãæäŸããŸããrecorderjsïŒãã€ãã£ãã§ãµããŒãããŠããªããã©ãŠã¶åãã«MediaRecorderæ©èœãæäŸããJavaScriptã©ã€ãã©ãªã
å®è·µçãªã¢ããªã±ãŒã·ã§ã³ãšãŠãŒã¹ã±ãŒã¹
ããã³ããšã³ãã®MediaStreamé²ç»ã¯ãWebã¢ããªã±ãŒã·ã§ã³éçºã«å¹ åºãå¯èœæ§ãéããŸãã以äžã«å®è·µçãªã¢ããªã±ãŒã·ã§ã³ãšãŠãŒã¹ã±ãŒã¹ãããã€ã瀺ããŸãïŒ
- ãªã³ã©ã€ã³äŒè°ãšãããªäŒè°ïŒãªã³ã©ã€ã³äŒè°ããããªäŒè°ã®ããã«ãé³å£°ãšæ åã®ã¹ããªãŒã ããªã¢ã«ã¿ã€ã ã§ãã£ããã£ããéä¿¡ããŸãã
- ãããªç·šéããŒã«ïŒãŠãŒã¶ãŒããã©ãŠã¶ã§çŽæ¥ãããªã³ã³ãã³ããé²ç»ã»ç·šéã§ããããã«ããŸãã
- ã€ã³ã¿ã©ã¯ãã£ããªãã¥ãŒããªã¢ã«ãšãã¢ã³ã¹ãã¬ãŒã·ã§ã³ïŒãŠãŒã¶ãŒã®æäœããã£ããã£ããããŒãœãã©ã€ãºããããã£ãŒãããã¯ãæäŸããã€ã³ã¿ã©ã¯ãã£ããªãã¥ãŒããªã¢ã«ããã¢ã³ã¹ãã¬ãŒã·ã§ã³ãäœæããŸãã
- é³å£°é²é³ã¢ããªã±ãŒã·ã§ã³ïŒã¡ã¢åãããã€ã¹ã¡ã¢ãé³å£°ç·šéã®ããã®é³å£°é²é³ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããŸãã
- ç£èŠã·ã¹ãã ãšã»ãã¥ãªãã£ã«ã¡ã©ïŒãããªã¹ããªãŒã ããã£ããã£ããŠèšé²ãããã©ãŠã¶ããŒã¹ã®ç£èŠã·ã¹ãã ãã»ãã¥ãªãã£ã«ã¡ã©ãå®è£ ããŸãã
- ã¢ã¯ã»ã·ããªãã£ããŒã«ïŒé³å£°ãé²é³ããŠãªã¢ã«ã¿ã€ã ã§ããã¹ãã«å€æããããåŸã§ç¢ºèªããããã«ç»é¢ã®ã¢ã¯ãã£ããã£ãèšé²ãããããããŒã«ãéçºããŸãã
äŸïŒã·ã³ãã«ãªæ åé²ç»ã¢ããªã±ãŒã·ã§ã³ã®å®è£
以äžã¯ãHTMLãCSSãJavaScriptã䜿çšããŠããããŸã§èª¬æããæŠå¿µãåºæ¬çãªæ åé²ç»ã¢ããªã±ãŒã·ã§ã³ã«çµ±åããç°¡åãªäŸã§ãïŒ
HTML (index.html):
Browser Video Recorder
Browser Video Recorder
CSS (style.css):
body {
font-family: sans-serif;
text-align: center;
}
video {
width: 640px;
height: 480px;
border: 1px solid #ccc;
}
button {
padding: 10px 20px;
font-size: 16px;
margin: 10px;
}
JavaScript (script.js):
const preview = document.getElementById('preview');
const recordButton = document.getElementById('recordButton');
const stopButton = document.getElementById('stopButton');
let mediaRecorder;
let recordedChunks = [];
recordButton.addEventListener('click', startRecording);
stopButton.addEventListener('click', stopRecording);
async function startRecording() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
preview.srcObject = stream;
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.onstop = handleStop;
mediaRecorder.start();
recordButton.disabled = true;
stopButton.disabled = false;
} catch (err) {
console.error("Error accessing media devices.", err);
}
}
function handleDataAvailable(event) {
if (event.data.size > 0) {
recordedChunks.push(event.data);
}
}
function stopRecording() {
mediaRecorder.stop();
recordButton.disabled = false;
stopButton.disabled = true;
//Stop all video streams
preview.srcObject.getVideoTracks().forEach(track => track.stop());
}
function handleStop() {
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'recorded-video.webm';
document.body.appendChild(a);
a.click();
setTimeout(() => {
URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 100);
recordedChunks = []; // Reset array for the next recording
}
ãã®äŸã¯ããã©ãŠã¶å ã§çŽæ¥ãããªããã£ããã£ã衚瀺ãé²ç»ãããŠã³ããŒãããéã®äžå¿çãªååã瀺ããŠããŸããæ©èœã匷åããããã«ããšã©ãŒãã³ããªã³ã°ãç°ãªãã³ãŒããã¯ãªãã·ã§ã³ããŸãã¯ãŠãŒã¶ãŒã調æŽå¯èœãªé²ç»å質ã远å ããããšãæ€èšããŠãã ããã
ã»ãã¥ãªãã£ã«é¢ããèæ ®äºé
MediaStreamé²ç»ã䜿çšããéã«ã¯ãã»ãã¥ãªãã£ã«é¢ããèæ ®äºé ãèªèããããšãäžå¯æ¬ ã§ãïŒ
- ãŠãŒã¶ãŒã®èš±å¯ïŒãã€ã¯ãã«ã¡ã©ã«ã¢ã¯ã»ã¹ããåã«ãå¿ ããŠãŒã¶ãŒã®èš±å¯ãæ±ããŠãã ããããããã®ããã€ã¹ãžã®ã¢ã¯ã»ã¹ãå¿ èŠãªçç±ãæç¢ºã«ç€ºããŠãã ããã
- HTTPSïŒã¡ãã£ã¢ã¹ããªãŒã ãæå·åãããçèŽããä¿è·ãããããã«HTTPSã䜿çšããŠãã ããã
getUserMedia()APIã¯éåžžãã»ãã¥ã¢ãªã³ã³ããã¹ãïŒHTTPSïŒãå¿ èŠãšããŸãã - ããŒã¿ã¹ãã¬ãŒãžïŒé²ç»ããŒã¿ãä¿åããå Žåã¯ããããå®å šã«ä¿åãããäžæ£ã¢ã¯ã»ã¹ããä¿è·ãããŠããããšã確èªããŠãã ãããæå·åãã¢ã¯ã»ã¹å¶åŸ¡ã¡ã«ããºã ã®äœ¿çšãæ€èšããŠãã ããããŠãŒã¶ãŒãšãã®æåšå°ã«é¢é£ããããŒã¿ãã©ã€ãã·ãŒèŠå¶ïŒäŸïŒGDPRãCCPAïŒãéµå®ããŠãã ããã
- ãã©ã€ãã·ãŒïŒé²ç»ããŒã¿ãã©ã®ããã«äœ¿çšããŠãããã«ã€ããŠéææ§ãä¿ã£ãŠãã ããããŠãŒã¶ãŒã«èªåã®ããŒã¿ãå¶åŸ¡ããåé€ããèœåãæäŸããŠãã ããã
- æªæã®ããã³ãŒãïŒãŠãŒã¶ãŒçæã³ã³ãã³ããæ±ãéã«ã¯æ³šæããŠãã ãããæªæã®ããã³ãŒããå«ãŸããŠããå¯èœæ§ããããŸããã¯ãã¹ãµã€ãã¹ã¯ãªããã£ã³ã°ïŒXSSïŒæ»æãé²ãããã«ããã¹ãŠã®ãŠãŒã¶ãŒå ¥åããµãã¿ã€ãºããŠãã ããã
ããã©ãŒãã³ã¹ã®æé©å
MediaStreamé²ç»ã䜿çšããéã«æé©ãªããã©ãŒãã³ã¹ã確ä¿ããããã«ã¯ã以äžãèæ ®ããŠãã ããïŒ
- MIMEã¿ã€ãã®éžæïŒãã©ãŠã¶ã§ãµããŒããããŠãããè¯å¥œãªå§çž®ãæäŸããMIMEã¿ã€ããéžæããŠãã ããã
- Timesliceã®ééïŒããŒã¿ã®å¯çšæ§ãšããã©ãŒãã³ã¹ã®ãã©ã³ã¹ãåãããã«
timesliceã®ééã調æŽããŠãã ãããtimesliceã®ééãçããããšãdataavailableã€ãã³ããããé »ç¹ã«çºçããŸããããªãŒããŒããããå¢å ããå¯èœæ§ããããŸãã - ããŒã¿ãã³ããªã³ã°ïŒã¡ã¢ãªãªãŒã¯ãããã©ãŒãã³ã¹ã®ããã«ããã¯ãé¿ããããã«ãé²ç»ãããããŒã¿ãå¹ççã«åŠçããŠãã ããã倧éã®ããŒã¿ãåŠçããããã«ããããã¡ãªã³ã°ãã¹ããªãŒãã³ã°ãªã©ã®æè¡ã䜿çšããŠãã ããã
- ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ïŒé²ç»ããã»ã¹ã«ã€ããŠãŠãŒã¶ãŒã«æç¢ºãªãã£ãŒãããã¯ãæäŸãããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãèšèšããŠãã ãããé²ç»ã€ã³ãžã±ãŒã¿ãŒã衚瀺ããé²ç»ã®äžæåæ¢ãåéã忢ã®ããã®ã³ã³ãããŒã«ãæäŸããŠãã ããã
çµè«
ããã³ããšã³ãã®MediaStreamé²ç»ã¯ãWebéçºè
ããã©ãŠã¶å
ã§çŽæ¥ããªããã§ã€ã³ã¿ã©ã¯ãã£ããªã¡ãã£ã¢äœéšãäœæããããšãå¯èœã«ããŸããMediaStreamããã³MediaRecorder APIãçè§£ããããšã§ãéçºè
ã¯ãªã³ã©ã€ã³äŒè°ããããªç·šéããŒã«ãããã€ã³ã¿ã©ã¯ãã£ããªãã¥ãŒããªã¢ã«ãç£èŠã·ã¹ãã ãŸã§ãå¹
åºãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸããã»ãã¥ãªãã£ãšããã©ãŒãã³ã¹ã«é¢ããèæ
®äºé
ã«æ³šæãæãããšã§ãWebã¢ããªã±ãŒã·ã§ã³ã®æ©èœæ§ãšãšã³ã²ãŒãžã¡ã³ããåäžããããå
ç¢ã§ãŠãŒã¶ãŒãã¬ã³ããªãŒãªã¡ãã£ã¢é²ç»ãœãªã¥ãŒã·ã§ã³ãäœæã§ããŸãã