LevelUp! Studio » javascript https://blog.levelup.in.th Experience the new world. Fri, 26 May 2017 10:06:07 +0000 th hourly 1 http://wordpress.org/?v=3.8.1 มาใช้ EventEmitter กันดีกว่า https://blog.levelup.in.th/2014/01/31/lets-use-eventemitter%e0%b8%a1%e0%b8%b2%e0%b9%83%e0%b8%8a%e0%b9%89-eventemitter-%e0%b8%81%e0%b8%b1%e0%b8%99%e0%b8%94%e0%b8%b5%e0%b8%81%e0%b8%a7%e0%b9%88%e0%b8%b2/ https://blog.levelup.in.th/2014/01/31/lets-use-eventemitter%e0%b8%a1%e0%b8%b2%e0%b9%83%e0%b8%8a%e0%b9%89-eventemitter-%e0%b8%81%e0%b8%b1%e0%b8%99%e0%b8%94%e0%b8%b5%e0%b8%81%e0%b8%a7%e0%b9%88%e0%b8%b2/#comments Fri, 31 Jan 2014 15:50:18 +0000 http://blog.levelup.in.th/?p=3135 EventEmitter คือ class ที่เอาไว้สร้างเหตุการณ์ต่างๆ สำหรับ Node.JS ถ้าเปรียบเทียบกับงานที่ทุกคนคงรู้จักกันก็เช่น event onclick เมื่อมีการคลิกให้ทำการเรียก function ที่กำหนดให้อัตโนมัติ ในบางภาษาจะเรียก AddEventListener นั่นเอง บางคนอาจจะคิดว่าทำต้องทำต้องเป็น event ด้วยในเมื่อเรียก function ตรงๆ ก็ได้ คำตอบคือการทำงานของ class EventEmitter จะเป็นการประกาศดักรอ event เมื่อ event เกิดขึ้นจึงค่อยทำงาน ซึ่งรูปแบบการทำงานจะเป็นลักษณะ passive รอถูกเรียก และสามารถประกาศรอรับ event กี่ที่ก็ได้ ทุกๆ ที่จะโดนเรียกทั้งหมด ทำให้สามารถทำงานได้สะดวกขึ้น

EventEmitter จะมีสอง method หลักๆ ที่ใช้งานคือ on และ emit ซึ่ง on เอาไว้ดักรอ event แล้วค่อยเรียก callback function ให้ทำงาน (AddEventListener)  ส่วน emit เอาไว้เป็นตัวสั่งการให้เกิด event ชื่อที่กำหนด และจะไปเรียก callback function ที่ประกาศรอไว้ในตอนแรกจนครบโดยอัตโนมัติ (ใน flash emit ก็คือ dispatchEvent นั่นเอง)

ตัวอย่าง code:
var EventEmitter = require('events').EventEmitter;
var util = require('util');
// create the class
var MyClass = function () { }
// inherit class
MyClass.prototype.__proto__ = EventEmitter.prototype;

var obj = new MyClass();
obj.on('startProgram', function(arg){
console.log('startProgram event run '+arg);
});

obj.on('startProgram', function(arg){
console.log('startProgram event run point 2 '+arg);
});

obj.emit('startProgram', '1');

ผลลัพธ์
startProgram event run 1
startProgram event run point 2 1

จะเห็นได้ว่าประกาศ on ไว้ 2 ที่ ก็จะโดนเรียกทั้ง 2 ที่ ซึ่งเวลาใช้งานจริงสามารถประกาศ on ที่ไฟล์อื่นก็ได้ (แต่ต้องส่ง instance ของ class ไปเพื่อเรียกใช้ด้วย) ทำให้เวลาทำงานจริงเราสามารถกำหนดโครงสร้างต่างๆ ได้ง่าย ตัวอย่างการใช้งาน EventEmitter อีกตัวที่เห็นได้ชัดก็คือ Socket.IO ที่ใช้ติดต่อส่งข้อมูลผ่าน network ไปยัง client นั่นเอง หรือแม้แต่ express ก็ใช้ EventEmitter นี่เช่นกัน จะเห็นได้ว่า EventEmitter เหมาะสำหรับงานทางด้าน network เป็นที่สุด เอาไว้สร้าง code ส่วนที่เป็น asynchronous ได้โดยง่าย

]]>
https://blog.levelup.in.th/2014/01/31/lets-use-eventemitter%e0%b8%a1%e0%b8%b2%e0%b9%83%e0%b8%8a%e0%b9%89-eventemitter-%e0%b8%81%e0%b8%b1%e0%b8%99%e0%b8%94%e0%b8%b5%e0%b8%81%e0%b8%a7%e0%b9%88%e0%b8%b2/feed/ 1
ใช้ Node.js วนลูป Callback แบบเรียงลำดับด้วย “async” Library https://blog.levelup.in.th/2013/04/24/nodejs-async-eachseries/ https://blog.levelup.in.th/2013/04/24/nodejs-async-eachseries/#comments Wed, 24 Apr 2013 09:04:00 +0000 http://blog.levelup.in.th/?p=2547 ในบทความนี้จะพูดถึงการใช้งาน Node.js ในการวนลูป Callback ของการทำงานกับ Array ตามลำดับแบบ Synchronous ซี่งต่อจากนี้ไปจะขออธิบายปัญหาต่างๆ เป็นสถานการณ์ตัวอย่างครับ

สมมุติมี Array ชื่อ activities เก็บข้อมูล Object ดังนี้

var activities = [
{ title: "Raising my hand", time: 1000 },
{ title: "Crying in the rain", time: 5000 },
{ title: "Spinning my head", time: 2000 },
];

สิ่งที่จะทำคือต้องการให้ทำกิจกรรมต่างๆ ตาม [title] ในช่วงเวลา [time] milliseconds ให้ครบทั้ง Array ซึ่งคุณสามารถเขียน Loop เพื่อวนทำกิจกรรมง่ายๆ ได้ดังนี้

for(var i = 0; i < activities.length; i++) {
(function(){
var title = activities[i].title;
var time = activities[i].time;
console.log("+ " + title + " for " + time/1000 + " second(s)");
setTimeout(function(){
console.log("- " + title + " completed!");
}, time);
})();
}

จากโค้ดก็ไม่มีอะไรมาก เป็นเพียงการวนลูป setTimeOut ทำกิจกรรมตามเวลาของแต่ละกิจกรรม

ซึ่งเมื่อรันโค้ดดังกล่าว ผลลัพธ์ที่ได้คือ
+ Raising hand for 1 second(s)
+ Crying in the rain for 5 second(s)
+ Spinning head for 2 second(s)
- Raising my hand completed!
- Spinning my head completed!
- Crying in the rain completed!

สังเกตว่า การทำ Raising hand, Crying in the rain, Spinning head นั้นจะเริ่มทำพร้อมกันไปเลย เมื่อตัวไหนทำเสร็จก่อนก็จะเข้าสู่ Callback Function และรายงานผลว่าเสร็จแล้ว ซึ่งการทำแบบนี้เป็นวิธีการแบบ Asynchronous ตามแบบฉบับของ Node.js ที่ใช้ Javascript เป็นฐานอยู่แล้ว

แต่ในบางครั้ง เราต้องการผลลัพธ์ที่มีการกระทำตามลำดับทีละรายการ เช่น จากตัวอย่างด้านบนเราต้องการ Raising hand 1 วินาทีให้จบก่อน จากนั้นค่อย Crying in the rain 5 วินาที หลังจากนั้นค่อย Spinning Head อีก 2 วินาทีตามลำดับ จึงต้องมีการจัดลำดับ ให้ทำงานเป็น Synchronous ให้ได้ (ร้องไห้ไป หมุนหัวไป ยกมือไปพร้อมกันคงพิลึก)

ซึ่งถ้าเขียนตามปกติก็จะต้องเขียนโค้ดให้มีหลักการคร่าวๆ ประมาณดังนี้

console.log("+ Raising my hand for 1 second(s)");
setTimeout(function(){
console.log("- Raising my hand completed!");
console.log("+ Crying in the rain for 5 second(s)");
setTimeout(function(){
console.log("- Crying in the rain completed!");
console.log("+ Spinning my head for 2 second(s)");
setTimeout(function(){
console.log("- Spinning my head completed!");
}, 2000);
}, 5000);
}, 1000);

ผลลัพธ์ที่ได้

+ Raising my hand for 1 second(s)
- Raising my hand completed!
+ Crying in the rain for 5 second(s)
- Crying in the rain completed!
+ Spinning my head for 2 second(s)
- Spinning my head completed!

จะเห็นว่าผลลัพธ์ถูกต้องทุกประการ ทำตามลำดับอย่างดี แต่น่าเสียดายที่ตัวอย่างข้างต้นเป็นเพียงหลักการที่มีจำนวนชั้นของ Callback คงที่ ไม่สามารถนำไปใช้จริงกับ Array “ativities” ในตัวอย่างได้ เพราะเป็นไปไม่ได้เลยที่เราจะวนลูปเรียก Callback ในแต่ละสมาชิกของ Array ไปเรื่อยๆ จนกว่าจะครบทุกสมาชิกใน Array

วิธีการแก้ปัญหาอาจมีอยู่มากมาย แต่ในบทความนี้ขอนำเสนอคำสั่ง async.eachSeries() ซึ่งเป็นคำสั่งหนึ่งที่อยู่ใน Library ยอดนิยม “async” และมีรูปแบบการใช้งานที่ไม่ยุ่งยากมากนัก วิธีการใช้งาน ในขั้นตอนแรกจำเป็นต้องมี Library “async” เสียก่อน สามารถติดตั้งได้โดยพิมพ์คำสั่งด้านล่างใน Directory ที่ต้องการบนหน้าจอ Terminal หรือ Command Line

npm install async

และมีการใช้งานดังนี้

async.eachSeries(arr, iterator, callback);

โดย

  • array: Array ที่ต้องการท่องเข้าไป
  • iterator: ฟังก์ชันการทำงานที่ต้องการ
  • callback: สิ่งที่จะทำหลังจากการท่องไปยัง Array เสร็จสิ้นแล้ว

จากปัญหาที่กล่าวมา สามารถเขียนโค้ดได้ดังนี้

async.eachSeries(activities, function(activity, next)
{
var title = activity.title;
var time = activity.time;

console.log("+ " + title + " for " + time/1000 + " second(s)!");
setTimeout(function(){
console.log("- " + title + " completed!");
next();
}, time);
}, function(){
console.log("= All completed!");
});

จากตัวอย่างจะมีโค้ดที่คล้ายคลึงกับตัวอย่างแรกสุด แต่สิ่งที่ต้องมีในของ iterator มีดังนี้

  • พารามิเตอร์แรก (activity) เป็นพารามิเตอร์ที่เป็นตัวแทนของสมาชิกแต่ละตัวของ Array (ในที่นี้หมายถึงสมาชิกแต่ละตัวของ Array activitities)
  • พารามิเตอร์ที่สอง (next) เป็นพารามิเตอร์ที่เป็นฟังก์ชัน เพื่อนำไปเรียกใช้อ้างอิง Callback ของสมาชิกใน Array ตัวถัดไป
  • การเรียกใช้พารามิเตอร์ที่สอง (การใช้ next()) เป็นการบ่งบอกว่าจะไปเรียก Callback ของสมาชิกใน Array ตัวถัดไปแล้ว

เมื่อลองรันดู ผลลัพธ์ที่ได้คือ
+ Raising my hand for 1 second(s)!
- Raising my hand completed!
+ Crying in the rain for 5 second(s)!
- Crying in the rain completed!
+ Spinning my head for 2 second(s)!
- Spinning my head completed!
= All completed!

ซึ่งผลลัพธ์สามารถใช้งานร่วมกับ Array และตอบปัญหาของบทความนี้ได้แล้ว นั่นคือ Raising hand 1 วินาทีให้จบก่อน จากนั้นค่อย Crying in the rain 5 วินาที หลังจากนั้นค่อย Spinning Head อีก 2 วินาทีตามลำดับ

สามารถเข้าไปดูรายละเอียดการใช้งานและลูกเล่นอื่นๆ เพิ่มเติมได้ที่ https://github.com/caolan/async


]]>
https://blog.levelup.in.th/2013/04/24/nodejs-async-eachseries/feed/ 0
Javascript “this”, “self” object https://blog.levelup.in.th/2012/12/29/javascript-this-objectjavascript-this-object/ https://blog.levelup.in.th/2012/12/29/javascript-this-objectjavascript-this-object/#comments Sat, 29 Dec 2012 16:07:07 +0000 http://blog.levelup.in.th/?p=2199 เราคงจะคุ้นเคยว่าในภาษา OOP ทั่วๆ ไปอย่าง C#, Java นั้นจะมีการใช้งาน this เพื่ออ้างอิงถึงตัว obj ของ class นั้นๆ แต่ว่า this ใน javascript นั้นจะแตกต่างกันออกไป เราลองมาดูตัวอย่าง


var obj = {
items: ["a", "b", "c"],
process: function() {
this.items.forEach(function(item) {
this.print(item);
});
},
print: function(item) {
console.log('*' + item + '*');
}
};
obj.process();

ตัวอย่างนี้เราประกาศตัวแปรชื่อ obj มี properties ชื่อ items และมี function ชื่อ process กับ print เราสั่งให้ทำงานด้วย obj.process() ซึ่งจะเห็นว่ามีการสั่ง this.items.forEach ณ บรรทัดนี้โค้ดจะยังทำงานได้ดังที่เราคาดหวังอยู่ แต่เมื่อเข้ามาอยู่ใน forEach แล้วบรรทัดที่สั่ง this.print(item); ก็ควรจะทำงานได้เหมือน this.items ใช่ไหมครับ แต่เดี๋ยวก่อน! ลอง copy ไปรันใน Google Chrome Developer Tools หรือ Firebug ไหงไม่มีผลลัพธ์ออกมาเลยล่ะ! ลองมาดูที่บรรทัดนี้อีกครั้ง


this.items.forEach(function(item) {
this.print(item);
});

this.items อ้างถึง items จาก function ชื่อ process ได้ แต่ this.print ทำไมสั่งไม่ได้ล่ะ? เป็นเพราะเมื่อมีการประกาศ function(item) {} ซึ่งเป็น function anonymous (ไม่มีชื่อ) ขึ้นมาจะพบว่ามีการสร้าง block ขอบเขตให้ตัวแปร block ใหม่ การประกาศตัวแปรใดๆ ในนี้จะไม่สามารถถูกเรียกจากนอก scope function นี้ได้ใช่ไหมครับ เช่น


this.items.forEach(function(item) {
var a =5;
});
console.log(a);

แน่นอน เราไม่สามารถสั่งการแบบนี้ได้ a จะได้เป็น undefined เช่นเดียวกันกับตัวแปร this ซึ่งตัว javascript จะถือว่าเป็นตัวแปรภายใน scope anonymous function โดยอัตโนมัติ เราไม่ได้เป็นคนประกาศตัวแปรชื่อ this การที่เราสั่ง this.print(item) this นั้นเป็นตัวแปรภายใน scope ที่เราสร้างขึ้นเอง จะไม่สามารถอ้างอิงถึง function print ได้จริงๆ เพราะอยู่คนละ scope กัน ดังนั้น ทีนี้มาดูวิธีแก้ปัญหากันครับ


var self = this;
this.items.forEach(function(item) {
self.print(item);
});

เราจะสร้างตัวแปรชื่อ self มารับค่า this เอาไว้ก่อนเข้าส่วนของ forEach ซึ่งภาษา Javascript นี้สามารถอ้างอิงถึงตัวแปรที่อยู่ภายนอก scope ได้ (ตรงกันข้าม ไม่สามารถอ้างถึงตัวแปรที่อยู่ภายใน scope ที่ลึกกว่าได้ดังที่แสดงให้ดูไปแล้ว เนื่องจาก code ด้านในยังไม่ถูก execute จริงๆ) ทำให้มีตัวแปรที่จำค่า this ของก่อนเข้า forEach เอาไว้ พอมีการอ้างถึง self ซึ่งเก็บว่า this ของ scope ตัวนอกเอาไว้จึงสามารถทำงานได้เป็นปกติครับ เทคนิคนี้ถูกใช้อย่างแพร่หลายมากใน library javascript หลายๆ ตัว ดังนั้นถ้าเจอ self เมื่อไหร่ให้เดาได้เลยว่ามันคือ this ของ scope ตัวนอกครับ :)

Reference: http://book.mixu.net/ch4.html

]]>
https://blog.levelup.in.th/2012/12/29/javascript-this-objectjavascript-this-object/feed/ 0
การส่งค่าจากแฟลชให้แสดงที่ console ในเว็บเบราเซอร์ต่างๆ https://blog.levelup.in.th/2012/09/30/send-data-for-js-console-from-flash/ https://blog.levelup.in.th/2012/09/30/send-data-for-js-console-from-flash/#comments Sun, 30 Sep 2012 16:20:56 +0000 http://blog.levelup.in.th/?p=2063 โดยปกติแล้วเราชาว Flash โปรแกรมเมอร์เวลาต้องการจะเช็คค่าที่ตำแหน่งต่างๆของโค้ดของเรา เราก็มักจะใช้ trace(“//string”); เพื่อเช็คค่าต่างๆขณะที่รันเทสแอปพลิเคชั่นของเรา แต่ในบางทีแล้วเราต้องการที่จะดักค่าที่เราต้องการทดสอบกับข้อมูลจริง ซึ่งต้องเป็นตัวที่ publish ไปรันบนแอปพลิเคชั่นจริงๆแล้วเราจึงไม่สามารถดู trace ที่เราเขียนขึ้นมาได้ เราจึงต้องมีการใช้วิธีต่างกันไป โดยวิธีที่จะนำมาเสนอในวันนี้จะเป็นดังนี้ครับ

เราจะทำการเรียกฟังก์ชั่น console.log ของ javascript ซึ่งจะแสดงค่าที่เราใส่ไว้ใน console ของ Developer Tools ที่มีใน Web Browser ในสมัยนี้ ซึ่งต่างๆกันไป

วิธีการเรียก console.log ก็จะมีหน้าตาดังนี้


ExternalInterface.call("console.log",[{
'test':"call me maybe"
}]);

จากการใช้ ฟังก์ชั่น ExternalInterface.call ซึ่งรับค่าสองตัว คือ ชื่อฟังก์ชั่น JS ที่จะเรียกและ ค่า Argument ที่จะส่งไปในฟังก์ชั่นนั้น ทำให้เราสามารถเรียกฟังก์ชั่น console.log ได้โดยใส่ค่าที่ต้องแสดงหรือตัวแปรที่ต้องการทราบค่า (นอกจากนั้นเรายังสามารถใส่ Object ทั้งก้อนเพื่อดูค่าด้านในได้เลยซึ่ง trace ทำไม่ได้)

ซึ่งจะทำให้เราเห็นค่าดังนี้

ตัวอย่างจาก Google Chrome (กด F12 แล้วเปิด Console ด้านล่าง)

ตัวอย่างจาก Google Chrome (กด F12 แล้วเปิด Console ด้านล่าง)

]]>
https://blog.levelup.in.th/2012/09/30/send-data-for-js-console-from-flash/feed/ 0
วิธี Invite Friend หรือส่ง Request ใน Facebook ด้วย Javascript SDK https://blog.levelup.in.th/2011/10/31/how-to-invite-friend-or-send-a-request-in-facebook-with-javascript-sdk%e0%b8%a7%e0%b8%b4%e0%b8%98%e0%b8%b5-invite-friend-%e0%b8%ab%e0%b8%a3%e0%b8%b7%e0%b8%ad%e0%b8%aa%e0%b9%88%e0%b8%87-request/ https://blog.levelup.in.th/2011/10/31/how-to-invite-friend-or-send-a-request-in-facebook-with-javascript-sdk%e0%b8%a7%e0%b8%b4%e0%b8%98%e0%b8%b5-invite-friend-%e0%b8%ab%e0%b8%a3%e0%b8%b7%e0%b8%ad%e0%b8%aa%e0%b9%88%e0%b8%87-request/#comments Mon, 31 Oct 2011 15:39:41 +0000 http://blog.levelup.in.th/?p=1276 ก่อนจะอ่านต่อ แนะนำให้ไปอ่านการใช้งาน Facebook Javascript SDK เบื้องต้นที่บทความเก่าของผมอันนี้ก่อนครับ คือต้องสั่ง FB.init ก่อนจะใช้งานครับ จากนั้นเรามาดูรูปแบบคำสั่งกันเลยดีกว่าครับ (ถ้าใครใช้กับ app เก่าที่มีอยู่แล้ว ให้ปรับที่หน้า developer ของ app tab Advanced ให้ Requests 2.0 Efficient เป็น enable เอาไว้ด้วยครับ)

Request Dialog 2.0

Request Dialog 2.0


FB.ui({
method: 'apprequests',
message: 'ข้อความที่จะแสดงให้ผู้รับเห็น',
filters: ['all'],
exclude_ids:['123'],
max_recipients: 20
}, function(response){
// ตรวจสอบว่าได้มีการเลือกเพื่อนอย่างน้อย 1 คนจึงจะทำงานต่อไป
if (response != null && response.to.length > 0){
for (var i=0; i < response.to.length; i++) {
alert(response['to'][i]); // วนลูปทดลองสั่งให้แสดงเลข user_id ของเพื่อนที่เลือกไป
}
}
}
);

จาก code ด้านบน ขออธิบายดังนี้

  • method (string) – บังคับระบุเป็น apprequests
  • message (string) – คือข้อความที่ต้องการให้ผู้รับเห็น
  • filters (array) – ต้องการให้แสดง list ของกลุ่มผู้ใช้กลุ่มใดบ้าง ระบุได้มากกว่าหนึ่งอย่าง โดยสามารถระบุได้ 3 อย่างได้แก่
    • all – แสดงเพื่อนทั้งหมดของผู้ใช้
    • app_users – แสดงเฉพาะเพื่อนที่ใช้งาน application ตัวนี้เหมือนกัน
    • app_non_users – แสดงเฉพาะเพื่อนที่ยังไม่เคยเข้ามาใช้งาน application ตัวนี้มาก่อน
  • exclude_ids (array) – ระบุยกเว้น user_id ใดๆ ที่ไม่ต้องการให้แสดง โดยกรอกเป็น array ของ user_id (ตัวอย่างการใช้งานเช่น ใช้กับการห้ามส่ง gift หาเพื่อนซ้ำคนเดิมในวันเดียวกันได้)
  • max_recipients (int) – กำหนดให้ผู้ใช้เลือกเพื่อนได้สูงสุดกี่คน
  • callback (function) – ใน parameter ตัวสุดท้ายจะเป็น callback function ซึ่งจะส่งค่า response กลับเข้าไปใน function นี้โดย response เป็นตัวแปรชนิด Object มีโครงสร้างดังนี้
    • request (int) – เป็น id การ request ครั้งนี้
    • to (array) – array ของ user_id ของเพื่อนที่ได้เลือกไป

เมื่อส่ง request เสร็จแล้ว และผู้รับได้กดรับ request แล้วเราจะต้องสั่งลบ request นั้นๆ เอง ไม่เช่นนั้นจะมี request ค้างอยู่ในหน้า app request หรือ game request อยู่อย่างนั้น โดยวิธีการลบคือให้นำ request id ที่ส่งมาต่อกับ user_id ของคนที่กดรับ request โดยคั่นกลางด้วย _ จะได้เลขอ้างอิงสำหรับลบเช่น โครงสร้าง javascript object ที่ได้รับมาเป็น {request:123, to:[3,4,5]} จะได้เป็น 123_3 ใช้ลบ request ของ user_id 3 ได้ 123_4 ใช้ลบ request ของ user_id 4 เป็นต้น วิธีการสั่งลบคือให้เรียก Graph API (ใช้ access_token ของ application ในการใช้สิทธิลบ) เพื่อลบเช่น (php นะครับ)
$facebook->api(“/123_3″,’DELETE’);
ก็จะลบ request ที่ user_id 3 กดรับไปแล้วออกจากหน้า app/game request ครับ

อันที่จริงในส่วนของการลบ request ไม่จำเป็นต้องทำก็ได้ application ยังคงทำงานได้ตามปกติแม้ไม่ลบ หากไม่เข้าใจขั้นตอนในการลบ request สามารถข้ามไปได้ครับ เพียงแต่ใน facebook เค้าว่า “เป็นหน้าที่ของ developer ที่จะต้องลบ request ที่ใช้งานแล้วทิ้งเอง” ซึ่งก็ไม่ได้บอกว่าถ้าไม่ลบจะเกิดอะไรขึ้นครับ ฮาๆ ขอให้สนุกกับการสร้าง application บน facebook นะครับ :)

]]>
https://blog.levelup.in.th/2011/10/31/how-to-invite-friend-or-send-a-request-in-facebook-with-javascript-sdk%e0%b8%a7%e0%b8%b4%e0%b8%98%e0%b8%b5-invite-friend-%e0%b8%ab%e0%b8%a3%e0%b8%b7%e0%b8%ad%e0%b8%aa%e0%b9%88%e0%b8%87-request/feed/ 0