Hexa's Blog

CSGO, Thiết lập để tập ném smoke

09/01/2020 CSGO

sv_cheats 1;
sv_infinite_ammo 1;
ammo_grenade_limit_total 5;
mp_warmup_end;
mp_freezetime 0;
mp_roundtime 60;
mp_roundtime_defuse 60;
sv_grenade_trajectory 1;
sv_grenade_trajectory_time 10;
sv_showimpacts 1;
mp_limitteams 0;
mp_autoteambalance 0;
mp_maxmoney 60000;
mp_startmoney 60000;
mp_buytime 9999;
mp_buy_anywhere 1;
mp_restartgame 1;
bot_kick;
bot_stop;
bind "ALT" "noclip";
bind "i" "bot_place";
alias +jumpthrow "+jump;-attack"; alias -jumpthrow "-jump"; bind mouse5 +jumpthrow;

CSGO, Thiết lập crosshair

09/01/2020 CSGO

cl_crosshair_drawoutline "0"
cl_crosshair_dynamic_maxdist_splitratio "0.35"
cl_crosshair_dynamic_splitalpha_innermod "1"
cl_crosshair_dynamic_splitalpha_outermod "0.5"
cl_crosshair_dynamic_splitdist "7"
cl_crosshair_friendly_warning "1"
cl_crosshair_outlinethickness "0.5"
cl_crosshair_sniper_show_normal_inaccuracy "0"
cl_crosshair_sniper_width "1"
cl_crosshair_t "0"
cl_crosshairalpha "250.000000"
cl_crosshaircolor "5"
cl_crosshaircolor_b "0"
cl_crosshaircolor_g "0"
cl_crosshaircolor_r "255"
cl_crosshairdot "0"
cl_crosshairgap "-2.500000"
cl_crosshairgap_useweaponvalue "0"
cl_crosshairscale "0"
cl_crosshairsize "3.000000"
cl_crosshairstyle "4"
cl_crosshairthickness "1.150000"
cl_crosshairusealpha "1"
cl_fixedcrosshairgap "3"

Rebase hay Merge Khi muốn có thay đổi từ nhánh Master

23/11/2019 Git

I. Giới Thiệu

Khi phát triển phần mềm việc chia nhánh để phát triển độc lập, song song luôn xảy ra. Có nhánh xong trước, có nhánh sẽ hoàn thành sau. Làm sau để các nhánh chưa hoàn thành có thể có những tính năng từ nhánh chính (nhánh master) là vấn đề của bài viết này.

Kịch bản cụ thể như sau. Có 2 tính năng phát triển độc lập với nhau, theo lẽ đương nhiên, lập trình viên sẽ tạo ra 2 nhánh riêng biệt từ nhánh master. Hai nhánh này sẽ có tên lần lượt là

  • feature-1
  • feature-2
[1] Nhánh feature-1 và feature-2
[1] Nhánh feature-1 và feature-2

Nhánh feature-1 hoàn thành sớm và nhanh chóng merge vào master. Lúc này nhánh master đang có mã nguồn mới nhất từ nhánh feature-1. Vấn đề bây giờ đó là ở nhánh feature-2, nhánh feature-2 hiện tại chưa phát triển xong, tuy nhiên nhánh feature-2 muốn có các tính năng mới nhất mà hiện tại đang có ở nhánh master.

[2] Nhánh feature-1 merge vào nhánh master, và tạo ra node màu xanh dương.
[2] Nhánh feature-1 merge vào nhánh master, và tạo ra node màu xanh dương.

Sẽ có 2 cách làm trong kịch bản này:

  • Merge từ nhánh master qua nhánh feature-2
  • Rebase nhánh feature-2 đến nhánh master

Rebase dịch sang tiếng việt có nghĩa là chuyển nền, còn có thể hiểu cách khác là chuyển commit nguồn của một nhánh sang một commit khác.

Lưu ý là nhánh master đang nói ở đây cụ thể là điểm commit mới nhất, cuối cùng trên nhánh master.

Một lần nữa, vấn đề hiện tại đó là làm sao để nhánh feature-2 có các tính năng mới nhất từ nhánh master và rồi lập trình viên có thể phát triển tiếp trên nhánh feature-2.

II. Giải pháp

1. Merge từ nhánh master qua nhánh feature-2

[3] Merge từ nhánh master qua nhánh feature-2
[3] Merge từ nhánh master qua nhánh feature-2

2. Rebase nhánh feature-2 qua nhánh master

[4] Rebase nhánh feature-2 đến commit mới nhất của nhánh master
[4] Rebase nhánh feature-2 đến commit mới nhất của nhánh master

Có thể nhận ra điểm khác biệt ngay lập tức đó là nhánh feature-2 được phát triển dựa vào commit màu xanh dương thay vì là màu xanh lá.

III. Ưu & Nhược Điểm.

1. Merge từ nhánh master qua nhánh feature-2

Ưu điểm: Nhìn rõ các commit lịch sử của nhánh feature-2, từng commit lúc này hoàn toàn ko có dính dáng gì đến commit mới nhất thuộc nhánh master2. Khi áp dụng giải pháp này, giả sử muốn quay lại các commit cũ thuộc nhánh feature-2, hoàn toàn là điểu dễ dàng, mã nguồn hoàn toàn không dính dáng gì đến nhánh feature-1 hết.

Nhược điểm: Git log nhìn sẽ rất xấu.

[5] git log khi áp dụng phương pháp merge
[5] git log khi áp dụng phương pháp merge

2. Rebase nhánh feature-2 sang commit mới nhất thuộc nhánh master

Ưu điểm: Git log nhìn sẽ cực kì, cực kì đẹp.

[6] git log khi áp dụng phương pháp rebase
[6] git log khi áp dụng phương pháp rebase

Nhược điểm: Các commit cũ của nhánh feature-2 lúc nhánh này dựa trên commit cũ thuộc nhánh master sẽ bị biến mất trên git log. Thay vào đó, các commit thuộc nhánh feature-2 sẽ hoàn toàn dựa trên commit mới nhất thuộc nhánh master. Giả sử như muốn quay lại các commit cũ, mã nguồn không dính dáng gì đến mã nguồn của feature-1, để làm được việc này khó khăn hơn rất nhiều so với phương pháp merge.

Trên hình số [5] và [6], hãy chú ý đến các commits thuộc nhánh feature-2.
- [feature-2] change 1
- [feature-2] change 2
- [feature-3] change 3

Sau khi áp dụng phương pháp rebase, commit hash của các commits thuộc nhánh `feature-2` đã thay
đổi hoàn toàn. Ví dụ như commit có tên là: `[feature-2] change 3`

Commit hash đã thay đổi từ `2eea38a` sang `5c59d21`.

Hãy thử tưởng tượng xem nếu cần debug trong nhánh `feature-2` và áp dụng phương pháp `rebase`,
lập trình viên sẽ gặp khó khăn trong việc quay lại commit cũ của mình trước khi `rebase`.
Thêm vào đó, lúc tranh luận **LỖI CỦA ANH - LỖI CỦA TÔI**, cũng sẽ thêm ít nhiều vấn đề.

Để áp dụng phương pháp `rebase`, lập trình viên thật sự cần biết là anh ta đang làm gì và
chịu trách nhiệm cho nó.

3. Tóm tắt

|------------+---------------------------------------+----------------------------------------|
|            | Merge                                 | Rebase                                 |
|------------+---------------------------------------+----------------------------------------|
| Ưu Điểm    | Nhìn rõ các commit lịch sử của nhánh  | Trên git log nhìn cực kì đẹp.          |
|            | feature-2, từng commit lúc này hoàn   | Các branch không bị lộn xộn,           |
|            | toàn ko có dính dáng gì đến commit    | chồng chéo nhau                        |
|            | mới nhất thuộc nhánh master           |                                        |
|------------+---------------------------------------+----------------------------------------|
| Nhược Điểm | Trên git log nhìn rất xấu. Các branch | Các commit cũ của nhánh `feature-2`    |
|            | bị chồng chéo.                        | lúc nhánh này dựa trên commit cũ       |
|            |                                       | thuộc nhánh master sẽ bị biến mất.     |
|            |                                       | Thay vào đó, các commit thuộc nhánh    |
|            |                                       | feature-2 sẽ hoàn toàn dựa trên commit |
|            |                                       | mới nhất thuộc nhánh master            |
|------------+---------------------------------------+----------------------------------------|

Tổng hợp các loại merge

23/11/2019 Git

1. Giới thiệu

Khi merge hai branch với nhau, có những kiểu merge như sau

  • no fast forward: không chuyển tiếp nhanh
  • fast forward: chuyển tiếp nhanh
  • squash: nén 🏋️

2. Chi tiết từng loại merge

a. No Fast Forward (–no-ff)

Khi merge ở chế độ no fast forward, một commit merge sẽ được tạo ra trên git log cho dù khi merge có xảy ra conflict hay không. Đây là sở đồ khối khi áp dụng cách merge no fast forward

[1] No Fast Forward Merge
[1] No Fast Forward Merge

Lưu ý là sự khác nhau giữa các loại merge là ở commit merge cuối cùng (màu hồng) Như ở trên sơ đồ khối, sự thay đổi của của nhánh(branch) tồn tại ở trên (B1, B2, B3), điểm cuối cùng (màu hồng) thực chất không có chứa thay đổi gì cả, ngoài trừ việc lưu ý rằng đây là commit merge từ nhánh có tên là branch vào nhánh master.

b. Fast Forward (–ff-only)

Khi merge ở chế độ fast forward, các commit từ nhánh mới sẽ chuyển tiếp qua nhánh đích và không có merge commit được tạo ra. Đây là sơ đồ khối các branch trước khi merge, không có commit màu hồng như đồ thị dành cho --no-fast-forward

[2] Before Fast Forward Merge
[2] Before Fast Forward Merge

Và đây là sơ đồ khối sau khi merge từ nhánh branch qua master

[3] After Fast Forward Merge
[3] After Fast Forward Merge

Như trong hình vẽ, nếu áp dụng fast forward, hoàn toàn không có merge commit như là no fast forward

c. Squash (–squash)

Squash có nghĩa là đè nén. Khi merge theo kiểu squash tất cả các commit thuộc nhánh sẽ bị nén với nhau lại sau đó merge vào nhánh đích. Đây là sơ đồ khối trước khi áp dụng merge squash (nó giống như là hình trước khi merge theo kiểu fast forward merge.

[4] Before Squash Merge
[4] Before Squash Merge

Còn đây là sơ đồ khối sau khi merge theo kiểu squash.

[5] After Squash Merge
[5] After Squash Merge

Như trong sơ đồ khối trên, sau khi merge theo kiểu squash, tất cả thay đổi trong các commit (B1, B2, B3) đều được nén lại thành một commit duy nhất (màu hồng). Khi mở git log của master, người xem sẽ chỉ thấy có commit đã nén mà ko thấy các commit (B1, B2, B3).

3. Ưu điểm và nhược điểm

a. Fast Forward

Ưu Điểm: Khi nhìn vào git log ở nhánh bị merge vào, người xem sẽ thấy toàn bộ các commit ở trên nhánh gốc. Thêm vào đó, ở trên git log chúng ta sẽ thấy một đường thẳng. Việc sử dụng fast forward cực kì có ích khi ở trên branch bị merge, không có tồn tại thêm các commit mới, lúc này áp dụng fast forward dòng git log là một đường thẳng. Nhược Điểm: Khi áp dụng cách này, khi muốn biết là cái commit được tạo ra trên branch nào, khi này sẽ gặp khó khăn khi nhìn trên git log. Đây là hình ảnh lấy ra từ git log --graph khi áp dụng git merge --fast-forward

[6] git merge fast forward
[6] git merge fast forward

b. No Fast Forward

Ưu Điểm: Cũng giống như là fast forward, người xem sẽ thấy toàn bộ commit của branch nhánh khi học xem git log. Thêm vào đó, người dùng còn biết được chính xác là commit được phát triển trên nhánh nào. Ưu điểm cuối cùng là khi nhìn git log --graph đẹp. Đây là hình ảnh ví dụ khi áp dụng git merge --no-ff.

[7] git merge no fast forward
[7] git merge no fast forward

Nhược Điểm: Giả sử với một người phát triển phần mềm và commit liên tục, một chuỗi các commit nhỏ nhỏ xuất hiện trên git log kết quả là nhìn rất rất là không đẹp, những commit nhỏ nhỏ đó nên được nhóm lại thành một commit.

c. Squash

Ưu Điểm: Khi nhìn vào git log, sẽ thấy git log cực kì sạch sẽ. Khi phát triển phần mềm, luôn luôn tồn tại những commit có message ít ý nghĩa, khi nhìn vào git log và đọc git message, thấy rất có vấn đề. Đặc biệt là những lập trình viên code và commit liên tục.

Nhược điểm: Cực kì sạch sẽ quá cũng là vấn đề. Giả sử đó là một chuỗi commit, khi tìm cách debug theo brach ví dụ sử dụng git bisect , nhìn một cái commit đơn độc cũng khá là mệt.

Free Image Sharing project

10/06/2017 Projects

Introduction

Sometime in my life, I want to share something stupid anonymously, somewhere to store data anonymously. Imgur is good, but I am not that bad to abuse the Imgur, last year, they close the api to share image anonymously and I dont want to do some shit crawling stuffs or playing around with their website.I write my own image data storage. The project written in elixir with phoenix web framework supporting and foundation. You can access the projet at http://image.hexalink.xyz

This small web application which helps you to share your images easily and quickly. Those uploading images might be stored on the system until my server storage getting full. If the server’s full, images will be removed to save space.

Current Features

  • Uploading image

Next Features

  • User can set time to live for image

SQL self join table and explaination to find min/max values

08/06/2017 SQL

Introduction

It’s general and popular to find min/max value of a column in tables with aggregate functions such as min and max. However, I would like to use vanila way to solve this problem, in addition to explain how does it work with join. The explaination can help you get a abstract of join and how does it work in processing.

Issue

To help you understand how join can help you approach min and max, we need a good example. Now let start. We got alot of people in a company, each of them has more then one assessment during their work time. The question is how to get the latest, newest assessment and the first, oldest assessment. The big question is how to get the latest and the first assessment answers filter by that person and assessment, remember that an assessment can be done many times. Our table will look like:

table named: assessment_answers;
|-------------+-----------+---------------+--------------------+-------------|
| id          | person_id | assessment_id | assessment_answers | inserted_at |
|-------------+-----------+---------------+--------------------+-------------|
| integer, fk | int       | int           | jsonb              | datetime    |
|-------------+-----------+---------------+--------------------+-------------|

Thinking approach

To find min/max value of inserted_at value filtered by the person_id and assessment_id, first we need to find all record filtered by person_id and assessment_id, then we must find a min/value of inserted_at via a loop to comparing one to others inserted_at siblings, one which is smaller than others is the smallest and one which is greater than all others is the greatest. This also can be understand in this way.

  1. If you can find a group named A from a fixed set filtered by some conditions, all elements in this group A can find a greater element from a fix set. On the other hands, other elements which does not belong to the group A cannot find any element which is greater than itself, which also means that those other element are the greatest.
  2. If you can find a group named B from a fixed set filtered by some conditions, all elemments in this group B can find a smaller element from a fix set. On the other hands, other elements which does not belong to the group B cannot find any element which is smaller than itself, which also mean that those elements are the smallest.

Solution

I would like to find the latest/newest assessments of all people. Let do it step by step and analyze:

The over all data set of a person who own id is 1. As you can see, for a single person, there are many assessments has been done by him/her. We have to find out the latest assessment answers of each assessment id. For example: assessment answers with id: 1, 7, 8, 9; the person has finished this assessment_id 2 four times.

select id, person_id, assessment_id, inserted_at from assessment_answers where person_id = 1;

 id | person_id | assessment_id |       inserted_at
----+-----------+---------------+-------------------------
  1 |         1 |             2 | 2016-12-14 04:04:46.477     x
  2 |         1 |             3 | 2016-12-14 04:07:11.96
  3 |         1 |             8 | 2016-12-14 04:07:12.74
  4 |         1 |             5 | 2016-12-14 04:07:13.177
  5 |         1 |             1 | 2016-12-14 04:07:14.053
  6 |         1 |             7 | 2016-12-14 04:07:14.427
  7 |         1 |             2 | 2016-12-16 01:19:25.61      x
  8 |         1 |             2 | 2017-02-24 22:13:12.79      x
  9 |         1 |             2 | 2017-02-25 09:48:03.53      x
 10 |         1 |             4 | 2017-02-14 00:00:00
 11 |         1 |             4 | 2017-02-22 00:00:00
 12 |         1 |             6 | 2017-02-14 00:00:00
(12 rows)

Now, let find a group of element which can find a greater one among the fixed set. The comparing value based on inserted_at column.

select aa.id, aa.person_id, aa.assessment_id, aa.inserted_at, ab.id, ab.person_id, ab.assessment_id 
from assessment_answers aa join assessment_answers ab
on aa.person_id = ab.person_id
and aa.assessment_id = ab.assessment_id
and aa.inserted_at < ab.inserted_at        -> I will explain why we set condition here not under _where_ phrase
where aa.person_id = 1
order by aa.id, ab.id;
 id | person_id | assessment_id |       inserted_at       | id | person_id | assessment_id |      inserted_at       
----+-----------+---------------+-------------------------+----+-----------+---------------+------------------------
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  7 |         1 |             2 | 2016-12-16 01:19:25.61
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  8 |         1 |             2 | 2017-02-24 22:13:12.79  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
 10 |         1 |             4 | 2017-02-14 00:00:00     | 11 |         1 |             4 | 2017-02-22 00:00:00
(7 rows)

The fixed set we are talking about is starting from id 1 -> 12, however, our group contain 1, 7, 8, 10. 1, 7, 8, 10 can find greater element for instance:

 id | person_id | assessment_id |       inserted_at       | id | person_id | assessment_id |      inserted_at       
----+-----------+---------------+-------------------------+----+-----------+---------------+------------------------
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  7 |         1 |             2 | 2016-12-16 01:19:25.61

The inserted_at(id_1) is smaller than inserted_at(id_7). For those elements which does not belong to this group cannot find greater element, because they are greatest ones. The other elements should include 2, 3, 4, 5, 6, 9, 11, 12. The previous query used join phrase as a consequence, it remove all unsatisfied element for condition aa.insrted_at < ab.inserted_at. On the other hands, left join takes satisfied and unsatisfied records.

select aa.id, aa.person_id, aa.assessment_id, aa.inserted_at, ab.id, ab.person_id, ab.assessment_id, ab.inserted_at from assessment_answers aa
left join assessment_answers ab
on aa.person_id = ab.person_id
and aa.assessment_id = ab.assessment_id
and aa.inserted_at < ab.inserted_at
where aa.person_id = 1
order by aa.id, ab.id;
 id | person_id | assessment_id |       inserted_at       | id | person_id | assessment_id |      inserted_at       
----+-----------+---------------+-------------------------+----+-----------+---------------+------------------------
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  7 |         1 |             2 | 2016-12-16 01:19:25.61
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  2 |         1 |             3 | 2016-12-14 04:07:11.96  |    |           |               | 
  3 |         1 |             8 | 2016-12-14 04:07:12.74  |    |           |               | 
  4 |         1 |             5 | 2016-12-14 04:07:13.177 |    |           |               | 
  5 |         1 |             1 | 2016-12-14 04:07:14.053 |    |           |               | 
  6 |         1 |             7 | 2016-12-14 04:07:14.427 |    |           |               | 
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  8 |         1 |             2 | 2017-02-24 22:13:12.79  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  9 |         1 |             2 | 2017-02-25 09:48:03.53  |    |           |               | 
 10 |         1 |             4 | 2017-02-14 00:00:00     | 11 |         1 |             4 | 2017-02-22 00:00:00
 11 |         1 |             4 | 2017-02-22 00:00:00     |    |           |               | 
 12 |         1 |             6 | 2017-02-14 00:00:00     |    |           |               | 
(15 rows)

Now let check the id of assessment answers records if the id 2, 3, 4, 5, 6, 7, 9, 11, 12 are the greatest. They cannot find any greater elements.

Let finalize our works to extract the greatest element only

select aa.id, aa.person_id, aa.assessment_id, aa.inserted_at, ab.id, ab.person_id, ab.assessment_id, ab.inserted_at from assessment_answers aa
left join assessment_answers ab
on aa.person_id = ab.person_id
and aa.assessment_id = ab.assessment_id
and aa.inserted_at < ab.inserted_at
where aa.person_id = 1
and ab.id is null
order by aa.id, ab.id;
 id | person_id | assessment_id |       inserted_at       | id | person_id | assessment_id | inserted_at 
----+-----------+---------------+-------------------------+----+-----------+---------------+-------------
  2 |         1 |             3 | 2016-12-14 04:07:11.96  |    |           |               | 
  3 |         1 |             8 | 2016-12-14 04:07:12.74  |    |           |               | 
  4 |         1 |             5 | 2016-12-14 04:07:13.177 |    |           |               | 
  5 |         1 |             1 | 2016-12-14 04:07:14.053 |    |           |               | 
  6 |         1 |             7 | 2016-12-14 04:07:14.427 |    |           |               | 
  9 |         1 |             2 | 2017-02-25 09:48:03.53  |    |           |               | 
 11 |         1 |             4 | 2017-02-22 00:00:00     |    |           |               | 
 12 |         1 |             6 | 2017-02-14 00:00:00     |    |           |               | 
(8 rows)

And for short, here it’s final shot to find the latest/newest assessment answers of user(id: 1)

select aa.id, aa.person_id, aa.assessment_id, aa.inserted_at from assessment_answers aa
left join assessment_answers ab
on aa.person_id = ab.person_id
and aa.assessment_id = ab.assessment_id
and aa.inserted_at < ab.inserted_at
where aa.person_id = 1
and ab.id is null
order by aa.id;
 id | person_id | assessment_id |       inserted_at       
----+-----------+---------------+-------------------------
  2 |         1 |             3 | 2016-12-14 04:07:11.96
  3 |         1 |             8 | 2016-12-14 04:07:12.74
  4 |         1 |             5 | 2016-12-14 04:07:13.177
  5 |         1 |             1 | 2016-12-14 04:07:14.053
  6 |         1 |             7 | 2016-12-14 04:07:14.427
  9 |         1 |             2 | 2017-02-25 09:48:03.53
 11 |         1 |             4 | 2017-02-22 00:00:00
 12 |         1 |             6 | 2017-02-14 00:00:00
(8 rows)

To find the smallest value, here is your solution:

select aa.id, aa.person_id, aa.assessment_id, aa.inserted_at from assessment_answers aa
left join assessment_answers ab
on aa.person_id = ab.person_id
and aa.assessment_id = ab.assessment_id
and aa.inserted_at > ab.inserted_at
where aa.person_id = 1
and ab.id is null
order by aa.id;
 id | person_id | assessment_id |       inserted_at       
----+-----------+---------------+-------------------------
  1 |         1 |             2 | 2016-12-14 04:04:46.477
  2 |         1 |             3 | 2016-12-14 04:07:11.96
  3 |         1 |             8 | 2016-12-14 04:07:12.74
  4 |         1 |             5 | 2016-12-14 04:07:13.177
  5 |         1 |             1 | 2016-12-14 04:07:14.053
  6 |         1 |             7 | 2016-12-14 04:07:14.427
 10 |         1 |             4 | 2017-02-14 00:00:00
 12 |         1 |             6 | 2017-02-14 00:00:00

Quesions

Q: Can we place the condition aa.inserted_at < ab.inserted_at under where phrase instead of under lelft join on phrase, and why?
A: No, if we put the condition aa.inserted_at < ab.inserted_at under the where phrase, we can only get a group of not-greatest elements

select aa.id, aa.person_id, aa.assessment_id, aa.inserted_at, ab.id, ab.person_id, ab.assessment_id, ab.inserted_at from assessment_answers aa
left join assessment_answers ab
on aa.person_id = ab.person_id
and aa.assessment_id = ab.assessment_id
where aa.person_id = 1
and aa.inserted_at < ab.inserted_at
order by aa.id, ab.id;  
 id | person_id | assessment_id |       inserted_at       | id | person_id | assessment_id |      inserted_at       
----+-----------+---------------+-------------------------+----+-----------+---------------+------------------------
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  7 |         1 |             2 | 2016-12-16 01:19:25.61
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  8 |         1 |             2 | 2017-02-24 22:13:12.79  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
 10 |         1 |             4 | 2017-02-14 00:00:00     | 11 |         1 |             4 | 2017-02-22 00:00:00
(7 rows)

Q: If I use left join in this query, why dont I get a combine of satisfied and unsatisfied records:
A: This is how the query look like and its result set.

select aa.id, aa.person_id, aa.assessment_id, aa.inserted_at, ab.id, ab.person_id, ab.assessment_id, ab.inserted_at from assessment_answers aa
left join assessment_answers ab
on aa.person_id = ab.person_id
and aa.assessment_id = ab.assessment_id
where aa.person_id = 1
order by aa.id, ab.id;    
 id | person_id | assessment_id |       inserted_at       | id | person_id | assessment_id |       inserted_at       
----+-----------+---------------+-------------------------+----+-----------+---------------+-------------------------
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  1 |         1 |             2 | 2016-12-14 04:04:46.477
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  7 |         1 |             2 | 2016-12-16 01:19:25.61
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  1 |         1 |             2 | 2016-12-14 04:04:46.477 |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  2 |         1 |             3 | 2016-12-14 04:07:11.96  |  2 |         1 |             3 | 2016-12-14 04:07:11.96
  3 |         1 |             8 | 2016-12-14 04:07:12.74  |  3 |         1 |             8 | 2016-12-14 04:07:12.74
  4 |         1 |             5 | 2016-12-14 04:07:13.177 |  4 |         1 |             5 | 2016-12-14 04:07:13.177
  5 |         1 |             1 | 2016-12-14 04:07:14.053 |  5 |         1 |             1 | 2016-12-14 04:07:14.053
  6 |         1 |             7 | 2016-12-14 04:07:14.427 |  6 |         1 |             7 | 2016-12-14 04:07:14.427
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  1 |         1 |             2 | 2016-12-14 04:04:46.477
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  7 |         1 |             2 | 2016-12-16 01:19:25.61
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  7 |         1 |             2 | 2016-12-16 01:19:25.61  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  8 |         1 |             2 | 2017-02-24 22:13:12.79  |  1 |         1 |             2 | 2016-12-14 04:04:46.477
  8 |         1 |             2 | 2017-02-24 22:13:12.79  |  7 |         1 |             2 | 2016-12-16 01:19:25.61
  8 |         1 |             2 | 2017-02-24 22:13:12.79  |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  8 |         1 |             2 | 2017-02-24 22:13:12.79  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
  9 |         1 |             2 | 2017-02-25 09:48:03.53  |  1 |         1 |             2 | 2016-12-14 04:04:46.477
  9 |         1 |             2 | 2017-02-25 09:48:03.53  |  7 |         1 |             2 | 2016-12-16 01:19:25.61
  9 |         1 |             2 | 2017-02-25 09:48:03.53  |  8 |         1 |             2 | 2017-02-24 22:13:12.79
  9 |         1 |             2 | 2017-02-25 09:48:03.53  |  9 |         1 |             2 | 2017-02-25 09:48:03.53
 10 |         1 |             4 | 2017-02-14 00:00:00     | 10 |         1 |             4 | 2017-02-14 00:00:00
 10 |         1 |             4 | 2017-02-14 00:00:00     | 11 |         1 |             4 | 2017-02-22 00:00:00
 11 |         1 |             4 | 2017-02-22 00:00:00     | 10 |         1 |             4 | 2017-02-14 00:00:00
 11 |         1 |             4 | 2017-02-22 00:00:00     | 11 |         1 |             4 | 2017-02-22 00:00:00
 12 |         1 |             6 | 2017-02-14 00:00:00     | 12 |         1 |             6 | 2017-02-14 00:00:00
(26 rows)

The condition I am talking here is aa.person_id = ab.person_id and aa.assessment_id = ab.assessment_id

  • Satisfied condition is aa.person_id == ab.person_id and aa.assessment_id == ab.assessment_id
  • Unsatisfied condition is aa.person_id != ab.person_id or aa.assessment_id != ab.assessment_id
    Why the record that are not satisfied exist in the result set. Hmm, that’s a question I am think about. Personally, I think the developers of postgres did make an exception, hardcode perhap if people use equal in the join expression.

How to install Flash for Opera manually

09/11/2016 etc

Since the documentation of Opera has been out of date, this article is all about installing flash plugin manually, I strongly believe that this can help you in any version of Opera or any operating system. In my free time, I have spent time researching on the resouce files of Opera and trace the directory that Opera use to read the flashplayer.so.

$ cat /lib64/opera-developer/resources/pepper_flash_config.json

{
  "PepperFlashPaths" : [
    "/usr/lib/adobe-flashplugin/libpepflashplayer.so",
    "/usr/lib/pepperflashplugin-nonfree/libpepflashplayer.so",
    "/usr/lib/PepperFlash/libpepflashplayer.so",
    "/usr/lib64/PepperFlash/libpepflashplayer.so",
    "/usr/lib/chromium-browser/PepperFlash/libpepflashplayer.so",
    "/usr/lib/chromium/PepperFlash/libpepflashplayer.so",
    "/usr/lib64/chromium-browser/PepperFlash/libpepflashplayer.so",
    "/usr/lib64/chromium/PepperFlash/libpepflashplayer.so",
    "/opt/google/chrome-beta/PepperFlash/libpepflashplayer.so",
    "/opt/google/chrome-unstable/PepperFlash/libpepflashplayer.so",
    "/opt/google/chrome/PepperFlash/libpepflashplayer.so"
  ]
}

As you can guess, we gonna download flash plugin from its official site then extract into any of these directory such as /usr/lib/adobe-flashplugin/. You need to extract two files including libpepflashplayer.so and manifiest.json, it’s a must to copy manifest.json along with the libpepflashplayer.so. Remember to set extracted files with appropriate permission (chmod command).

Phoenix and using multiple layouts

26/01/2016 Phoenix

1. How to specify the layout when render() in controllers

There is an option in render/3 method, source
In the below example, I did specify the layout, the layout will be located at @conn.assigns[:layout], so as :id

defmodule ImageQuickShare.ImageController do
  use ImageQuickShare.Web, :controller
  def show(conn, %{"id" => id}) do
    render(conn, "show.html", id: id,
           layout: {ImageQuickShare.ImageView, "empty_layout.html"})
  end
end

The directory which locate layout look like:

templates
├── image
│   ├── empty_layout.html.eex
│   └── show.html.eex
├── layout
│   └── app.html.eex
└── page
    └── index.html.eex

2. Setup a default layout for all method within a controller

We have to use plug :put_layout.

defmodule ImageQuickShare.ImageController do
  use ImageQuickShare.Web, :controller
  plug :put_layout, {ImageQuickShare.ImageView, "empty_layout.html"}  #<--- HERE
  
  def show(conn, %{"id" => id}) do
    render(conn, "show.html", id: id)
  end
end

3. Get advanced from PLUG.

Because of using plug, we can also specify the defaul layout in router. In route.ex we can define an extra pipeline.

pipeline :empty_layout do
  plug :put_layout, {ImageQuickShare.ImageView, "empty_layout.html"}
end

And then, within scope, add the pipeline via pipe_through. Here is an example.

scope "/", ImageQuickShare do
  pipe_through [:browser, :empty_layout] # Use the default browser stack
  get "/", PageController, :index
  get "/image", ImageController, :show
end

REFERENCE

Tweak to ssh quickly any server

25/01/2016 tweak

To ssh to server, I used to type ssh --flags, the command line too long and replication. Here is a solution reduce the pain.

Go to file ~/.ssh/config, and add the following configuration. If the file is not exist, you can make a new one.

Host server-dev1
Hostname  xxx.xxx.xxx.xxx
Port 1022
User nguyenvinhlinh

Host server-dev2
Hostname  xxx.xxx.xxx.xxx
Port 1023
User nguyenhoangson

Right after that, you can use ssh with server alias name.

$ ssh server-dev1
$ ssh server-dev2

Devise, generate hash password

04/01/2016 Ruby on Rails 4

The question is that you are using devise and you want to get hash password from raw password. Here is your solution:

password = 'the secret password'
new_hashed_password = User.new(:password => password).encrypted_password