New FAMILUG

The PyMiers

Sunday 27 December 2015

Những khái niệm khi bắt đầu "chọc" Android

Android là con robot hư hỏng, đã sản sinh vô tính và thống trị thế giới smartphone. Trong những con robot hư hỏng này, có những con còn zin và rất ngoan. Để "trưởng thành" và hư hỏng hơn, nó cần phải trải qua quá trình đầy thay đổi và đau đớn mà đâu đó trong thế giới loài người, người ta gọi là DẬY THÌ. Còn với Android, đó là rooting, flash ROM mới ...



Có rất nhiều từ khoá quan trọng để có thể bắt đầu quá trình phá hoại này. Bài viết sẽ tổng hợp những khái niệm này giúp người dùng bắt đầu lấn sang sân chơi mới.

ROM là gì?

Wednesday 9 December 2015

Chạy service bằng port < 1024 - không cần quyền root

Trên các hệ điều hành nhân Linux, để một process có thể nghe (bind) ở port < 1024, process ấy phải có quyền root.

Các port < 1024 còn được gọi là các "privileged port".
Có nhiều cách để workaround giới hạn này, như:
- dùng iptables để chuyển hướng các kết nối tới privileged port đến port mà service đang listen
- dùng authbind

Linux từ bản 2.6.24 trở lên hỗ trợ thêm tính năng set "capability" để cho phép 1 file có thể thực hiện 1 khả năng nào đó mà không cần quyền root.

Để cho phép 1service listen ở privileged port mà không cần quyền root, chạy lệnh sau với quyền root:

Monday 7 December 2015

Xách ba lô lên... và ở lại

[Bài giới thiệu dự án cá nhân mang tên : "Lang thang Hà Nội"] - random thought, non-tech.

Monday 30 November 2015

[Golang] ba chấm

Trong Go có một ký hiệu khá đặc biêt: ba chấm (...)
Ba chấm, thêm vào mỗi cuối câu, để lại một sự miên man trong suy nghĩ.
Như "Anh ... em"...

Và có vẻ như bác Rob Pike cũng hiểu 3 chấm có ý này nọ kiểu vậy, nên lấy nó làm ký hiệu cho "wildcards".
Tức dấu ... sẽ "match" với tất cả mọi thứ (gần giống ký hiệu * trong shell).
Khi viết
"github.com/hvnsweeting/pika/..."
nó sẽ match với tất cả các sub package trong package "pika" cũng như chính package "pika".

Để làm gì? 
Một ứng dụng đơn giản là để test tất cả các package / subpackage trong 1 package,
Ví dụ: cần test toàn bộ package
github.com/labstack/echo
chỉ cần chạy
go test github.com/labstack/echo/...

Sunday 29 November 2015

Tiếng Anh

Học tiếng Anh không phải chuyện đơn giản, nhưng rồi ai cũng phải làm.
Hãy tạm ngừng than vãn về độ khó của Tiếng Anh và xem những developer nổi tiếng nói về việc họ đã học nó vất vả ra sao.

1. Linus Torvard - creator of Linux, git
Linus Torvard là người Phần Lan (Finland), nơi mà tiếng Anh không phải là tiếng mẹ đẻ.
Linus đã bắt đầu đọc bộ Lord Of The Rings với một quyển từ điển, và khi kết thúc
ông không cần nó nữa.
That said, I'll point to a couple of books I really enjoyed. On the non-fiction side, Richard Dawkin's "The Selfish Gene" was one book that I think is pretty influential. On the fiction side, as a teenager I enjoyed Heinlein's "Stranger in a strange land" a lot, and I have to admit to "Lord of the Rings" having been pretty important to me - but for a slightly odd reason, not as a huge Tolkien fan. For me, it was one of the first "real" books I read in English, and I started with a dictionary by my side, and ended it reading without needing one.
http://meta.slashdot.org/story/12/10/11/0030249/linus-torvalds-answers-your-questions

2. Salvatore Sanfilippo (Antirez) - creator of Redis, hping

Thursday 19 November 2015

Django

Django đọc là gieng gâu ( JANG-oh).
Chữ D là âm câm, không phát âm.

Nghe phát âm ở: http://red-bean.com/~adrian/django_pronunciation.mp3

Django là tên của Python web framework phổ biến nhất vũ trụ.
Được đặt tên theo Django Reinhardt - một trong những guitarist vĩ đại nhất mọi thời đại.
Cùng nghe một album của ông:


Tham khảo.
https://docs.djangoproject.com/en/1.8/faq/general/#what-does-django-mean-and-how-do-you-pronounce-it
https://en.wikipedia.org/wiki/Django_Reinhardt

P/s: Ngoài ra cũng có một bộ phim tên là "Django Unchained" rất nổi tiếng và đã thắng 2 giải Oscar.

Wednesday 4 November 2015

Ghi nháy về lọc process theo state bằng check_procs

check_procs là tên của chương trình dùng để check process trên 1 máy theo tiêu chí nào nó.

Bài viết nhắm tới độc giả đã sử dụng check_procs / nagios / shinken. 

Trên Ubuntu 14.04 nó nằm trong package:
$ dpkg -S '/usr/lib/nagios/plugins/check_procs'
nagios-plugins-basic: /usr/lib/nagios/plugins/check_procs
Được dùng trong monitoring, thường dùng kèm với NRPE, NSCA, nagios, shinken ...

check_procs có chức năng lọc process theo state, nó lấy output của lênh:
/bin/ps axwwo 'stat uid pid ppid vsz rss pcpu etime comm args'
rồi xử lý. State của 1 process là ký hiệu xuất hiện ở cột đầu tiên trong output của lệnh trên.

Ta có thể liệt kê / đếm các process có state là S bằng lệnh sau:
$ /usr/lib/nagios/plugins/check_procs -s S -vv | head -n4
CMD: /bin/ps axwwo 'stat uid pid ppid vsz rss pcpu etime comm args'
Matched: uid=0 vsz=0 rss=0 pid=2 ppid=0 pcpu=0.00 stat=S etime=70-01:46:40 prog=kthreadd args=[kthreadd]
Matched: uid=0 vsz=0 rss=0 pid=3 ppid=2 pcpu=0.00 stat=S etime=70-01:46:40 prog=0 args=[ksoftirqd/0]
Matched: uid=0 vsz=0 rss=0 pid=7 ppid=2 pcpu=0.00 stat=S etime=70-01:46:40 prog=rcu_sched args=[rcu_sched]
$ /usr/lib/nagios/plugins/check_procs -s S
PROCS OK: 45 processes with STATE = S | procs=45;;;0;

Wednesday 28 October 2015

[crypto] md5, sha, bit, byte, và hex

8 bits = 1 byte
1 byte biểu diễn được 2^8 = 256 "ký tự"
4 bits biểu diễn được 2^4 = 16 "ký tự".

Một ký tự thuộc hệ hexadecimal (hệ số 16) là một ký tự trong khoảng: 0123456789abcdef
Vậy chỉ cần 4 bits là có thể biểu diễn 1 ký tự hex, 2 ký tự hex = 1 byte

MD5 là gì?
MD5 là tên một thuật toán hash được sử dụng rộng rãi, được định nghĩa đầy đủ trong rfc1321.
Thuật toán hash hiểu nôm na là thuật toán nhận 1 đầu vào thì sẽ cho ra 1 kết quả duy nhất, 2 đầu vào khác nhau sẽ phải cho ra 2 đầu ra khác nhau.
nhận đầu vào có kích thước tuỳ ý nhưng trả về đầu ra với kích thước cố định. Các hàm hash dùng trong bảo mật thường có thêm tính chất: với 2 đầu vào khác nhau sẽ luôn cho ra 2 đầu ra khác nhau.
Giá trị được trả về bởi hash function gọi là "hash value", "hash codes", "hash sums", hay "hash".

Ví dụ:
$ printf "familug" | md5sum
b2bc686c91b99bd9cd92e70cdeaadf40  -
$ printf "FAMILUG" | md5sum
60e29026b93e27f815e73123efedad31  -
$ printf "FAMILUG" | md5sum | cut -d' ' -f1 | tr -d '\n' | wc -c
32
Ví dụ trên cho thấy giá trị MD5 của 2 string khác nhau là khác nhau, mã MD5 (MD5 checksum) có độ dài là 32 ký tự.
Chú ý các ký tự này đều trong khoảng [0-9a-f] tức đều là biểu diễn dạng hexadecimal của giá trị ẩn dưới đó.

Friday 16 October 2015

[Golang] gofmt và sắp xếp import package

câu lệnh ``gofmt`` (đọc là gâu-phằm) sẽ tự động sắp xếp import, format code của file đầu vào, và in ra màn hình code đã được format theo tiêu chuẩn của Golang.

Nếu để các dòng import liền nhau, gofmt sẽ sắp xếp chúng theo thứ tự alphabetical.
Để tách riêng các standard package với các external package, phân cách chúng bởi 1 dòng trắng. Hai cụm import sẽ được gofmt sắp xếp riêng.

Ví dụ:
import (
    "encoding/json"
    "fmt"
    "net"
    "net/http"

    recover_mw "git.familug.org/hvn/golib/echo/recover"
    log "github.com/Sirupsen/logrus"
    logmw "github.com/deoxxa/echo-logrus"
    "github.com/labstack/echo"
)
Cũng có thể dùng goimports để sắp xếp với logic tương tự mà không cần dòng trắng, nhưng đôi khi
goimports tỏ ra quá thông minh và đã có lần tự import https://github.com/cockroachdb/cockroach/tree/421dcbbfe645eab4b49f682eabf69d98d36e50b7/util/log thay vì "log".

Wednesday 14 October 2015

Học Python tại Hà Nội

Tiếp nối thành công 2 khoá PyFML01 và PyFML02, khoá PyFML03 đã được mở.
Xem thông tin chi tiết tại: https://gist.github.com/hvnsweeting/4112374900ef17411f44
Buổi học tới sẽ bắt đầu lúc 19h thứ 5 ngày 15 tháng 10 năm 2015.
Vui lòng đăng ký ngay để biết thêm chi tiết.
Page Facebook: https://www.facebook.com/pyfml
Hết.

Friday 9 October 2015

Mirroring apt repository với apt-mirror

Mirror trong tiếng Việt, dạng danh từ là cái gương, dạng động từ là "phản chiếu".
Trong IT, mirror có nghĩa là giữ một bản copy nội dung của 1 site tại một site khác, nôm na là tạo bản copy.
Đây là một kỹ năng có thể nắm bắt trong 10 phút và dùng cả đời :D

Keyword
mirror /ˈmɪrə/ Việt sub: mí-rơ



apt repository là nơi chứa các package để cài đặt một phần mềm cho các hệ điều hành sử dụng apt (debian, ubuntu...).
Ví dụ apt repository của postgresql: http://www.postgresql.org/download/linux/ubuntu/

Vì sao phải mirror?

Saturday 26 September 2015

base64 encoding

Loạt bài viết giới thiệu về các khái niệm liên quan đến việc chuyển hoá dữ liệu thành 1 dạng khác (encode), và chuyển ngược lại (decode).

Các từ khoá:
- encode/decode <verb>
- encoding/decoding <noun> việc "encode"/"decode"
- data encoding

Base64, Base32, Base16
- tên các thuật toán để encode và decode các chuỗi nhị phân tuỳ ý (binary string) thành dạng text tương ứng.
- Tại sao lại là 64? vì nó sử dụng 64 ký tự để biểu diễn. [A-Za-z0-9+/] là 26 + 26 + 10 + 2 = 64. Ngoài ra có ký tự "=" dùng để đệm (pad).
- Có biến thể khác sử dụng dấu -_ thay cho +/, dùng trong xử lý URL và filename

Tương tự, Base32 sử dụng bảng chữ cái [A-Z2-7] = 26 + 6 = 32
Base16 còn gọi là hex - sử dụng các ký tự [0-9A-F] = 10 + 6 = 16

Trên terminal, dùng lệnh base64 để encode một chuỗi bất kỳ thành dạng "Base64":
$ printf "FAMILUG" | base64
RkFNSUxVRw==
Python2.7 (sử dụng ipython):
In [3]: import base64
In [7]: base64.b64encode("FAMILUG")
Out[7]: 'RkFNSUxVRw==' 
Lấy 10 bytes từ urandom (/dev/urandom - nguồn sinh các byte ngẫu nhiên trên máy tính *NIX), encode thành dạng Base64:

Friday 21 August 2015

Vagrant, những bước chân lang thang...

Mình luôn là fan cuồng của những dòng lệnh, và lý do mà mình không đến với vagrant sớm hơn cũng vì điều này. Nhưng muộn còn hơn không, nhỉ?!!!
 
Trước kia dùng linux, sử dụng KVM để chạy máy ảo, chỉ cần vài câu lệnh là đủ để 1 cái máy chạy ngon lành, ssh vào ầm ầm, và chẳng có lý do gì để mình phải cài lên máy 1 phần mềm viết bằng Ruby, chỉ để phục vụ mục đích tương tự - lại còn phải chạy với Virtualbox (ngày xưa thế, giờ chắc đã hỗ trợ KVM).

Nhưng giờ đã khác, mình không còn dùng Linux nữa, Virtualbox là giải pháp duy nhất trên hệ điều hành này, cách để bật một máy ảo lên không gì khác ngoài sử dụng giao diện GUI. Sống tạm bợ được hơn một năm, và một ngày cuối tuần, mình bất ngờ tìm lại với Vagrant.

Từ khoá
vagrant: /ˈveɪɡr(ə)nt/ Vietsub: vâygrờnt :  có nghĩa là người lang thang

Vagrant đơn giản đến bất ngờ, cái doc đọc xong trong vòng 20 phút, và cuộc đời sang trang.


Cài đặt
xem chi tiết tại: http://www.vagrantup.com/downloads

Từ giờ cần bật máy, chỉ cần cd vào thư mục tương ứng, gõ
$ vagrant up && vagrant ssh
Tất nhiên bài viết này không viết lại hay dịch cái document rất ngắn gọn và dễ hiểu của vagrant, nên đừng gõ dòng lệnh trên nếu bạn chưa đọc doc.

Saturday 8 August 2015

[bash] trôi - in từng dòng của file theo phong cách slow-motion

Xin giới thiệu phát minh vĩ đại nhất của ngày hôm nay mang tên "trôi", một câu lệnh siêu khủng khiếp có khả năng in ra từng dòng của một file - theo cơ chế quay chậm (slow-motion) : ))

Ứng dụng:
- xem cho đẹp, ngắm cho vui
- auto scroll,  tự cuộn trang như boss

Câu lệnh:
$ alias troi='while read i; do echo $i; sleep 0.5; done <'
$ troi /etc/passwd

và rồi nói cứ thế trôi, 
như suối trong khe, 
như xe trên phố 
trôi đi trôi đi
như thế này này
xe xe xe xe
nước nước nước nước
...

[Golang] awesome-go, log to syslog

Log là chuyện hiển nhiên của mọi phần mềm,
Module "log" của Golang là một nỗi thất vọng tràn trề cho ai đến từ Python với logging module, hay Java với Log4j thần thánh.

Và đây là lúc sức mạnh của mã nguồn mở bắt đầu...

Google là cái bản đồ kỳ diệu, nhưng cuối cùng nó cũng chỉ dẫn đến đích là GitHub, nơi kho báu nằm chờ. Cộng đồng mạng của tây thay vì ngồi thể hiện quan điểm về đất nước mình, họ đã xây dựng lên 1 hệ thống gọi là awesome-xyz, lưu trữ đầy đủ mọi tài nguyên liên quan đến mọi thứ. Danh sách đầy đủ các loại some xem ở đây hoặc đây.

Awesome-go cũng góp phần vào sự thần kỳ ấy với đầy đủ các package của cộng đồng, với mục logging gồm hơn hai chục package, làm sao để tìm ra cái mình cần?

Có nhiều cách để đánh giá, nhưng phổ biến nhất là theo lượng star/fork nếu đây là một project trên Github, vậy là từ một thứ "awesome", một sản phẩm hơn cả "awesome"  - fucking awesome đã ra đới ^^

Logrus dẫn đầu cuộc đua sao với 1500+ star, tiếp sau là glog (có sự tham gia của Rob Pike - tác giả của Golang) với 700+ và seelog với 400+

Tuesday 21 July 2015

[Vim] TOhtml, filetype, plugin, indent

1. TOhtml

Trong Vim, ở normal mode, gõ ``:TOhtml``, vim sẽ convert file hiện tại thành code HTML.

2. filetype
Vim có cơ chế load plugin dựa trên kiểu của file đang mở.
Để xem thiết lập hiện tại, gõ ``:filetype``
Kết quả có thể trông như thế này:
filetype detection:ON  plugin:ON  indent:ON
Gõ ``:filetype on`` để bật chế độ tự động nhận dạng filetype. Gõ ``:filetype off`` để tắt.

3. plugin

[PyFML] Tuyển sinh khoá học Python tháng 8/2015

Tiếp nối thành công của khoá PyFML1
 lớp học Python khoá 2 sẽ mở vào tháng 8/2015 tại Hà Nội, xem chi tiết tại đây.
Homepage của lớp học: https://www.facebook.com/pyfml

Bạn muốn tự học?
- Tài liệu: http://www.familug.org/2011/04/learning-python.html

Friday 17 July 2015

[Go] strings package - xử lý string

Xử lý strings chưa bao giờ là một công việc không nhàn chán đối với tôi, nhưng chán
không có nghĩa là không phải làm, vì chán thì vẫn phải làm, vậy nên đành làm cho nó chán mình.

Bài viết giới thiệu các function hữu ích thường dùng trong package strings của Golang, kèm theo các method tương ứng của Python

Bài viết thực hiện trên:
$ go version
go version go1.4.2 darwin/amd64
Tổng số function strong package strings:
$ godoc strings | grep ^func | grep -v 'func (' | wc -l
      43
1. func Contains(s, substr string) bool
Kiểm tra xem string ``s`` có chứa string ``substr`` hay không.

Wednesday 15 July 2015

imgur - upload/share screenshot cho Ubuntu

Hướng dẫn này dành cho ai ko dùng Desktop Environment (dùng i3 chả hạn ._.)

Distributor ID:    Ubuntu
Description:    Ubuntu 14.04.2 LTS
Release:    14.04
Codename:    trusty

$ cd ~
$ wget https://github.com/jomo/imgur-screenshot/archive/master.tar.gz
$ tar xzvf master.tar.gz
$ rm master.tar.gz
$ cd imgur-screenshot-master/
$ sudo ln -s /home/lamdt/imgur-screenshot-master/imgur-screenshot.sh /usr/bin/shit

Tuesday 14 July 2015

Giới thiệu nhanh về MIME

MIME là một từ khoá bạn sẽ nghe tới không ít lần nếu đã sử dụng các email client (MUA) trên desktop.

MIME là gì?
Viết tắt của cụm từ "Multipurpose Internet Mail Extensions"
được mô tả trong RFC 1524 và các RFC khác: RFC 2045, RFC 2046, RFC 2047, and RFC 2231

Nói một cách đơn giản, lúc mới ra đời, giao thức gửi mail chỉ hỗ trợ gửi plaintext, MIME là phần mở rộng cho phép email có thể gửi/nhận các file có định dạng khác (HTML, video, nhạc, ...)
Python: xem https://docs.python.org/2/library/email.html

Sử dụng MIME
Trên UNIX-based OS, các file sau được cung cấp (hoặc tự tạo nếu không có) để hỗ trợ MIME:

Saturday 4 July 2015

[CLI] watch - lót dép ngồi hóng

watch là một động từ, với nghĩa là "xem - theo dõi", kiểu như watching TV.
Với ý nghĩa tương tự, command line ``watch`` sẽ cho phép bạn ngồi xem màn hình, như đang xem tivi.

Chào hỏi kiểu CCGU:
$ for cmd in whatis whereis which; do echo $cmd: `$cmd watch`; done
whatis: watch (1) - execute a program periodically, showing output fullscreen
whereis: watch: /usr/bin/watch /usr/share/man/man1/watch.1.gz
which: /usr/bin/watch
watch sẽ chạy một chương trình theo chu kỳ, hiển thị output đầy màn hình ~.~

Để theo dõi các process dùng nhiều CPU nhất trên máy, theo chu kỳ 2 giây (giả lập lệnh top):

Sunday 21 June 2015

[SaltStack] Chào Muối, em là ai?

Title phụ: How to fall in love with SaltStack?

Update: tham gia hội người dùng Salt tại Việt Nam https://www.meetup.com/VietNam-SaltStack-Meetup/

Muối, một cô gái 25 tuổi, sống nội tâm, một mình ở nơi toàn sắp thép, luôn được bao quanh bởi những anh chàng IT khô cằn mà mỗi thằng đều dấu dưới chân mình một cái giếng ngập tràn chất lỏng (nước?).
Muối không hoàn hảo, như tất cả mọi thứ trên hành tinh này.
Muối không dễ được yêu, bởi Muối chỉ dành cho những ai cần đến cô.
Nhưng Muối đơn giản (YAML), muối nhẹ nhàng (lightweight ~ 50MB RAM), dù nhiều khi hơi phũ phàng trước thay đổi (upgrade PITA).
Muối chẳng cần phải so sánh mình với ai, bởi đấy không phải cách một kẻ yêu bản thân mình sẽ sống.

Muối là tên gọi hư cấu mà tác giả dành cho SaltStack, một điều đặc biệt đã thay đổi cuộc đời anh, mãi mãi.

1. SaltStack là gì?

Friday 12 June 2015

[Debian] update-alternatives: thay đổi là sự lựa chọn!

update-alternatives là tên của một chương trình trong Debian (tất nhiên cả Ubuntu), phục vụ cho việc quản lý các symlink để quyết định câu lệnh nào là default (mặc định).

Chú ý 1: có chữ ``s`` ở cuối tên câu lệnh
Chú ý 2: phiên âm là /ɔːlˈtəːnətɪv/  - Việt sub: ôl tơ nơ tiv 
 
Chào hỏi theo phong cách CCGU
$ for cmd in whatis whereis which; do echo -n $cmd: ; $cmd update-alternatives; done
whatis:update-alternatives (8) - maintain symbolic links determining default commands
whereis:update-alternatives: /usr/bin/update-alternatives /usr/sbin/update-alternatives /usr/share/man/man8/update-alternatives.8.gz
which:/usr/sbin/update-alternatives
Là một câu lệnh thuộc man8, update-alternatives nhắm tới đối tượng sử dụng là các sysadmin, tên câu lệnh khá dài và cho thấy một sự thật rằng dài nhiều khi không phải đã là hay.

update-alternatives giải quyết vấn đề gì?
Khi có nhiều chương trình cùng cung cấp 1 tính năng (ví dụ emacs, nano và vim đều cung cấp tính năng "editor"), việc này tiện cho user được lựa chọn nhưng với các chương trình thì đây lại là một vấn đề, chúng sẽ không biết lấy cái gì để dùng. ``alternatives system`` của Debian đảm bảo cung cấp 1 cái tên chung (cụ thể là 1 symlink file: vd /usr/bin/editor), và nó sẽ chọn một chương trình phù hợp để cung cấp tính năng ấy.

Tuesday 26 May 2015

[CodeGold] Kiểm tra 2 list giống nhau

Update: Đã có code ví dụ bằng Golang/Python, mời các bạn đóng góp các phương án khác sử dụng các thuật toán khác,  các ngôn ngữ khác.

Cho 2 list đầu vào, kiểm tra xem 2 list này có giống nhau không (cùng phần tử, cùng thứ tự).
Với các list đầu vào:
xs = ['pikachu', 'tho', 'chim']
ys = ['chim', 'tho', 'pikachu']
zs = ['chim', 'tho', 'pikachu', 'chaien']
xxs =  ['pikachu', 'tho', 'chim']

Thuật toán thực hiện cần đảm bảo trả về kết quả sai khi so ``xs`` với ``ys`` ``zs``, và trả về kết quả đúng khi so với ``xxs``.

Đề bài viết bằng Python nhưng có thể dễ dàng dịch sang các ngôn ngữ khác.
Hãy suy nghĩ kỹ cách giải của mình trước khi bấm vào "đọc tiếp".

Thursday 21 May 2015

[CodeMath] Giải "Bài toán lớp 3 có số lượng đáp án khổng lồ"

Một bài toán làm náo loạn cộng đồng mạng =)) vậy giải hoy còn chờ gì :3
Đã có lời giải bằng Golang, mời các bạn đóng góp lời giải bằng ngôn ngữ khác và cùng đối chiếu kết quả :D

http://vnexpress.net/tin-tuc/giao-duc/bai-toan-lop-3-co-so-luong-dap-an-khong-lo-3220439.html

với các biến a,b,c,d,e,f,g,h,i là các số nằm trong khoảng 1-9 (các biến có thể có giá trị giống nhau), dạng biểu thức:
a + 13 * b / c + d + 12 * e – f – 11 + g * h / i – 10 = 66
1. Câu hỏi cho học sinh lớp 3: Tìm các số từ a đến i thoả mãn bài toán (tìm một nghiệm của bài toán)
2. Câu hỏi cho cử nhân, kỹ sư, lập trình viên, hacker blah blah: BÀI TOÁN NÀY CÓ BAO NHIÊU NGHIỆM?
3. Câu hỏi cho fan thỏ bảy màu và chaien: Có bao nhiêu phần trăm hư cấu trong câu nói : "Tôi đã dùng ngôn ngữ lập trình Maple để thử tìm hết tất cả đáp án của bài toán và chỉ 3-4 phút đã cho tới 74 trang A4 các đáp số" của thạc sĩ ở đầu bài viết?
4. Tính xấp xỉ số trang A4 - 1 mặt, để in hết kết quả của bài toán với font Time new roman size14, line giãn cách default, mỗi dòng chứa tối đa số đáp án có thể viết được (ví dụ viết 9 số liền nhau rồi tách với đáp án khác bằng một dấu cách).
Phân tích chém gió:
Bài này tính một cách thô sẽ có: 9 biến, mỗi biến có 9 cách chọn, vậy có tất cả 9*9 :
In [5]: 9 ** 9
Out[5]: 387420489 # "ba trăm triệu có lẻ" khả năng.
Thuật toán tối ưu để giải là trừ dần đi để giảm giới hạn của các biến về sau.

Lời giải:

Monday 18 May 2015

[Hanoi] học lập trình python tại lớp học của các thành viên FAMILUG

Đăng ký tại: http://fml.vn/

Kế hoạch ấp ủ đã lâu, giờ thời cơ đã đến, tớ quyết định đứng lớp để đào tạo mội đội hình python đầy nguy hiểm ngay tại lòng thủ đô Hà Nội.
 
Nội dung chi tiết và đăng ký bấm thẳng vào mặt biểu tượng Python bên dưới:



Chú ý PHẢI gửi thêm email từ địa chỉ đã điền trong mẫu đăng ký tới địa chỉ hvn@familug.org để chứng thực. (Tiêu đề: đăng ký lớp PyFML1)

Vài điểm nhấn:
- Trả lại học phí sau 3 buổi học nếu không tiếp tục.
- Review và fix code cho học viên.
- Giảng viên là hvnsweeting - contributor của Saltstack (CTRL F tìm salt) hiện với 74 commits, fix nhiều lỗi nghiêm trọng, top 10 contributor của Diamond
- Trợ giảng là hai học viên đời "F1", chính là 2 người đã thử nghiệm chương trình học này lúc còn thưở ban đầu. Trong đó một người là sinh viên tốt nghiệp khoa hoá, trở thành lập trình viên /sysadmin từ con số 0 tròn trĩnh.
- Đảm bảo truyền tải những kinh nghiệm mà học viên sẽ phải tự mò rất nhiều mới có được.
- Khoá đầu tiên nên học phí còn rẻ :D

Saturday 16 May 2015

[CodeGolf] Dài nhất và ngắn nhất

Đã có code Golang, các ngôn ngữ khác lại chờ bạn đóng góp :D 

Trong cuộc sống, người ta vẫn luôn quan tâm đến những cái nhất, nhất, nhất chứ không phải thứ 2 hay thứ 10.
WorldCup cứ 4 năm diễn ra, nóng bỏng là thế, nhưng vẫn có đội đề xuất bỏ hẳn trận đá tranh giải 3-4 vì người ta xem cũng chỉ quan tâm đội được nhất thôi.

Và để được nhớ mãi, hãy là dài nhất, hoặc ngắn nhất chứ đừng là dạng vừa:

Cho một danh sách các loài, tìm con nào tên dài nhất và ngắn nhất:
In [6]: xs = ['chim', 'bo', 'ga', 'vit', 'voi', 'buom', 'than lan']

Thursday 14 May 2015

m17n, ibus-m17n

m17n là cái tên khá kỳ lạ:
m17n là một kiểu viết tắt đặc biệt của từ : Multilingualization
Từ này có 19 chữ cái -> m + (ulti...atio)-"17 chữ" + n = 19 chữ.
Trên ubuntu, cài gói ibus-m17n để có hỗ trợ gõ tiếng Việt bằng ibus.
$ echo -n Multilingualization | wc -c
19
Hết.

Saturday 9 May 2015

[Code] Tính từ cùng 9gag

UPDATE: đã có code Go, Ruby.  Các ngôn ngữ khác đang chờ bạn đóng góp :p 
Tối ngủ, sốt, nóng, thấy 9gag có cái hình hay hay, code ngay cho nóng

http://9gag.com/gag/aWWP7bd?ref=fbp


Hãy nghĩ thuật toán bạn sẽ dùng để tính ra số theo quy tắc trong bức hình trước khi bấm đọc tiếp.

Wednesday 6 May 2015

httpbin - xem mình đã làm gì với 1 HTTP request

httpbin là tên 1 pip package, là phiên bản offline của site: http://httpbin.org/

Trên một máy tính đã cài sẵn pip, có thể cài nó bằng lệnh sau:
$ pip install httpbin gunicorn
Sau khi chạy, app python này sẽ được chạy và listen port 8000:
$ gunicorn httpbin:app
[2015-05-06 14:03:47 +0700] [26875] [INFO] Starting gunicorn 19.3.0
[2015-05-06 14:03:47 +0700] [26875] [INFO] Listening at: http://127.0.0.1:8000 (26875)
[2015-05-06 14:03:47 +0700] [26875] [INFO] Using worker: sync
[2015-05-06 14:03:47 +0700] [26878] [INFO] Booting worker with pid: 26878
Giờ hãy gửi 1 GET request bằng curl đến đây để xem được mình đã làm gì:

Sunday 26 April 2015

[News] Ubuntu 15.04 ra lò - Vivid Vervet

Như thường lệ, mang tính chất truyền thống, mỗi khi Ubuntu release thì FAMILUG sẽ lên bài như một lời tri ân, cũng là dịp anh em kéo nhau đi uống bia cám ơn cuộc đời, đội ơn Ubuntu đã mang đến cho chúng em ngày hôm nay.

Năm nay, khi tháng tư sắp đi qua, người ta bận rộn đi chơi để Ubuntu "ra" trong lặng lẽ.
Sẽ có 1 buổi party, nhưng phải đợi tháng 5 :D

`http://www.ubuntu.com/

Bản 15.04 có tên khá là buồn cười khi đọc lên "Vivid vervet" (vi vítđ vơ vít)

Thursday 23 April 2015

ghi chú nhanh về cron

1. cron gửi notification (email)
cron gửi output (cả stdout và stderr) của file cronjob hay các câu lệnh trong crontab tới user đã được gán cho biến môi trường ``MAILTO`` của cron. Nếu câu lệnh fail nhưng không có output,
syslog sẽ ghi lại lần chạy fail này nhưng KHÔNG CÓ output nào được gửi tới user cả (thường là root)  vẫn có email gửi về với tên của script đã fail và return code.
Bản chất cron là một daemon đọc file cấu hình từ /etc/crontab và lên lịch để chạy các câu lệnh đó (cron.daily, cron.hourly ...) chỉ là các giá trị (thư mục chứa executable files) được config sẵn trong /etc/crontab

2. Không cần restart cron
mỗi khi thêm/thay đổi một script vào một trong các thư mục chứa crontab file (/etc/cron\..+), không cần restart cron deamon vì cron sẽ tự động quét các thư mục này mỗi phút.
 Thus  cron need not be restarted whenever a crontab file is modified.
3. Tên file cronjob 

Wednesday 22 April 2015

Tạo file "backup" trước khi phá phách

Nhiều khi bạn sẽ cần sửa file trực tiếp trên 1 server, và việc tốt luôn nên làm là tạo một bản gốc để có thể hồi phục, phòng khi lỡ làm gì dại dột.
Sau đây là vài tips giúp việc này trở nên dễ dàng:

1. cp 
Hiển nhiên cách dễ nhất là tạo 1 bản sao của file mình sẽ sửa:
# cp file_se_sua file_se_sua.orig # viết tắt của original 
Nếu gõ lại tên file 2 lần thì hơi mỏi, hãy dùng tính năng của bash, ví dụ:
$ cp states.py{,.orig}; ls states.py*
states.py    states.py.orig
Nhờ tính năng "brace expansion" của bash, 
states.py{,.orig}
 sẽ tự chuyển thành:
states.py states.py.orig
2.  vim
Nhỡ đã mở file ra bằng Vim rồi, có thể sử dụng lệnh sau để lưu file:

Sunday 19 April 2015

[Ebook] Sách học Lua

Lua là tên một ngôn ngữ lập trình.
Lua is a powerful, fast, lightweight, embeddable scripting language.
Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode for a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.
Cuốn sách Programming in Lua được liệt kê ngay trong phần document tại trang chủ của Lua và là một cuốn sách hay, kể cả cho những người không học Lua và nó free online:
http://www.lua.org/pil/contents.html#P1

Ví dụ về sự hay:
giải thích về tail call và tail recursion http://www.lua.org/pil/6.3.html

Thursday 16 April 2015

[CLI] top 10 process dùng nhiều tài nguyên nhất, tmux tip

Không có gì màu mè cả, đơn giản chỉ cần dùng top và cho sắp xếp theo một cột nào đó là xong, nhưng bài này dùng ps và sort.

1. top 5 dùng nhiều CPU nhất:
$ ps xau | head -n1; ps xau | sort -nrk3 | head -n5
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     28368  3.8  4.1 357208 41932 pts/4    Sl+  14:02   0:23 /usr/bin/python /usr/bin/salt-master -ldebug
root     28744  1.8  5.4 523132 55292 pts/5    Sl+  14:07   0:05 /usr/bin/python /usr/bin/salt-run state.orch orchestration.es -ldebug
root     28356  1.2  2.6 298472 27028 pts/4    Sl+  14:02   0:07 /usr/bin/python /usr/bin/salt-master -ldebug
root     28801  1.0  3.3 372236 34168 ?        S    14:07   0:02 /usr/bin/python /usr/bin/salt-cloud --profile ci-minion es7
root     28629  0.8  3.3 372980 34476 ?        S    14:03   0:04 /usr/bin/python /usr/bin/salt-cloud --profile ci-minion es7
ps xau để hiển thị các process đang chạy, head -n1 sẽ lấy dòng title để cho dễ nhìn,
sort -nrk3 để sắp xếp theo kiểu số học (-n) từ lớn xuống nhỏ (-r) theo cột thứ 3 (-k cột %CPU)
head -n5 để lấy 5 kết quả đầu tiên.

Thursday 2 April 2015

[Sysad] một trận chiến giữa netcat và tcpdump

bình yên quá, dậy sóng thôi.

Cài đặt hai bên chiến tuyến:
# apt-get install -y tcpdump  netcat-openbsd
Sau đây hai đấu thủ cùng ra chào khán giả:
# for pkg in nc tcpdump; do whatis $pkg; whereis $pkg; done
nc (1)               - arbitrary TCP and UDP connections and listens
nc: /bin/nc /bin/nc.openbsd /usr/share/man/man1/nc.1.gz
tcpdump (8)          - dump traffic on a network
tcpdump: /usr/sbin/tcpdump /usr/share/man/man8/tcpdump.8.gz
Bây giờ là phần quảng cáo bỉm sữa và bình luận trước trận đấu:
- Bên công rõ ràng là nc, với khả năng tạo kết nối TCP/UDP tuỳ ý (ngoài ra có cả khả năng listen).
- Bên thủ chính là tcpdump danh tiếng, với khả năng "dump" mọi traffic trên 1 network, tcpdump có thể xử lý rất nhiều protocol khác nhau: ether, fddi, tr, wlan, ip, ip6, arp, rarp, decnet, tcp and udp, rõ ràng là hơn nc vài bậc về dạng rộng. ($ man pcap-filter | sed -n "/  proto  /,/If/ p" | sed 's/If.*//g')

Trận đấu bắt đầu trên sân vận động TCP:

Wednesday 1 April 2015

Thursday 26 March 2015

Kiểm tra một process đang chạy hay không (dựa vào PID)?

NOTICE: bài viết tập trung vào vấn đề "kiểm tra xem một process có đang chạy hay không dựa vào PID đã biết"

Tất nhiên cách thô thiển nhất là gõ ps auxww | grep PID để tìm, nhưng bài viết này không viết về cái thô thiển ấy.

Trên Linux, có sử dụng một thứ gọi là proc filesystem. Với mỗi process đang chạy có pid là PID, sẽ tồn tại tương ứng một thư mục /proc/PID

Vậy trên các OS sử dụng Linux, có thể kiểm tra thư mục này có tồn tại không là sẽ biết process có đang chạy hay không.
# ps -ef | grep bin[d]
bind     32511     1  0 05:33 ?        00:00:00 /usr/sbin/named -u bind
# python -c 'import os; print os.path.isdir("/proc/32511")'
True
# process với PID 32519 không tồn tại
# python -c 'import os; print os.path.isdir("/proc/32519")' && ps -ef | grep [3]2519
False
Có vẻ đã bớt thô thiển hơn nhiều, nhưng cách này chỉ áp dụng được với các hệ điều hành dùng Linux (và một số hệ điều hành hỗ trợ procfs thanks +Le Manh Cuong) . Vậy còn cách nào hơn? có thể chạy trên OS X, BSD ...?

Kill it!

Monday 23 March 2015

man + man = men

Với người mới sử dụng UNIX-like OS, man là một thứ khá dài dòng, khó đọc, khó hiểu.
Bài viết này sẽ mang ``man`` đến gần bạn hơn: man + man = (vodka) men

$ whatis man
man (1)              - an interface to the on-line reference manuals
man(1) là chương trình để đọc các file manual (manpage)

1. sections
Các manpage được phân thành 8 sections khác nhau, sections thường gặp nhất là
1 2 3 5 và 8 (fibonacci?!!!)
Khi thấy viết login(1) login(3), chúng ám chỉ chương trình login và function login.
Người dùng bình thường sẽ chỉ gõ ``man caulenh`` và nó thường trả về man 1,
để chỉ rõ section muốn dùng, thêm số section cần mở, vd ``man 3 login`` (nếu máy bạn chưa cài gói  ``manpages-dev`` câu lệnh man trên sẽ báo lỗi).
# apt-get install -y manpages-dev
...
Setting up manpages-dev (3.35-0.1ubuntu1) ...
Để liệt kê tất cả các manpage chứa 1 từ khoá, sử dụng man -k

Thursday 12 March 2015

inodes, statvfs, và các thông số cơ bản về một filesystem

inode là viết tắt của index node, một cấu trúc dữ liệu để biểu diễn một filesystem object trên UNIX-like filesystem. Một inode có thể biểu diễn một file, directory, hoặc object khác (symlink, special block ...). Để dễ hiểu, có thể sử dụng file node thay cho inode.

sử dụng df -i để xem thông tin về inode của các filesystem trên hệ thống bạn đang dùng.
ls -i giúp hiển thị index number của 1 filesystem object.
hvn@ubuntu:~⟫ ls -i /etc/passwd
263212 /etc/passwd
hvn@ubuntu:~⟫ df -i
Filesystem                  Inodes IUsed  IFree IUse% Mounted on
/dev/mapper/ubuntu--vg-root 441504 71768 369736   17% /
none                        127233     2 127231    1% /sys/fs/cgroup
udev                        124422   456 123966    1% /dev
statvfs là một system call tuân theo chuẩn POSIX để lấy thông tin về một file system.
C function statvfs(PATH) sẽ trả về thông tin về file system chứa file được gán trong PATH.

Trên python2.7 có thể lấy thông tin này bằng os.statvfs(PATH)

Tuesday 3 March 2015

[Python] Tí ăn gì nhỉ?

Câu hỏi vui hàng ngày được đưa ra trước 12h trưa,

A: tí ăn gì nhỉ
B: ăn tí gì nhỉ ....
C: ...
A: 4! = 24 :))

Hay là  mình cứ bất chấp hết in hết nó ra:

Wednesday 25 February 2015

[cmd] mối quan hệ giữa du, sudo và "SH"

1. du
$ du -csh Github/ Pictures/
2.3G    Github/
6.6G    Pictures/
8.9G    total
có vài option cần chú ý của lệnh này
-s  --summarize
Chỉ hiện các giá trị là tổng dung lượng của mỗi argument

Tức nếu dùng du với 2 argument thì kết quả sẽ chỉ có 2 dòng (nếu argument là 1 directory, nó sẽ tính dung lượng tổng của directory đó thay vì của từng file)

-c --total
Hiển thị tổng dung lượng của các argument đã gán cho du. Như ví dụ trên, dòng cuối cùng là 8.9 G, tổng dung lượng của 2 thư mục đầu vào.

-h --human-readable
In ra dung lượng ở dạng thân thiện với người dùng (thay vì mặc định in ra số byte - thường khá lớn)

2. sudo

Thursday 12 February 2015

[Python] lambda

Bài viết giới thiệu vài ví dụ về việc tạo anonymous function sử dụng lambda trong Python.

Cú pháp:
lambda arguments: expression
Trả về 1 function object
Nó thường dùng để định nghĩa các hàm đơn giản (trong 1 dòng) , là một khái niệm đi mượn từ các ngôn ngữ lập trình hàm.
Nếu sử dụng lambda, dù chỉ 1 lần thử, người dùng sẽ có những cảm giác vô cùng mới lạ, sảng khoái với nó. Bài viết khác sẽ đi sâu vào giải thích khái niệm lambda, bài này chơi đã :

.. note: toàn bộ ví dụ trong bài này được code trực tiếp trên ipython trên python2.7 nhưng vẫn chạy được trên python3.x:

Saturday 7 February 2015

[Python] WTF I did last year

Một phiên bản python của bài hát "Em làm gì tối nay - Khắc Việt".
Năm qua mình đã làm được gì? hãy tự đánh giá và in ra cho đỡ xấu bằng script sau, rồi ngắm nhìn kết quả...

https://github.com/familug/FAMILUG/blob/master/Python/wtfidly.py
Và trước khi kết thúc, hãy cùng nghe bài hát "em làm gì tối nay" :3


Thursday 5 February 2015

[Python, bash] Kiểm tra file executable

Để kiểm tra xem đầu vào của nó có phải là một file chạy được không (như các file trong /bin, hay các file đã đươc chmod +x),
hacker mũ hồng viết như sau:

bash:
$ test -x path
python:
In [3]: os.access(path, os.X_OK)
Out[3]: True
Có gì sai ở đây?

Tuesday 3 February 2015

[Python] try...finally

Trong python, try...except là cặp đôi hoàn cảnh mà đi đâu cũng sẽ gặp, mà nếu như trong 1, 2 trang code của bạn không dùng try...except một lần nào thì có vẻ như đoạn code ấy có vấn đề.
finally không được sử dụng nhiều như except, và vì thế người dùng có thể không hiểu rõ tác dụng của nó. Bài viết này sẽ giải thích các trường hợp đặc biệt với finally.

Từ khoá:
  • try statement : câu lệnh try
  • finally clause: mệnh đề finally
Định nghĩa về "try"
The try statement specifies exception handlers and/or cleanup code for a group of statements
Vậy try... có 2 tác dụng:
  1. xử lý exception (exception handling - bằng mệnh đề except)
  2. và cleanup code cho một tập các câu lệnh (bằng mệnh đề finally)
Chi tiết về việc sử dụng exception là một phần không thể thiếu / là văn hoá của Python rồi nên ở đây không bàn tới.

Monday 2 February 2015

[Programming] Closure

Closure /ˈkləʊʒə/ sự đóng kín (Việt sub: cờ lâu giơ)

Là một khái niệm phổ biến ở các ngôn ngữ lập trình hàm (functional programming language như LISP, Scheme, ...) nhưng cũng có thể thấy ở Javascript,Ruby, Go, Object C, hay hỗ trợ 1 phần ở python2 và hỗ trợ hoàn toàn ở python3... (nhưng không có trong C, Java). Các ngôn ngữ nào cho phép trả về giá trị là một function thì có thể sẽ hỗ trợ closure.

Để tránh sử dụng wikipedia, sau đây là các định nghĩa closure từ document chính thức của một số ngôn ngữ lập trình:

Go đưa ra khái niệm ở dạng mô tả như sau trong gotour:
Một closure là một function (hàm) mà reference (tham chiếu) đến các biến ở ngoài body của nó. Function này có thể truy cập và thay đổi các biến mà nó đã reference. Có thể nói function "bound"(đã gắn) đến các biến.

EMACS LISP:
Một closure là function mà nó "mang theo" một bản ghi về "môi trường lexical" đã tồn tại khi hàm đó được định nghĩa.

Javascript:
Closure là function mà nó "tham chiếu"(refer) đến các biến độc lập. Hay nói cách khác, function ấy có khả năng "nhớ' về môi trường mà nó đã được tạo.

Dễ hiểu nhất là phân tích đoạn code sau:

Friday 30 January 2015

Vài sai lầm hay mắc phải khi lập trình viên Python code Go

1. Quên compile =))
Thường nếu chỉ code các script nhỏ, code xong ra python filename.py chạy luôn. Nhưng Go là một compiled-language, code xong phải compile, compile xong mới chạy được.
2. Dùng '' thay vì ""
Trong Go, string nằm giữa dấu ngoặc kép "", trong Python dấu ngoặc '' hay "" đều dùng được cả. Và lỗi về việc này sẽ thường xuyên đập vào mặt: "illegal rune literal".
3. Quên không return khi định nghĩa function
Python là dynamic type language, khi viết function không cần / không thể ghi là nó sẽ trả về giá trị nào, thuộc type gì. Golang hay bất cứ static type language nào cũng cần khai báo giá trị sẽ trả về và kiểu (type) của nó.

Có nên học Go?

Wednesday 28 January 2015

Để trờ thành Linux sysadmin ...

Làm thế nào để trở thành Linux sysadmin? học gì để trở thành Linux sysadmin?

Đăng ký học Linux Sysadmin OFFLINE tại https://pymivn.github.io/sysad101/
Khoan hãy đi vào phần trả lời, hãy tự hỏi mình vài câu sau:
- bạn có sẵn sàng thức dậy vào lúc 3h sáng vì hệ thống có sự cố ? bạn có sẵn sàng / muốn ở trung tâm dữ liệu suốt một tuần không biết ngày đêm?

Nếu câu trả lời là có, hãy tiếp tục.
Nếu có chút ngần ngại, hãy ngó qua khả năng trở thành một python developer...
Nhưng dù sao đi nữa, hãy cứ tiếp tục :))

Monday 26 January 2015

[Vim] vim-pathogen

Nếu bạn đã dùng nó, hãy bỏ qua bài này.
Nếu chưa, hãy dành 5 phút đọc và dùng ngay.
vim-pathogen là một vim-plugin cho phép cài đặt các vim-plugin khác một cách dễ dàng. Đại khái là "khó một lần rồi thôi", sau lần này sẽ dễ. Mà thực chất thì lần này cũng chả khó gì ~.~

English
pathogen /ˈpaθədʒ(ə)n/ mầm bệnh (sub Việt : "PÁT thơ giờn")

Cài đặt
Chạy lệnh sau:
mkdir -p ~/.vim/autoload ~/.vim/bundle && \
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
 
Github repo: https://github.com/tpope/vim-pathogen

Sau đó thêm dòng

Monday 19 January 2015

[Go] select và giao thông

Bài viết này giải thích cách hoạt động của câu lệnh "select" trong Go, sử dụng ví dụ trong tutorial "A tour of Go"

1. function fibonacci
(Xem code ở dưới).
- Nhận input là 2 channel kiểu int. (channel sẽ chỉ "truyền" dữ liệu có kiểu "int").
"for { }" => tương đương với "while true" trong khác ngôn ngữ khác, ở đây lặp vô hạn.

Trong ví dụ này, câu lệnh ``select`` có chứa 2 case, theo phần giới thiệu của tutorial:
``select`` lets a goroutine wait on multiple communication operations.
 ``select`` cho phép một goroutine chọn hướng chạy dựa trên kết quả của các hoạt động giao tiếp (truyền data trong channel)
câu lệnh ``select`` sẽ block cho đến khi một trong các ``case`` của nó có thể chạy (channel hoạt động - không bị block), khi đó nó sẽ chạy các câu lệnh trong ``case`` ấy, nếu có nhiều ``case`` đều có thể chạy cùng lúc thì nó sẽ chọn ngẫu nhiên một ``case``.

Để dễ hiểu, ở ví dụ dưới tưởng tượng 2 channel là 2 con đường, nó giao nhau ở ngã tư có 1 anh cảnh sát giao thông.