Phiếu đi chợ

Ông bà mình thường nói “Các con bây giờ làm sao mà biết được thời kì tem phiếu nó thế nào”. Và mình cũng nghĩ rằng, chắc sẽ không bao giờ biết được trải nghiệm đó. Vậy mà, trong những năm đất nước phát triển này, trải nghiệm đó đã quay lại. Nhưng nó quay lại với một ý nghĩa khác, một ý nghĩa tích cực hơn.

Trước tình hình dịch bệnh Covid phức tạp, khả năng lây nhiễm trong cộng đồng cao. Chợ lại là nơi có nhiều người lui đến, cho nên phiếu đi chợ ra đời để hạn chế số lượng người đến chợ trong một ngày cũng như dễ dàng kiểm soát được những ai đã đến trong ngày đó.

Thực ra đối với gia đình mình nó cũng không quá tù túng lắm nhưng với một vài gia đình khác sẽ hơi khó khăn cho họ. Tuy nhiên trong hoàn cảnh này, mỗi người chịu khó một chút, hy sinh một chút, mình tin đợt dịch này sẽ sớm được dập tắt và mọi thứ sẽ trở về như cũ.

Dù sao, trong cái hoàn cảnh hiện tại, coi như mọi người đã có một chút kỷ niệm thú vị trong cuộc đời.

Phiếu đi chợ


The Sixth Sense (1999) - Một bộ phim hack não nhẹ nhàng và thú vị

Chú ý: Đây không phải là review phim, chỉ là những dòng lưu lại để nhớ, sau khi xem một bộ phim mình cảm thấy thú vị.

Đã được vài ngày kể từ khi tạm dừng chơi game, thật ra thỉnh thoảng cũng mò vào một tí nhưng rồi thoát ra.
Tuy nhiên nhiều khi rãnh rỗi thật sự, không biết làm gì và không muốn làm gì. Thế là mình tìm phim để coi. Mình muốn coi phim gì đó gay cấn một chút, kích thích đầu óc một chút. Vì vậy mình đã tìm những bộ phim gọi là hack não, theo thông tin tìm kiếm mình đã coi được bộ phim The Sixth Sense (1999).

Bộ phim tuy gọi là phim hack não, nhưng tình tiết của nó khá là nhẹ nhàng, vừa phải pha với chút yếu tố hù nhẹ làm cho giật mình. Và điều thú vị ở cái kết khiến mình nổi da gà, vỡ òa ra lúc bỗng dưng khám phá ra nó (Chắc coi phim hack não nào cũng vậy).

Vì vậy, sau khi coi xong mình phải ghi liền ra đây, để sau này còn nhớ tên phim mà coi lại. (Mình cũng coi nhiều phim thú vị rồi, nhưng không lưu lại vào đâu cả, thành ra coi xong không nhớ tên phim, đây là bộ phim đầu tiên mình lưu lại ở đây và có thể tiếp tục có những bộ phim khác nữa trong tương lai.)


Tạm dừng cày game - Lần nỗ lực thứ 4

Mấy bữa nay dịch dã, ở nhà sinh rãnh rỗi. Mình lại cày game. Nghe chừng cũng rất bình thường và hợp lý. Nhưng khổ nỗi cái game này nó có chế độ cày rank. Gặp tính mình càng cày càng hăng. Game nó cũng biết trêu ngươi mình, lúc cho thắng, lúc cho thua nên cứ càng cố cày. Thức đêm thức khuya rồi dậy sớm cày một lúc liên tù tì mấy trận, phải cố lắm mới dừng được.

Nhiều lần trong quá khứ đã tuyên bố bỏ game rồi, bỏ vì nó quá mất thời gian, bỏ vì ngồi chơi con nó thấy thì không tốt cho cả con lẫn mình, bỏ vì mình mà chơi thì rất dễ nghiện. Bằng chứng mấy lần bỏ xong chơi thử một ván là nghiện lại.

Nên khi mình nói bỏ, vợ con bạn bè chẳng ai tin nữa, thành ra bây giờ không bỏ nữa, chỉ là TẠM DỪNG một thời gian, khi nào thích hợp sẽ quay lại nếu còn muốn. Tuyên bố như vậy, mình cũng đỡ cảm thấy áp lực hơn, thoải mái hơn, không bị nặng nề tâm lý :D Chứ cứ BỎ BỎ, rồi nghĩ mãi về việc đó có khi ham chơi lại như mấy lần trước cũng nên.

Thời gian dành cho game trước kia giờ dành cho con cái, cho bản thân nó sẽ có ích hơn.

Thật ra chơi game nó chẳng có gì sai cả, cái sai của minh ở đây là mình quá dễ bị nghiện, vì vậy dừng lại là tốt nhất, tự nhủ sẽ không động đến nó trong một khoảng thời gian tới. Nếu được thì hết năm này và hy vọng rằng trong thời gian mình dừng chơi game, sẽ có những thói quen tốt khác giúp mình quên đi được nó luôn.

Để coi lần này quyết tâm của mình có thể đến đâu.

unsplash.com


Download file bằng Restangular và FileSaver

Mình cần viết chức năng download có API đã được xây dựng trước để tải file bằng phương thức POST. Ở client mình dùng Restangular. Như các bạn biết thì dùng Restangular ta chỉ có thể đọc được dữ liệu chứ không lưu nó thành dạng file được. Sau một hồi tìm kiếm, mình tìm được thư viện FileSaver.js giúp ta lưu file từ javascript.

Đây là kết quả trả về từ server khi ta gọi API:

1
2
3
4
5
6
7
8
9
10
11
12
POST /api/download


Request Headers:
----------------

Authorization: Bearer .... (Server của mình yêu cầu token này để xác thực user)

Response Header:
----------------
Content-Type: application/vnd.ms-excel
Content-Disposition: attachement; filename=report.xls

Đây là đoạn code mình xử lý để gọi đến API và lưu data trả về thành file trên máy tính:

1
2
3
4
5
6
7
8
9
10
11
12
var DownloadRestangular = Restangular.withConfig(function(RestangularConfigurer) {
RestangularConfigurer.setFullResponse(true);
});

DownloadRestangular.all(url)
.withHttpConfig({responseType: 'arraybuffer'})
.post(postValue, params)
.then(function(res) {
var filename = res.headers('Content-Disposition').match(/filename=(.*)/)[1];
var file = new Blob([res.data], { type: res.headers('Content-Type') });
saveAs(file, filename);
});

Trước tiên, ta cần cài đặt setFullResponse cho Restangular để lấy được thông tin headers từ đó ta mới có file typefile name.

Sau đó ta cần response trả về kiểu arraybuffer như vậy ta mới dùng được với thư viện FileSaver.js.

Cuối cùng là chuyển dữ liệu trả về sang Blob và lưu lại bằng hàm saveAs của FileSaver.


Kỷ luật là tự do

Như vậy là sau khoảng 2 tháng rưỡi tham gia khóa học Machine Learning trên Coursera, ngay tối ngày hôm qua, mình đã hoàn thành xong khóa học và nhận được chứng chỉ. Đây chỉ là chứng chỉ để ghi nhận rằng mình đã hoàn thành hết khóa học, coi hết videos, làm hết các bài quiz, và hoàn thành hết các bài tập code, chứ không phải ghi nhận rằng mình đã nắm vững kiến thức về machine learning, bởi vì muốn nắm vững còn phải làm nhiều và tìm hiểu nhiều.

Tuy nhiên, cảm giác khi thấy thông báo chúc mừng hiện lên, được nghe những lời tổng kết của thầy Andrew Ng, thấy háo hứng, thú vị và phấn khích. Bởi vì đây là lần đầu sau bao lâu mình mới hoàn thành một điều gì đó khi đã theo đuổi nó trong một thời gian dài.

Tại sao lại như vậy?

Đây là những khóa học mình đã đăng ký tham gia trước đó.

courses

Cả 10 khóa mà chẳng hoàn thành được một khóa nào, khóa cao nhất chỉ hoàn thành được gần 50%. Đó là do cái tính của mình, cái tính khi bắt đầu thì rất hứng thú, nhưng dần dần lại lười đi. Nên có nhiều dự định, cứ bắt đầu rồi âm thầm kết thúc. Để rồi, một thời gian sau nhìn lại mình lại cảm thấy tiếc, thấy bức rứt, thấy xấu hổ với bản thân vì đã không theo đuổi được đến cùng (theo như cái bài nào đó mình mới đọc, thì đó là bản thân mình đã trở thành nô lệ của lười nhác, khi phải gánh chịu những cảm xúc tiêu cực về bản thân). Không biết bạn nào đã từng có cảm giác như mình không.

Đến với khóa học Machine Learning lần này, mình đã áp dụng một phương pháp, để đưa bản thân vào khuôn khổ hơn (ít nhất là với khóa học này). Mình in ra một tờ lịch năm trên tờ giấy A4 để đánh dấu lại những ngày nào mình học, ngày nào không học, cứ mỗi tối mình kiểm tra lại và cập nhật lại tờ lịch.

Đây là, những ngày học và không học của mình:

Lich 1

Lich 2

Mỗi lần nhìn lên tờ lịch này, mình sẽ biết được mình đã học ngày nào, đã bỏ ngày nào và quan trong nhất nhìn những ngày bị đánh dấu [X] cái cảm giác nó khó chịu lắm. Vì thế mình càng hạn chế dấu X càng tốt.

Một cái nữa, mình dán tờ lịch ngay chỗ làm nên ngày nào nó cũng đập vào mắt mình, nhắc nhở mình, cho nên nhiều khi đi nhậu về, hơi mệt mệt định nghỉ rồi mà nghĩ đến phải đánh dấu X vào ngày đó cũng không đành, nên cố gắng ngồi học một chút cho đúng tiến độ, mặc dù ngày hôm sau vẫn phải coi lại bài đã qua. Nhưng như vậy nó cũng có tác dụng thúc ép mình phải tiếp tục ngay cả khi cảm thấy không hứng thú, cho đến khi nào hoàn thành thì thôi.

Và đây là kết quả của mình sau bao nhiêu cố gắng chiến đấu với bệnh lười của bản thân để thỏa mãn ham muốn tìm hiểu của mình.

Coursera-ML

Một cảm giác thật tuyệt!


Những chức năng mới của ES6

Phiên bản mới của Javascript đã ra đời được một thời gian rồi, mình cũng có làm qua nhưng chưa thực sự chú ý nhiều, chủ yếu vẫn viết theo kiểu cũ. Nay mình mới đọc lại một số tài liệu, hướng dẫn và tống hợp lại những chức năng thú vị của ES6.

Template string

Với chức năng này ta có thể tạo một bản mẫu cho chuỗi cho phép ta nhúng các biểu thức vào, và cũng có thể viết trên nhiều dòng. Chú ý là ta sẽ dùng dấu ` chứ không phải dấu ‘, dấu này ở ngay dưới phím Esc trên bàn phím.

Cách dùng

1
2
3
4
var country = 'vietnam';
var str = `Xin chao ${country}
phep tinh 1 + 2 = ${1+2}`;
console.log(str);

Kết quả

1
2
Xin chao vietnam
phep tinh 1 + 2 = 3

Destructuring assignment (Tách và gán)

Tách và gán là mình tự dịch ra thôi, chức năng này cho phép ta trích xuất dữ liệu từ mảng hoặc đối tượng gán vào các biến riêng lẽ.

Cách dùng

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var arr = [1, 2, 3];
var [one, two, three] = arr;
console.log('one is', one); // => one is 1
console.log('two is', two); // => two is 2
console.log('three is', three); // => three is 3

// Lấy 1 phần của mảng
var [a, ...rest] = arr;
console.log(a); // => 1
console.log(rest); // => [2,3]

var obj = {name: 'thach', age: 27};
var {name, age} = obj;
console.log('name is', name); // => name is thach
console.log('age is', age); // => age is 27

Lấy kết quả trả về từ hàm

1
2
3
4
5
6
function getTop2() {
return ['hai', 'ha'];
}
var [p1, p2] = getTop2();
console.log(p1); // hai
console.log(p2); // ha

Gán cho một biến khác tên với thuộc tính của đổi tượng

1
2
3
var obj = {name: 'thach', age: 27};
var {name: n, age: a} = obj;
console.log(n, a); // thach 27

Block scope với let

let cho phép ta tạo ra một biến được giới hạn trong phạm vi của block chứa nó. let khác với var ở chỗ, var tạo ra một biến có phạm vi toàn cục hoặc xuyên suốt một hàm. Để rõ hơn thì mình coi qua ví dụ so sánh giữa letvar.

1
2
3
4
5
6
7
8
9
10
if (true) {
// Đây là 1 block của if
var a = 'foo';
let b = 'bar';
console.log(a); // foo
console.log(b); // bar
}

console.log(a); // foo
console.log(b); // Error: Uncaught ReferenceError: b is not defined

Như ta thấy ở ví dụ trên, biến b chỉ có thể dùng trong if-block mà không thể dùng bên ngoài được. Bây giờ ta tiếp tục ví dụ với hàm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function varFunc() {
var x = 1;
if (true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
}

function letFunc() {
let y = 1;
if (true) {
let y = 2;
console.log(y); // 2
}
console.log(y); // 1
}

varFunc();
letFunc();

Khi ta let y = 2 bên trong if-block nó tạo ra một biến y mới không liên quan gì đến let y = 1 ở trên cả. cho nên sau if-block, y bên ngoài không bị thay đổi.

Dùng let với bất đồng bộ

Hãy xem ví dụ sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for (var i = 0; i < 3; i ++) {
setTimeout(function() {
console.log('var', i);
});
}

// var 3
// var 3
// var 3

for (let i = 0; i < 3; i ++) {
setTimeout(function() {
console.log('var', i);
});
}

// var 0
// var 1
// var 2

Nếu ta dùng var ở trên, sau khi 3 vòng lặp thực hiện xong, 3 dòng console.log bên trong setTimeout sẽ được thực thi, khi đó in ra giá trị i lúc này đã là 3 rồi, cho nên ta có 3 nội dung var 3 giống nhau.

Tuy nhiên nếu dùng let như ở dưới, mỗi vòng lặp tạo ra một biến i không liên quan gì đến nhau, cho nên ta có 3 nội dung in ra khác nhau.

Vì vậy, ta thấy dùng let sẽ giúp cho code rõ ràng hơn trong trường hợp này, tránh phải sai lầm không mong muốn.

Const

Coi về let rồi thì tranh thủ coi về const 1 chút luôn. const giúp ta định nghĩa một biến với giá trị không thể thay đổi.

1
2
const a = 'foo';
a = 'bar'; // Error: Uncaught TypeError: Assignment to constant variable.

Class

Khi trước để tạo một giả class trong js ta sẽ dùng function, như thế này:

1
2
3
4
5
6
7
8
9
10
function Person() {
// ....
}

Person.prototype.hello = function() {
console.log('hello');
}

var p1 = new Person();
p1.hello(); // hello

Nay với ES6, ta có class, giúp ta có thể tạo lớp, đối tượng, làm việc với kế thừa một cách đơn giản hơn.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person {
constructor (name) {
this.name = name;
}

speak() {
console.log('My name is', this.name);
}

// static method có thể được gọi mà không cần đến đối tượng của class
static sayHello() {
console.log('Hello');
}
}

var p1 = new Person('Viet');
p1.speak(); // My name is Viet

Person.sayHello(); // Hello

Tạo một class con với extends

Để tạo một class con của một class ta dùng extends.

1
2
3
4
5
6
7
8
class Teacher extends Person {
speak() {
console.log('My name is', this.name, 'I am a teacher');
}
}

var p2 = new Teacher('Hai');
p2.speak(); // My name is Hai I am a teacher

Nếu trong lớp con có constructor thì ta phải gọi phương thức super() trước khi sử dụng this.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student extends Person {
constructor(name, school) {
super(name);
this.school = school;
}

speak() {
console.log('My name is', this.name, 'I am studying in', this.school);
}
}

var p3 = new Student('Minh', 'ST');
p3.speak(); // My name is Minh I am studying in ST

Arrow functions

Một cách viết hàm mới, ngắn gọn hơn.

Dưới đây là ví dụ so sánh giữa cách viết cũ và mới.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ES5
[1,2,3].map(function (num) { return num * 2; })
// => [2, 4, 6]

// ES6
[1,2,3].map((num) => { return num * 2; })
// => [2, 4, 6]

// Vì chỉ có 1 tham số num nên ta có thể bỏ dấu ngoặc đơn luôn
[1,2,3].map(num => { return num * 2; })
// => [2, 4, 6]

// Nhưng ở đây cũng chỉ có mỗi lệnh return nên ta có thể bỏ luôn dấu ngoặc nhọn và return
[1,2,3].map(num => num * 2)
// => [2, 4, 6]

Nếu như hàm có nhiều tham số, và có nhiều dòng lệnh hơn thì ta viết đầy đủ thế này:

1
2
3
4
5
6
7
8
[1,2,3].map((num, index) => {
console.log(index);
return num * 2;
});
// 0
// 1
// 2
// => [2, 4, 6]

Trả về một object

Chú ý nếu muốn trả về một object ta không chỉ đơn giản dùng { key: value } được.

1
2
3
4
5
var func1 = () => { name: 'saysua' };
func1(); // undefined

var func2 = () => { name: 'saysua', age: 3 };
func2(); // Error: Uncaught SyntaxError

Lỗi ở đây là do, ở giữa cặp dấu ngoặc nhọn {} code sẽ được hiểu là một chuỗi các câu lệnh. Như ở func1, name được hiểu là 1 label chứ không phải là một key của object. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label)

Ta viết lại cho đúng như sau:

1
2
3
4
5
var func1 = () => ({ name: 'saysua' });
func1(); // => Object {name: "saysua"}

var func2 = () => ({ name: 'saysua', age: 3 });
func2(); // => Object {name: "saysua", age: 3}

Arrow function không tự động bind this

Nếu ở ES5 ta tạo một hàm mới, nó sẽ luôn tự tạo ra một giá trị this vì vậy code dưới đây sẽ chạy bị sai.

1
2
3
4
5
6
7
8
9
function Runner() {
this.count = 1;
setTimeout(function() {
this.count ++; // this ở đây không phải là this ở trên nên this.count không tồn tại
console.log(this.count); // NaN
}, 100);
}

var r = new Runner();

Ta sẽ thường xử lý bằng cách gán một biến that = this hoặc là bind(this) vào hàm bên trong.

1
2
3
4
5
6
7
8
9
10
11
function Runner() {
var that = this;

this.count = 1;
setTimeout(function() {
that.count ++;
console.log(that.count); // 2
}, 100);
}

var r = new Runner();

Còn arrow function không tự động tạo giá trị this nên đoạn code sau sẽ chạy đúng như ta mong muốn.

1
2
3
4
5
6
7
8
9
function Runner() { 
this.count = 1;
setTimeout(() => {
this.count ++;
console.log(this.count); // 2
}, 100);
}

var r = new Runner();

Tuy nhiên, chính vì đặc tính này mà bạn cần phải chú ý khi sử dụng arrow function trong một số trường hợp, ví dụ:

1
2
3
4
5
6
7
8
9
10
var sum = {
a: 1,
b: 2,
run: () => {
console.log(this === window); // => true (this không phải là sum)
return this.a + this.b; // NaN (nên this.a và this.b không có)
}
};

sum.run();

Tổng kết

Mình thấy những tính năng mới của ES6 rất thú vị, giúp viết code nhanh và vui hơn, vẫn còn nhiều tính năng mới nữa nhưng mình chưa tìm hiểu hết được. Tuy nhiên một vài trường hợp cần phải sử dụng cẩn thận, kẻo nhanh quá lại hóa sai, không kiểm soát được các giá trị. Happy codding!


Lưu log của nginx vào elastic search bằng logstash

Thông thường, mỗi truy cập vào nginx đều được lưu vào file log, ví dụ /var/log/nginx/access.log. Tại đây, ta có thể coi các thông tin về truy cập như thời gian, đường dẫn, trình duyệt của người dùng.

Nhưng nếu ta cần có thống kê chi tiết hơn về các truy cập này, như số lượt truy cập trong ngày, phân loại người dùng … thì file log này là chưa đủ. Cho nên, ta có thể đẩy những log này lên elastic search rồi từ đó dùng các công cụ thích hợp để phân tích.

READ MORE


Chạy Visual Studio Solution từ command line

Đôi khi ta muốn chạy một solution của Visual Studio từ command line thay vì phải mở Visual Studio IDE lên để giảm bớt tài nguyên cho hệ thống, ta có thể làm như sau:

  • Di chuyển đến thư mục chứa file .sln
  • Build code "C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe" SelfHost.sln /p:Configuration=Release (Hoặc là Debug)
  • Chạy file đã build SelfHost\bin\Release\SelfHost.exe

Để thuận tiện cho những lần chạy sau, ta có thể tạo một file bat, khi nào cần chỉ cần click một phát là xong.


Tôi học Machine Learning - 004 - Unsupervised Learning - Học không có giám sát

Bài ghi chú

Với học không có giám sát, chúng ta biết được một ít không không có ý tưởng về kết quả sẽ như thế nào. Chúng ta được đưa cho dữ liệu và yêu cầu trả về cấu trúc của dữ liệu đó dựa vào mối quan hệ giữa các biến trong dữ liệu.

Ví dụ:

  • Dựa vào dữ liệu về khách hàng của một công ty, chúng ta phân nhóm khách hàng để có thể thực hiện các chiến dịch bán hàng đặc biệt.
  • Phân loại các nhóm thành viên trên mạng xã hội.
  • Trong một bữa tiệc, ta có tập ghi âm thanh, ta có thể phân tích và tách các tạp âm để lọc ra âm thanh riêng của từng người.

Tôi học Machine Learning - 003 - Supervised Learning - Học có giám sát

Bài ghi chú

Với học có giám sát (Supervised Learning), chúng ta được đưa một dữ liệu với kết quả đầu ra tương ứng đã biết trước, ta cần xây dựng mối quan hệ dữa đầu vào và đầu ra, để dự đoán kết quả đầu ra của các giá trị đầu vào khác.

Ví dụ, dự đoán giá nhà dựa vào vị trí, kích thước của căn nhà.

Học có giám sát được chia ra làm hai loại, regression (hồi quy)classification (phân lớp).

  • Loại hồi quy: ta cố gắng dự đoán kết quả dưới dạng liên tục.
  • Loại phân lớp: ta cố gắng dự đoán kết quả dưới dạng rời rạc.

Ví dụ:

  • Loại hồi quy:
    • Cho kết quả kiểm tra đầu vào một lớp học, dự đoán số học sinh lên lớp.
    • Dựa vào kích thước, màu sắc của quả dưa leo, dự đoán giá bán sản phẩm.
  • Loại phân lớp:
    • Dựa vào kích thước, màu sắc của quả dưa leo, dự đoán có bán được hay không?
    • Cho thông tin khách hàng, dự đoán khách hàng mua sản phẩm hay không?