<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>I&#39;m Thanh</title>
	<subtitle></subtitle>
	<link href="https://int3ractive.com/feed.xml" rel="self"/>
	<link href="https://int3ractive.com/"/>
	
	<updated>2026-04-14T15:00:00Z</updated>
	
	<id>https://int3ractive.com</id>
	<author>
  <name>Thanh Tran</name>
  <email>trongthanh@gmail.com</email>
	</author>
	
  
  <entry>
    <title>curl https://amlich.app</title>
    <link href="https://int3ractive.com/blog/2026/curl-amlich-app/"/>
    <updated>2026-04-14T15:00:00Z</updated>
    <id>https://int3ractive.com/blog/2026/curl-amlich-app/</id>
    <content type="html"><![CDATA[
      <p>Một cải tiến với trang <a href="https://amlich.app">amlich.app</a> mà mình dự định từ lâu, lấy ý tưởng từ trang <a href="http://wttr.in">wttr.in</a> đó là hiển thị thông tin Âm Lịch ngay trên cửa sổ terminal.</p>
<p>Nay nhờ có thằng đệ Claude Code và gói Copilot Pro Github tài trợ cho open source developer, mình đã xong nốt món nợ tech này.</p>
<p>Tính năng rất đơn giản: Ngay trong cửa sổ terminal, chỉ cần gõ</p>
<pre class="language-sh"><code class="language-sh">$ <span class="token function">curl</span> <span class="token parameter variable">-L</span> amlich.app
<span class="token comment"># hoặc</span>
$ <span class="token function">curl</span> https://amlich.app</code></pre>
<p>thì thông tin của ngày Âm hiện tại và bảng lịch tháng sẽ hiện thị rõ ràng, “rực rỡ” như một phần mềm CLI.</p>
<p>Ngoài ra, amlich.app cũng được thêm tính năng render thông tin Âm Lịch dưới dạng plain text cho AI Agent hoặc bất kỳ HTTP client nào có truyền header “accept: text/markdown”. Việc trả về plain text sẽ giúp tiết kiệm token khi làm việc với LLM.</p>
<p><img src="/images/2026/amlich-app-curl-markdown.png" alt="Markdown output của amlich.app cho AI Agent" title="curl -L -H 'Accept: text/markdown' amlich.app"></p>
<p>Bài giới thiệu cũng chỉ đến đây. Bà con có thắc mắc gì thêm mình comment nghen.</p>
<hr>
<p>Ghi chú thêm:</p>
<ul>
<li>curl mặc định prepend <code>http://</code> nên cần thêm flag <code>-L</code> để follow redirection. Domain <code>.app</code> bắt buộc phải dùng https.</li>
<li>Nếu terminal không có curl thì có thể thay bằng <code>wget -qO-</code></li>
</ul>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Web Extension: Tra Cứu Đơn Vị Hành Chính VN</title>
    <link href="https://int3ractive.com/blog/2026/web-extension-tra-cuu-dvhcvn/"/>
    <updated>2026-04-03T05:00:00Z</updated>
    <id>https://int3ractive.com/blog/2026/web-extension-tra-cuu-dvhcvn/</id>
    <content type="html"><![CDATA[
      <p>Tôi đã “vibe code” browser extension: <a href="https://tracuudvhc.thanh.im">Tra cứu Đơn Vị Hành Chính 🇻🇳</a>.</p>
<p>Đây là một side project xuất phát từ nhu cầu cá nhân mà mình nghĩ nhiều người cũng sẽ gặp phải: việc sử dụng tên phường xã mới đã xuất hiện sâu rộng trên các văn bản, mẫu đơn, tin tức báo chí… nhưng chúng vẫn quá mới và lạ lẫm đối với những người đã lớn lên cùng với những cái tên phường, tên quận quen thuộc.</p>
<p>Đã có một vài công cụ tra cứu trực tuyến được làm ra từ năm ngoái nhưng khi mình tìm thử một browser extension để tiện việc tra cứu ngay tại tab đang mở thì chưa có ai làm.</p>
<p><img src="/images/2026/wx-tra-cuu-dvhcvn-screenshot-2.png" alt="Tab tra cứu Cũ → Mới của extension" title="Tab tra cứu Cũ → Mới"></p>
<p>Với số lượng dữ liệu ĐVHC cấp nhỏ nhất là phường/xã không quá lớn: 3291 đơn vị phường xã mới; 9953 phường xã cũ, tương đương với số lượng đối chiếu giữa cũ và mới). Đây là con số khá lý tưởng để thử khả năng và tốc độ của công nghệ IndexedDB mà các trình duyệt hiện đại đều hỗ trợ. Và nhờ sử dụng IndexedDB, tất cả dữ liệu và xử lý tra cứu hoàn toàn xảy ra offline tại trình duyệt mà không cần đến server.</p>
<p>Một tính năng đáng kể mà chỉ có browser extension mới làm được đó là tự động tìm và chú thích các tên phường / xã mới với tên địa phương cũ trong bất kỳ trang web nào bạn đọc. Việc này giúp độc giả các trang tin tức dễ dàng liên hệ đến vị trí địa lý của địa phương đang được nhắc tới.</p>
<p><img src="/images/2026/wx-tra-cuu-dvhcvn-screenshot-3.png" alt="Tính năng tự động chú thích tên phường xã mới trên trang tin tức" title="Tự động chú thích tên địa danh trên trang web"></p>
<p>Ngoài ra, side project này cũng giúp mình thử nghiệm agentic engineering và build software gần như hoàn toàn bằng AI Agent (Claude Code).</p>
<p>Và đến hôm nay, giữa thời đại AI này, mình đã được kiểm chứng rằng: VIẾT CODE sẽ không còn là công việc của lập trình viên nữa. LTV sẽ phải “tiến hóa” sang một vai trò cao hơn và đúng nghĩa engineering hơn. Topic này mình xin bàn trong một bài viết khác.</p>
<p>Cuối cùng, mời mọi người <a href="https://tracuudvhc.thanh.im">cài thử extension này</a> và cho feedback nhé. Extension này nguồn mở và hoàn toàn không có quảng cáo hay tracking.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>My 2023 Lookback</title>
    <link href="https://int3ractive.com/blog/2023/2023-recap/"/>
    <updated>2023-12-31T15:20:36Z</updated>
    <id>https://int3ractive.com/blog/2023/2023-recap/</id>
    <content type="html"><![CDATA[
      <p><img src="/images/2023/presenting-at-vws.jpg" alt="Me presenting at Vietnam Web Summit 2023" title="Me presenting at Vietnam Web Summit 2023"></p>
<p>This blog is getting quite some dust. It’s been a while and I was too busy with daywork, technical research and especially a family with 2 kids. I regreted a little bit that I should have kept a habit of writing.</p>
<p>Anyhow, here I am, at the end of of 2023. I jotting down my recap of 2023 as a chance to look back and appreciate what I have achieved and also to restart my writing habit.</p>
<h3>Professional</h3>
<p><img src="/images/2023/chotot-id.png" alt="id.chotot.com rearchitect and revamp" title="id.chotot.com"></p>
<ul>
<li>🚢 Released <a href="http://id.chotot.com">id.chotot.com</a> and deep dived in OAuth &amp; OpenID Connect</li>
<li>🚢 Released first stable version 1.0 of Chợ Tốt Design System after 2+ years of research, cross-domain collaboration and execution</li>
<li>🚢 Strengthen Chợ Tốt’s users authentication with SMS-based MFA</li>
<li>✅ Fought (and won) the uphill battle against Facebook Data Assessment ordeal</li>
</ul>
<h3>Personal</h3>
<p><img src="/images/2023/stablediffusion-automatic1111.jpg" alt="screenshot of my testing out StableDiffusion image generation" title="Me testing out Stable Diffusion"></p>
<ul>
<li>⌨️ Switched to Neovim completely and set up a <a href="https://github.com/trongthanh/nvchad">portable nvim config</a> based on NVChad</li>
<li>🖼️ Dipped one toe into Generative AI with Stable Diffusion, Automatic1111, LLM and Langchain</li>
<li>🔑 Researched WebAuthn and passwordless tech solutions; delivered a <a href="https://int3ractive.com/slides/passwordless-authentication-with-webauthn/">presentation</a> at Vietnam Web Summit 2023</li>
<li>📜 Learned Go lang, Python</li>
<li>📚 Read (mostly listen to) 08 books</li>
<li>🚙 Traveled to 09 different towns and city with team and family.</li>
<li>🛝 Raised 2 boys (5 and 9 year old) without going insane.</li>
</ul>
<p><img src="/images/2023/family-selfie-explora-science.jpg" alt="selfie of my family at Quy Nhon Explora Science center" title="My family trip to Quy Nhon, Vietnam. At Explora Science Quy Nhon."></p>
<p>More images:</p>
<p><img src="/images/2023/clad-ui.png" alt="screenshot of Chotot Web design system" title="Chợ Tốt Clad UI Design System (closed source)"></p>
<p><img src="/images/2023/my-custom-nvchad-config.png" alt="screenshot of my Neovim with custom NVChad config" title="Screenshot of my Neovim with custom NVChad config"></p>
<p><img src="/images/2023/facebook-data-assessment.png" alt="screenshot of Facebook Data Assessment dashboard" title="Multiple submissions at Facebook Data Assessement dashboard. I've spent many hours gathering documents, collecting info from owners, writing up explanations and appeal to finally pass this cumbersome process."></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Things to do after installing Ubuntu Mate</title>
    <link href="https://int3ractive.com/blog/2019/things-to-do-after-installing-ubuntu-mate/"/>
    <updated>2019-12-10T18:40:08Z</updated>
    <id>https://int3ractive.com/blog/2019/things-to-do-after-installing-ubuntu-mate/</id>
    <content type="html"><![CDATA[
      <p>Despite the title, this post is not intended as a generic guide like <a href="https://www.omgubuntu.co.uk/2019/10/things-to-do-after-installing-ubuntu-19-10">this one for the official Ubuntu GNOME</a>. It is more of personal notes from my tweaks to become as productive on Ubuntu MATE as compared with macOS on the same MacBook Air. Therefore it is strongly opinionated from someone who has been using macOS on MacBook for a long time. Nevertheless, if you’re interested in using Ubuntu MATE on MacBook or laptop in general, this post may give you some head start.</p>
<p>How to install <a href="https://ubuntu-mate.org/">Ubuntu MATE</a> on MacBook (Air) is out of this post scope. You may look up tutorials or YouTube videos specialized on this aspect.</p>
<p>Here’s what you need to do, after install it successfully and on the first start up:</p>
<h2>#1 Choose panel layout</h2>
<p>Ubuntu MATE uses the <a href="https://mate-desktop.org/">MATE Desktop Environment</a> and it has system of panels affixed to the sides of the screen. These panels are so flexible that with them, MATE desktop can mimic any popular desktop layouts, including the traditional GTK2 layout, or Windows, or current Ubuntu GNOME or even Mac OSX…</p>
<p>However, tweaking the panels is tedious, so starting from Ubuntu Mate 19.10, you’ll have the Desktop Layout option on the Welcome screen where you can choose the preset of the panels that will resemble any popular desktops:</p>
<p><img src="/images/2019/ubuntu-mate-pick-layout.png" alt="Screenshot of Ubuntu MATE Welcome window" title="Ubuntu MATE Welcome window"></p>
<p>If you miss this screen, you can still search and re-open <strong>Welcome</strong> app from the applications menu.</p>
<p>Another way to choose panel layout is via <strong>MATE Tweak</strong> (installed by default): With MATE Tweak opened, switch to <strong>Panel</strong> settings group. At the <strong>Panels</strong> layout dropdown, select your preferred preset. Here, you have the option to save your panels’ preferences as a custom preset for your convenience.</p>
<p>Since I’m used to OSX metaphor, my choice was <strong>Cupertino</strong> and some of below tweaks depends on this.</p>
<h2>#2 Install <code>TLP</code> power saving daemon</h2>
<p>You only need this step if you’re on laptop. Here’s the claim by the author: “TLP saves laptop battery power on Linux without the need to understand every technical detail.”</p>
<p>For most laptop devices and MacBooks, all you have to to do is install these packages:</p>
<p><code>sudo apt install tlp tlp-rdw</code></p>
<p>And from now on, just leave it to the daemon to do its job. For more more info and configuration, visit <a href="http://linrunner.de/en/tlp/docs/tlp-linux-advanced-power-management.html">TLP documentation page over here</a>.</p>
<h2>#3 Install dconf editor</h2>
<p><strong>dconf Editor</strong>, if you don’t know it yet, is a very handy tool to configure some of very hidden settings of Linux desktop. It is also a required tool for some of the steps below. If you can’t find it in the Applications menu &gt; System Tool, install it now:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> dconf-editor</code></pre>
<h2>#4 Hide the plank icon on dock</h2>
<p>The Cupertino (macOS style) layout use Plank dock. By default it has the plank icon always appear on the dock (clicking it will open Plank preferences) which looks redundant for me.</p>
<p><img src="/images/2019/ubuntu-mate-plank-dock.jpg" alt="Dock with plank icon highlighted"><em>Dock with Plank icon</em></p>
<p>So to hide it, open dconf Editor, click on the 🔍 (search) icon, search for <code>plank</code>, then select the path <code>/net/launchpad/plank</code>, then <code>dock</code> &gt; <code>dock1</code> (Since there is only one dock on the screen).</p>
<p>Scroll down and look for <strong>show-dock-item</strong>, turn it to <code>false</code>.</p>
<h2>#5 Change Brisk menu hotkey</h2>
<p>The applications menu (open when clicking top left Ubuntu MATE icon) is called Brisk menu. Depends on which panel layout you choose, it will be a conventional dropdown list menu or the full screen icons grid like ones found in modern desktops. But they use the same hot key to trigger, and by default it is <code>Super_L</code> (the left Command / Window key). However, I’m used to binding Super key with many shortcuts, so my preference is to change it to something else.</p>
<p>Open <strong>dconf Editor</strong>, search for <code>brisk-menu</code>, and navigate to <code>/com/solus-project/brisk-menu/hot-key</code>, disable Use default value and then set your own shortcut. Here are some of my suggestions:</p>
<ul>
<li><code>LaunchB</code> - Launch the menu like on macOS; it is the media key at <code>F4</code> key on MacBook keyboard. (This is my choice)</li>
<li><code>&lt;Mod4&gt;space</code> - Launch the menu with Super+space</li>
<li><code>&lt;Mod4&gt;a</code> - Similar to GNOME Shell’s activity and app launcher</li>
</ul>
<h2>#6 Reduce indicator applet spacing</h2>
<p>Ubuntu MATE’s systray icons notoriously have <a href="https://ubuntu-mate.community/t/mate-18-04-indicator-applet-complete-1-20-0-icons-resize-issue/16807">very large spacing</a>. To fix this, we will add some custom gtk-3 CSS overrides. Open this file or create it if it doesn’t exist: <code>~/.config/gtk-3.0/gtk.css</code>. Add below CSS to the file and you may adjust it depending on your panel’s height and theme:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* this apply to all panel menu items */</span>
<span class="token selector">.mate-panel-menu-bar menuitem</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 2px 2px<span class="token punctuation">;</span> <span class="token comment">/* vertical then horizontal padding */</span>
<span class="token punctuation">}</span>

<span class="token comment">/* this increase horizontal spacing a bit for global menu items*/</span>
<span class="token selector">.-vala-panel-appmenu-private > menuitem</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 2px 4px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>#7 Install new theme</h2>
<p>Ubuntu MATE comes with a few default themes which you can pick from the app named <strong>Appearance</strong>. To me, only the default Ambiant-MATE theme looks decent, while other looks dated. Fortunately, there are some good-looking themes that are still compatible with MATE desktop and can be easily installed from default Ubuntu apt-get repo:</p>
<ul>
<li>Adapta (<code>adapta-gtk-theme</code>)</li>
<li>Arc (<code>arc-theme</code>)</li>
<li>Numix (<code>numix-gtk-theme</code>)</li>
<li>Flat-remix (<a href="https://drasite.com/flat-remix-gtk">installation instructions</a>)</li>
</ul>
<p>Besides, many GTK theme here compatible with Ubuntu Mate: <a href="https://www.omgubuntu.co.uk/2017/11/best-gtk-themes-for-ubuntu">omgubuntu.co.uk/2017/11/best-gtk-themes-for-ubuntu</a></p>
<p>Icons also have big impact on look &amp; feel of the desktop. However I’ve tried many icon themes and because of compatibility, many of theme make the systray icons look terrible. These are a few of them that look decent on MATE:</p>
<ul>
<li>Papirus (<code>papirus-icon-theme</code>)</li>
<li>Numix / Numix Circle (<code>numix-icon-theme</code>)</li>
<li>Faenza (from <code>faenza-icon-theme</code>)</li>
<li>Faenza MATE Icon (<code>mate-icon-theme-faenza</code>)</li>
<li>Flat Remix icons (<a href="https://drasite.com/flat-remix-gtk">installation instructions</a>)</li>
</ul>
<p><img src="/images/2019/ubuntu-mate-desktop.jpg" alt="Screenshot of my current desktop"><em>My current desktop featuring default Ambiant MATE Dark theme with Flat-Remix-GTK window decoration.</em></p>
<h2>#8 Switch to use dark cursors</h2>
<p>Here’s another personal preference, but I’d prefer dark cursors to light ones. From <strong>Appearance</strong> app, you can choose the default <strong>MATE Black</strong> at the Pointer chooser. Or, you can install <strong>Yaru</strong> cursors theme via <code>yaru-theme-icon</code> apt package.</p>
<p>To set the cursor theme even before user log in, you can run below command, and then choose the preferred one:</p>
<pre><code>sudo update-alternatives --config x-cursor-theme
</code></pre>
<h2>#9 Install Ulauncher</h2>
<p>I’m a big fan of <strong>Spotlight</strong>, and more recently, the <a href="https://www.alfredapp.com/">Alfred app</a> on macOS. More or less, both of them let me search and launch apps quickly without having to browse through the list of icons in launcher menu. They also let me search and open files quickly, and provide some handy actions like calculate arithmetic expression, look up dictionary and even search from the web.</p>
<p>When moving to Linux, fortunately, I’ve found <a href="https://ulauncher.io/">Ulauncher</a> which does very similarly to Alfred. To install, you can follow instructions at Ulauncher website. (there’s a custom ppa for Ubuntu users’ convenience.)</p>
<p>Ulauncher’s default shortcut is similar to macOS Spotlight’s, that is <code>Super + Space</code>. You can change it from the application’s setting.</p>
<p><img src="/images/2019/ubuntu-mate-ulauncher.jpg" alt="Screenshot of ULauncher"><em>Ulauncher popup with System extension</em></p>
<h2>#10 Install Ubuntu Software application</h2>
<p><strong>Software Boutique</strong> is the default software center on Ubuntu MATE. However, it has very small selection of applications. To come back to the popular Ubuntu Software center which has more choices, including many updated Snap apps, install following package via terminal:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> ubuntu-software</code></pre>
<h2>#11 Remember opening applications when log out / shutdown</h2>
<p>When switching from macOS to Ubuntu MATE on this same MacBook Air, I noticed that the <strong>suspend mode</strong> on Linux keep <strong>consuming power much more than that on macOS</strong>. That means when I closed the laptop to put away or to carry to somewhere, the battery kept draining, and I ended up having to charge it constantly.</p>
<p>As long time macOS user, I find <strong>this is the most annoying thing about Linux on laptop</strong>. To work around, I shutdown the laptop whenever I leave it overnight or for a long time. Fortunately, Ubuntu MATE is already light-weigh and boots up very fast on SSD. To ease the pain of recovering the opening windows from last session, you can turn on <code>Automatically remember running applications when logging out</code> option in <strong>Startup Application</strong> window:</p>
<p><img src="/images/2019/ubuntu-mate-restore-window.jpg" alt="Remember running applications when logging out"></p>
<h2>#12 Fix keyboard back lights keep turn up to 100% after restart / re-login</h2>
<p>If your laptop has backlight for keyboard, then you’ll notice an annoying issue with the power management control which will set the keyboard backlight to maximum whenever you re-login or change from battery to AC power. On this <a href="https://ubuntu-mate.community/t/keyboard-light-keeps-turning-on-after-login-and-or-unlock/6914">community thread regarding the issue</a>, some suggested to edit the Upower.conf but this will also disable the ability to adjust backlight brightness level with media keys.</p>
<p>Adapting from <a href="https://ubuntu-mate.community/t/keyboard-light-keeps-turning-on-after-login-and-or-unlock/6914/24">this post</a>, below are the config I’m currently use as work-around. It will reset backlight to a very dim level which is visible in the dark instead of turn it off completely.</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># run with terminal</span>
gsettings <span class="token builtin class-name">set</span> org.mate.power-manager kbd-backlight-battery-reduce on
gsettings <span class="token builtin class-name">set</span> org.mate.power-manager kbd-brightness-dim-by-on-battery <span class="token number">75</span>
gsettings <span class="token builtin class-name">set</span> org.mate.power-manager kbd-brightness-on-ac <span class="token number">10</span></code></pre>
<p>Instead of running above commands, you can edit these config with <strong>dconf Editor</strong> at <code>/org/mate/power-manager</code></p>
<h2>MacBook tweaks</h2>
<p>Below are some additional tweaks specialized for MacBook. These tweaks may be too opinionated and less demanding so I just keep them brief (and because at this point I’m so exhausted writing this long post):</p>
<h2>#13 Correct monitor color with custom ICC profile</h2>
<p>My MacBook monitor looks a bit bluish when booting to Linux. This can be fixed by apply correct ICC color profile. Unfortunately, these is no ICC profile chooser on Ubuntu MATE (Ubuntu GNOME does have one). To apply custom ICC color profile on Ubuntu MATE, I need to install a tool named <a href="https://wiki.archlinux.org/index.php/ICC_profiles#Loading_ICC_profiles"><code>xcalib</code></a>.</p>
<ul>
<li>Extract the *.icc file when logged into macOS or search and download a file called <code>CustomMacRumors.icc</code>.</li>
<li>Add a new entry in <strong>Startup Application</strong> with following command: <code>/usr/bin/xcalib -d :0 /path/to/CustomMacRumors.icc</code></li>
<li>If there is error related to <em>ramp size</em>, <a href="https://askubuntu.com/questions/930084/xcalib-error-unsupported-ramp-size">check out this SO question</a>.</li>
</ul>
<h2>#14 Swap Fn and Control keys and/or Option and Command keys</h2>
<p>Install a kernel module named <code>hid-apple-patched</code>. Visit this <a href="https://github.com/free5lot/hid-apple-patched">Github repo to learn more.</a>.</p>
<h2>#15 Install multi touch touchpad driver and config</h2>
<p>If you want to make the best of your MacBook touch pad, especially wanting native three-finger drag, visit <a href="https://int3ractive.com/2018/09/make-the-best-of-MacBook-touchpad-on-Ubuntu.html">this article of mine to learn more</a>.</p>
<h2>#16 Install <code>fusehpfs</code> to mount HPFS disk drive from macOS</h2>
<p>If you’re dual-booting Linux and macOS and wanting to mount macOS’ <a href="https://en.wikipedia.org/wiki/High_Performance_File_System">HPFS drive</a>, head to <a href="https://github.com/sgan81/apfs-fuse">this Github repo</a> for instructions to install an APFS FUSE Driver for Linux. Do note that, with this fuse driver, you can only mount the HPFS drive as read-only for now.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Hai ứng dụng của String.prototype.normalize trong tiếng Việt</title>
    <link href="https://int3ractive.com/blog/2019/hai-ung-dung-cua-string-normalize-voi-tieng-viet/"/>
    <updated>2019-07-25T16:43:28Z</updated>
    <id>https://int3ractive.com/blog/2019/hai-ung-dung-cua-string-normalize-voi-tieng-viet/</id>
    <content type="html"><![CDATA[
      <h2>Đôi điều về hai bảng mã Unicode tiếng Việt</h2>
<p>Chắc hẳn khi dùng các công cụ gõ văn bản tiếng Việt (TV), bạn đã từng nghe qua hai bộ mã TV Unicode: <strong>dựng sẵn</strong> và <strong>tổ hợp</strong>.</p>
<p>Để hiểu rõ hơn chúng ta hãy cùng xem xét ký tự TV có dấu đơn giản: <strong>“Ạ”</strong>. Để mã hóa ký tự này, với Unicode dựng sẵn, chúng ta dùng một ký tự có <a href="https://en.wikipedia.org/wiki/Code_point">mã Unicode</a> <code>U+1EA0</code> với tên mô tả tiếng Anh: “LATIN CAPITAL LETTER A WITH DOT BELOW”. Cả chữ A và dấu nặng được dựng sẵn trong một tọa độ mã Unicode (code point). Còn với Unicode tổ hợp, bạn cần hai code point:</p>
<ul>
<li><code>U+0041: LATIN CAPITAL LETTER A</code></li>
<li><code>U+0323: COMBINING DOT BELOW</code></li>
</ul>
<p>Đoạn JavaScript sau sẽ minh họa thêm sự khác nhau giữa 2 cách viết:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> dungSan <span class="token operator">=</span> <span class="token string">'\u1EA0'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> toHop <span class="token operator">=</span> <span class="token string">'\u0041\u0323'</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>dungSan<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "Ạ"</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>toHop<span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">// "Ạ"</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>dungSan<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>toHop<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">// 2</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>dungSan <span class="token operator">==</span> toHop<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span></code></pre>
<blockquote>
<p>Hiện nay, hầu như tất cả các phần mềm bộ gõ tiếng Việt đều sử dụng <strong>bộ mã dựng sẵn</strong> khi người dùng chọn bảng mã Unicode. Trong giao diện cài đặt Unikey cho Window, tại danh sách bảng mã sổ xuống, bạn sẽ thấy 2 lựa chọn: <em>Unicode</em> (ngầm hiểu là dựng sẵn) và <em>Unicode tổ hợp</em>.</p>
</blockquote>
<h2>Hai ứng dụng của <code>String.prototype.normalize</code></h2>
<h3>Ứng dụng 1: So sánh chuỗi tiếng Việt</h3>
<p>Như đã nói ở trên, văn bản tiếng Việt có thể được viết bằng hai bảng mã, và dù về mặt hiển thị ta thấy cùng một chuỗi, nhưng khi so sánh bằng code, hai chuỗi không bằng nhau (<code>&quot;Ạ&quot; != &quot;Ạ&quot;</code>). Do đó, sẽ có nhu cầu “chuẩn hóa” chuỗi văn bản tiếng Việt về một bảng mã thống nhất để dễ dàng so sánh.</p>
<p>Để chuẩn hóa chuỗi tiếng Việt trong ES6+, chúng ta chỉ cần gọi phương thức <code>normalize</code> của string như sau:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> dungSan <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token string">'NFC'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// NFC — Normalization Form Canonical Composition. — Dựng Sẵn (mặc định)</span>
<span class="token keyword">const</span> toHop <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token string">'NFD'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// NFD — Normalization Form Canonical Decomposition. — Tổ Hợp</span></code></pre>
<p>Như vậy, để so sách chuỗi tiếng Việt an toàn, chúng ta sẽ dùng normalize như ví dụ sau:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> str1 <span class="token operator">=</span> <span class="token string">'\u1EA0'</span><span class="token punctuation">;</span> <span class="token comment">// "Ạ"</span>
<span class="token keyword">const</span> str1n <span class="token operator">=</span> str1<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token string">'NFC'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> str2 <span class="token operator">=</span> <span class="token string">'\u0041\u0323'</span><span class="token punctuation">;</span> <span class="token comment">// "Ạ"</span>
<span class="token keyword">const</span> str2n <span class="token operator">=</span> str2<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token string">'NFC'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str1 <span class="token operator">==</span> str2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str1n <span class="token operator">==</span> str2n<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span></code></pre>
<blockquote>
<p>Xem thêm đặc tả của <a href="https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Global_Objects/String/normalize">String.prototype.normalize tại MDN.</a></p>
</blockquote>
<h2>Ứng dụng 2: Gỡ bỏ dấu khỏi chuỗi tiếng Việt và chuyển thành slug</h2>
<p>Trước đây, để bỏ dấu khỏi chuỗi tiếng Việt trong JS, chúng ta cần một bảng tra cứu tất cả các ký tự có dấu, như ví dụ sau:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> str <span class="token operator">=</span> <span class="token string">'Từ Điển Tiếng Việt'</span><span class="token punctuation">;</span>
str <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[aáàảãạâầẩẫậăằẳẵặ]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// tiếp tục cho các nguyên âm còn lại...</span>
<span class="token comment">// và thêm một bảng tương tự nếu cần giữ nguyên hoa thường...</span></code></pre>
<p>Tuy nhiên với <code>normalize</code>, có một thủ thuật khá ngắn gọn để gỡ bỏ dấu TV mà không cần đến bảng tra cứu. Cơ chế của nó là bạn sẽ chuyển chuỗi TV thành định dạng tổ hợp với dấu là các ký tự rời. Các ký tự dấu rời nằm trong một dãy Unicode biết trước có tên <code>Combining Diacritical Marks</code> (\u0300-\u036f) nên chúng ta dễ dàng xóa chúng một cách tổng quát. Cuối cùng, ký tự <strong>“Đ”</strong> là một ký tự độc lập nên cần kiểm tra riêng trường hợp này:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> str <span class="token operator">=</span> <span class="token string">'Từ Điển Tiếng Việt'</span><span class="token punctuation">;</span>

<span class="token comment">// chuyển về dạng tổ hợp</span>
str <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">normalize</span><span class="token punctuation">(</span><span class="token string">'NFD'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// xóa các ký tự dấu tổ hợp</span>
str <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[\u0300-\u036f]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// chuyển chữ đ/Đ thành d/D</span>
str <span class="token operator">=</span> str<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[đĐ]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token parameter">m</span> <span class="token operator">=></span> m <span class="token operator">===</span> <span class="token string">'đ'</span> <span class="token operator">?</span> <span class="token string">'d'</span> <span class="token operator">:</span> <span class="token string">'D'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 'Tu Dien Tieng Viet'</span></code></pre>
<blockquote>
<p>Không phải tôi tự nghĩ ra giải pháp thú vị này, mà tôi đã tình cờ đọc được <a href="https://twitter.com/leaverou/status/934590045708840960?lang=en">tweet này</a> của Lea Verou. Và cũng nhờ nó mà lần đầu tiên tôi biết đến phương thức <code>normalize</code>.</p>
</blockquote>
<p>Việc xóa dấu TV có nhiều mục đích, tuy nhiên phổ biến nhất có lẽ là để chuyển tiêu đề thành <a href="https://en.wikipedia.org/wiki/Clean_URL#Slug">dạng <em>slug</em></a> để tạo URL cho trang web. Sau đây là đoạn CodePen hiện thực phương thức chuyển chuỗi slug tiếng Việt:</p>
<p class="codepen" data-height="344" data-theme-id="0" data-default-tab="js,result" data-user="trongthanh" data-slug-hash="KZQKxr" style="height: 344px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vietnamese Slug Converter with Unicode Normalizer">
  <span>See the Pen <a href="https://codepen.io/trongthanh/pen/KZQKxr/">
  Vietnamese Slug Converter with Unicode Normalizer</a> by Thanh Tran (<a href="https://codepen.io/trongthanh">@trongthanh</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
<p>Trên đây là hai ứng dụng thú vị của <code>String.prototype.normalize</code> với tiếng Việt. Nếu bạn phát hiện ra thêm ứng dụng nào hay ho nữa hay có thắc mắc, hãy để lại comment bên dưới.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Tại sao lại để dư một dấu phẩy</title>
    <link href="https://int3ractive.com/blog/2019/why-trailing-comma-in-js-is-a-good-idea/"/>
    <updated>2019-04-12T07:39:08Z</updated>
    <id>https://int3ractive.com/blog/2019/why-trailing-comma-in-js-is-a-good-idea/</id>
    <content type="html"><![CDATA[
      <h2>Trailing comma là gì? Tại sao nó từng là lỗi trong JavaScript?</h2>
<p>Trailing comma (dấu phẩy đuôi, dấu phẩy cuối) là việc để dư <strong>một dấu phẩy</strong> sau phần tử cuối cùng ở cuối một danh sách. (có thể là phần tử trong Array literal, property trong Object literal, tham số của hàm…). Ví dụ:</p>
<pre class="language-js"><code class="language-js"><span class="highlight-line"><span class="token comment">// trailing comma trong Array literal</span></span>
<span class="highlight-line"><span class="token keyword">var</span> categories <span class="token operator">=</span> <span class="token punctuation">[</span></span>
<span class="highlight-line">  <span class="token string">'men'</span><span class="token punctuation">,</span></span>
<span class="highlight-line">  <span class="token string">'women'</span><span class="token punctuation">,</span></span>
<mark class="highlight-line highlight-line-active">  <span class="token string">'accessories'</span><span class="token punctuation">,</span></mark>
<span class="highlight-line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="highlight-line"><span class="token comment">// trailing comma trong Object literal</span></span>
<span class="highlight-line"><span class="token keyword">var</span> person <span class="token operator">=</span> <span class="token punctuation">{</span></span>
<span class="highlight-line">  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Harry Potter'</span><span class="token punctuation">,</span></span>
<span class="highlight-line">  <span class="token literal-property property">gender</span><span class="token operator">:</span> <span class="token string">'male'</span><span class="token punctuation">,</span></span>
<mark class="highlight-line highlight-line-active">  <span class="token literal-property property">house</span><span class="token operator">:</span> <span class="token string">'Gryffindor'</span><span class="token punctuation">,</span></mark>
<span class="highlight-line"><span class="token punctuation">}</span><span class="token punctuation">;</span></span>
<span class="highlight-line"><span class="token comment">// trailing comma trong tham số của hàm (và trong lời gọi hàm)</span></span>
<span class="highlight-line"><span class="token keyword">function</span> <span class="token function">compare</span><span class="token punctuation">(</span></span>
  <span class="token parameter">param1<span class="token punctuation">,</span>
  param2<span class="token punctuation">,</span></span>
<span class="highlight-line"><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* ... */</span> <span class="token punctuation">}</span></span></code></pre>
<p>Như bạn cũng có thể thấy, dấu phẩy vốn để ngăn cách <strong>giữa</strong> các phần tử trong một danh sách, và dấu phẩy cuối là dư thừa về mặt cú pháp. Để dễ hình dung hơn, ví dụ mảng ở trên nếu viết trên cùng một dòng sẽ là <code>var categories = ['men', 'women', 'accessories',]</code>. Trong thực tế, với các trình duyệt cũ chỉ hỗ trợ <a href="https://int3ractive.com/2019/01/nhung-dieu-can-biet-ve-ecmascript.html">ECMAScript 3</a> trở về trước (IE8), trailing comma sẽ gây ra lỗi cú pháp lúc chạy.</p>
<p><img src="/images/2019/trailing-comma-ie8-error.png" alt="Trailing comma gây ra lỗi cú pháp lúc chạy trên IE8. Hình screenshot lấy từ StackOverflow"><em>Trailing comma gây ra lỗi cú pháp lúc chạy trên IE8. Hình screenshot lấy từ <a href="https://stackoverflow.com/questions/17490014/website-causes-script-error-in-ie8">StackOverflow</a>.</em></p>
<p>Tuy nhiên, kể từ ECMAScript 5, trailing comma được chấp nhận cho danh sách phần tử Array và Object property. Việc lấy số phần tử (<code>array.length</code>) vẫn đúng với Array có trailing comma.</p>
<h2>Tại sao trailing comma trở thành best practice?</h2>
<h3>1. Phần tử khi thêm vào cuối sẽ luôn đồng nhất và tách bạch</h3>
<p>Khi không dùng trailing comma, việc thêm phần tử vào cuối danh sách sẽ gây ảnh hưởng đến phần tử kế cuối vừa được thêm dấu phẩy và commit log của bạn sẽ như thế này:</p>
<pre class="language-diff"><code class="language-diff"><span class="token unchanged"><span class="token prefix unchanged"> </span> var categories = [
<span class="token prefix unchanged"> </span>   'men',
<span class="token prefix unchanged"> </span>   'women',
</span><span class="token deleted-sign deleted"><span class="token prefix deleted">-</span>   'accessories'
</span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span>   'accessories',
<span class="token prefix inserted">+</span>   'children'
</span><span class="token unchanged"><span class="token prefix unchanged"> </span> ];
</span></code></pre>
<p>Khi có trailing comma, commit log của bạn sẽ chỉ hiển thị phần thay đổi:</p>
<pre class="language-diff"><code class="language-diff"><span class="token unchanged"><span class="token prefix unchanged"> </span> var categories = [
<span class="token prefix unchanged"> </span>   'men',
<span class="token prefix unchanged"> </span>   'women',
<span class="token prefix unchanged"> </span>   'accessories',
</span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span>   'children',
</span><span class="token unchanged"><span class="token prefix unchanged"> </span> ];
</span></code></pre>
<h3>2. Dễ dàng sắp xếp lại thứ tự và cập nhật danh sách</h3>
<p>Vì tất cả các phần tử đều kết thúc bằng dấu phẩy, sắp xếp lại thứ tự phần tử bất kỳ đơn giản và dễ dàng:</p>
<p><img src="/images/2019/trailing-comma-reorder.gif" alt="Sắp xếp lại phần tử trong mảng" width="480"><em>Sắp xếp lại phần tử trong mảng</em></p>
<h3>3. Giảm số dòng conflict khi merge với version control</h3>
<p><img src="/images/2019/trailing-comma-conflict.png" alt="Conflict code hiển thị khi không dùng và có dùng trailing comma"><em>Conflict code hiển thị khi không dùng (trên) và có dùng (dưới) trailing comma</em></p>
<p>Trong ví dụ không dùng trailing comma, mặc dù phần tử <code>female</code> đều thêm cùng một dấu phẩy, Git vẫn không tự động merge dòng này và vẫn báo conflict cùng với dòng thay đổi tiếp theo. Việc theo dõi những dòng conflict vô nghĩa này sẽ gây khó khăn cho người merge và rất dễ gây ra sai sót bị mất code sau khi resolve.</p>
<p>Ngoài ra, khi số dòng thay đổi ít đi thì khả năng conflict code sẽ giảm và khả năng code tự merge sẽ cao hơn.</p>
<h2>Sử dụng trailing comma có an toàn?</h2>
<p>Trailing comma chỉ hữu dụng với danh sách trên nhiều dòng, do đó khi danh sách ngắn trên cùng một dòng, bạn không cần để dư dấu phẩy làm gì.</p>
<p>Như đã nói ở trên, trailing comma được chấp nhận kể từ ECMAScript 5 cho Object và Array literal, nên nó khá an toàn cho 2 trường hợp này. Ngoài ra khi được minify, mã nguồn JavaScript cuối cùng sẽ được loại bỏ dấu phẩy dư thừa.</p>
<p>Với danh sách tham số của hàm, nó chỉ mới được chấp nhận trong ES2017. Nếu JS engine chưa hỗ trợ, và khi chạy trực tiếp nó sẽ gây lỗi cú pháp. Cho nên sẽ an toàn hơn nếu code của bạn được biên dịch thông qua Babel và sử dụng <code>preset-env</code>.</p>
<p>Theo kinh nghiệm cá nhân, hiện tôi vẫn tránh dùng trailing comma trong tham số hàm và cũng rất ít khi viết hàm có danh sách tham số quá dài. Thay vào đó, lời khuyên cho bạn là nên dùng object literal để gom danh sách nhiều tham số vào thành một tham số cho hàm, như ví dụ sau:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Thay vì viết hàm nhận nhiều tham số:</span>
<span class="token keyword">function</span> <span class="token function">getDayString</span><span class="token punctuation">(</span><span class="token parameter">lunar<span class="token punctuation">,</span> solarDay<span class="token punctuation">,</span> solarMonth<span class="token punctuation">,</span> solarYear</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* ...*/</span> <span class="token punctuation">}</span>
<span class="token comment">// Nên thay bằng hàm nhận một tham số là object</span>
<span class="token keyword">function</span> <span class="token function">getDayString</span><span class="token punctuation">(</span><span class="token parameter">options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* ...*/</span> <span class="token punctuation">}</span>

<span class="token comment">// Khi đó lúc gọi hàm ta có thể truyền tham số bằng object literal</span>
<span class="token comment">// và sử dụng propety shorthand nếu biến local trùng tên</span>
<span class="token function">getDayString</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  lunar<span class="token punctuation">,</span>
  solarDay<span class="token punctuation">,</span>
  solarMonth<span class="token punctuation">,</span>
  solarYear<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// Bằng việc sử dụng object literal, tham số của hàm giờ đây sẽ tham chiếu theo tên</span>
<span class="token comment">// và không còn phụ thuộc vào thứ tự như với mảng danh sách tham số.</span></code></pre>
<h2>Công cụ hỗ trợ viết code với trailing comma</h2>
<p>Phần này danh cho những ai đã có kinh nghiệm cấu hình code editor nên tôi chỉ viết ngắn gọn:</p>
<h3>ESLint</h3>
<p>Nếu bạn đang sử dụng <strong>eslint</strong>, bạn có thể thêm rule: <a href="https://eslint.org/docs/rules/comma-dangle">comma-dangle</a>. Rule này có thể được áp dụng tùy trường hợp, ví dụ để không áp dụng cho tham số hàm:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"comma-dangle"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"error"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token property">"arrays"</span><span class="token operator">:</span> <span class="token string">"always-multiline"</span><span class="token punctuation">,</span>
    <span class="token property">"objects"</span><span class="token operator">:</span> <span class="token string">"always-multiline"</span><span class="token punctuation">,</span>
    <span class="token property">"imports"</span><span class="token operator">:</span> <span class="token string">"always-multiline"</span><span class="token punctuation">,</span>
    <span class="token property">"exports"</span><span class="token operator">:</span> <span class="token string">"always-multiline"</span><span class="token punctuation">,</span>
    <span class="token property">"functions"</span><span class="token operator">:</span> <span class="token string">"never"</span>
  <span class="token punctuation">}</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre>
<h3>Prettier</h3>
<p>Với prettier, bạn chỉ cần bật option: <a href="https://prettier.io/docs/en/options.html#trailing-commas">trailingComma</a>.</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token comment"># chỉ bật trailing comma cho Array, Object và import</span>
<span class="token key atrule">trailingComma</span><span class="token punctuation">:</span> es5
<span class="token comment"># bật trailing comma cho cả danh sách tham số hàm</span>
<span class="token key atrule">trailingComma</span><span class="token punctuation">:</span> all</code></pre>
<h2>Trường hợp danh sách khai báo biến</h2>
<p>Khi nói về danh sách có dấu phẩy không thể không nhắc đến trường hợp khai báo nhiều biến cùng lúc với một từ khóa <code>var</code> / <code>let</code>. Tuy nhiên với danh sách này, cú pháp JavaScript hiện tại không cho phép trailing comma:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// lỗi cú pháp unexpected token...</span>
<span class="token keyword">var</span> a<span class="token punctuation">,</span>
    b<span class="token punctuation">,</span>
    c<span class="token punctuation">,</span>
    <span class="token punctuation">;</span></code></pre>
<p>Thay vì vậy, từ lâu tôi vẫn áp dụng best practice cho việc khai báo nhiều biến local như sau:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Với danh sách biến không gán giá trị ban đầu,</span>
<span class="token comment">// có thể viết trên cùng một hàng:</span>
<span class="token keyword">var</span> a<span class="token punctuation">,</span> b<span class="token punctuation">,</span> c<span class="token punctuation">,</span> d<span class="token punctuation">,</span> e<span class="token punctuation">;</span>
<span class="token comment">// Với danh sách biến có gán giá trị ban đầu,</span>
<span class="token comment">// luôn luôn xuống dòng và bắt đầu với từ khóa var / let:</span>
<span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> y <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> z <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
<span class="token comment">// Trong mọi trường hợp, nếu muốn việc thêm bớt và sắp xếp biến local</span>
<span class="token comment">// dễ dàng, luôn xuống dòng và bắt đầu từ khóa var / let:</span>
<span class="token keyword">var</span> foo <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> bar <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> baz<span class="token punctuation">;</span></code></pre>
<p>Việc luôn xuống dòng và bắt đầu bằng từ khóa <code>var</code> / <code>let</code> sẽ giúp đạt được những lợi ích như đã liệt kê ở trên với trailing comma.</p>
<h2>Một cách viết danh sách comma khác</h2>
<p>Trước đây, đã từng có một kiểu viết danh sách phần tử trong JavaScript khá thịnh hành, đó là <a href="http://ajaxian.com/archives/is-there-something-to-the-crazy-comma-first-style">“comma first”</a>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> gender <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token string">'men'</span>
  <span class="token punctuation">,</span> <span class="token string">'women'</span>
  <span class="token punctuation">,</span> <span class="token string">'accessories'</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p>Tuy nhiên, đây là cách viết nhiều người (trong đó có tôi) xem là không chuẩn và vẫn bị một hạn chế đó là dòng đầu tiên không đồng nhất (ngược lại với comma last). Và một khi thành thói quen, có thể bạn sẽ để dư thêm dấu phẩy ở dòng đầu tiên và điều này còn nguy hiểm hơn là để dư dấu phẩy cuối.</p>
<h2>Thay lời kết: luôn thêm ký tự xuống dòng cuối file</h2>
<p>Dù không nhìn thấy, các dòng văn bản plain text đều kết thúc bằng ký tự <em>linefeed</em> (<code>\n</code>) đối với Linux &amp; macOS và 2 ký tự <em>carriage return</em> và <em>linefeed</em> (<code>\r\n</code>) trên Windows. Khi người soạn văn bản (hay code) viết đến cuối file và không gõ Enter lần nữa, dòng cuối cùng của file sẽ không kết thúc bởi ký tự xuống dòng. Do đó khi văn bản mới được đánh vào cuối file, dòng cuối cùng của version trước đó sẽ thay đổi trong change log bởi nó vừa được thêm ký tự xuống dòng.</p>
<p>Do đó cùng nguyên tắc như với trailing comma, lời khuyên là luôn chèn ký tự xuống dòng vào cuối file. Và nếu bạn nghĩ mình sẽ quên, các editor phổ biến (VSCode, SublimeText, Atom…) đều có setting <strong>Insert Final Newline</strong> để tự động làm việc này cho bạn.</p>
<p>Nếu team bạn có sử dụng <a href="https://editorconfig.org/">editorconfig</a>, bạn có thể cài đặt rule này: <code>insert_final_newline = true</code> để áp dụng cho cả project.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Common Linux / macOS terminal commands in my handbook</title>
    <link href="https://int3ractive.com/blog/2019/common-linux-macos-commands/"/>
    <updated>2019-01-29T10:12:59Z</updated>
    <id>https://int3ractive.com/blog/2019/common-linux-macos-commands/</id>
    <content type="html"><![CDATA[
      <p>This will be a living reference blog post that I’ll keep updating.</p>
<p>When I started my software engineering career, I was fully immerged with GUI and mouse pointers by the OS and the tooling I used. With irritation at first, I had to self-taught my terminal skills because some of the tasks demanded. However, the more I advanced in my career, the more I see how powerful and convenient CLI (command line interface) can be. Through the years, I had to look up every command that is needed by my job, as a coder, writer, devops and even as casual user, and kept the command usage in a long note. I’m migrating and organizing them here for my own reference as well as may it be useful for other peeps.</p>
<p>Sure you can further look up command usage in <a href="http://cheat.sh/">cheat sheets</a> or Google them up if you know what command to use, but for my younger self as CLI noob, I had no ideas what command to use as well as which tasks are possible on the terminal. Therefore, this mini cheat sheet is how I get on with the CLI bandwagon.</p>
<blockquote>
<p>I’m composing below snippets and headings following <a href="https://devhints.io">devhints.io</a> markdown structure with intention that this may be re-deployed in that format later.</p>
</blockquote>
<p><strong>Note:</strong> these commands of course use Bash or compatible shells (ZSH, fish), which is available as default in Linux and macOS.</p>
<h2>Navigate file systems</h2>
<h3>Display full path of current working directory:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">pwd</span></code></pre>
<h3>List folder content:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># list content of current folder</span>
<span class="token function">ls</span>
<span class="token comment"># list content (even hidden files) of current folder</span>
<span class="token function">ls</span> <span class="token parameter variable">-a</span>
<span class="token comment"># list content of current folder with extra metadata columns</span>
<span class="token function">ls</span> <span class="token parameter variable">-l</span></code></pre>
<p><strong>Note:</strong> The terms <strong>folder</strong> and <strong>directory</strong> are interchangeable.</p>
<h3>Change directory (a.k.a cd):</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># go to a folder with absolute path (start with /)</span>
<span class="token builtin class-name">cd</span> /home/user/documents
<span class="token comment"># go to a child folder from current folder (./ optional)</span>
<span class="token builtin class-name">cd</span> work/projects/client
<span class="token comment"># go to parent folder</span>
<span class="token builtin class-name">cd</span> <span class="token punctuation">..</span>
<span class="token comment"># go to user's home folder (from anywhere)</span>
<span class="token builtin class-name">cd</span> ~</code></pre>
<h3>Display byte size of current directory and sub-directories</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># get size of current and its direct sub-directories</span>
<span class="token function">du</span> <span class="token parameter variable">-chd</span> <span class="token number">1</span>

<span class="token comment"># get size of a single directory</span>
<span class="token function">du</span> <span class="token parameter variable">-sh</span> node_modules/</code></pre>
<ul>
<li><code>-d</code>: max depth (if omitted, display all sub-directories recursively)</li>
<li><code>-h</code>: use human-readable size</li>
<li><code>-s</code>: display only 1 entry for each specified directory</li>
</ul>
<h3>Find files via name:</h3>
<h4>Find files with name in current directory and its children:</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-type</span> f <span class="token parameter variable">-name</span> "postgis-2.0.0”</code></pre>
<p>Type: <code>f</code> (file); <code>d</code> (directory)</p>
<h4>Find all files in a folder with pattern and execute command on it</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-name</span> <span class="token string">'*.js'</span> <span class="token parameter variable">-exec</span> <span class="token punctuation">[</span>command<span class="token punctuation">]</span> <span class="token string">'{}'</span> <span class="token punctuation">\</span><span class="token punctuation">;</span></code></pre>
<p>Note:
<code>{}</code> is the path to the file of each loop entry
<code>\;</code> is the terminate character</p>
<p>Example:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-name</span> <span class="token string">'*.js'</span> <span class="token parameter variable">-exec</span> jscodeshift <span class="token parameter variable">-t</span> migrate-to-modern-1.0.js <span class="token string">'{}'</span> <span class="token punctuation">\</span><span class="token punctuation">;</span></code></pre>
<h4>Find and remove all <code>node_modules</code> folder recursively</h4>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Dry run:</span>
<span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-name</span> <span class="token string">"node_modules"</span> <span class="token parameter variable">-type</span> d <span class="token parameter variable">-exec</span> <span class="token builtin class-name">echo</span> <span class="token string">"{}"</span> +
<span class="token comment"># Do it:</span>
<span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-name</span> <span class="token string">"node_modules"</span> <span class="token parameter variable">-type</span> d <span class="token parameter variable">-exec</span> <span class="token function">rm</span> <span class="token parameter variable">-rf</span> <span class="token string">'{}'</span> +</code></pre>
<h3>Search for pattern in files with <code>grep</code></h3>
<pre><code>grep -rnw '/path/to/somewhere/' -e 'pattern'
</code></pre>
<ul>
<li><code>-r</code> or <code>-R</code> is recursive,</li>
<li><code>-n</code> is line number, and</li>
<li><code>-w</code> stands for match the whole word.</li>
<li><code>-l</code> (lower-case L) can be added to just give the file name of matching files.</li>
</ul>
<p>Along with these, <code>--exclude</code>, <code>--include</code>, <code>--exclude-dir</code> flags could be used for efficient searching:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># This will only search through those files which have .c or .h extensions:</span>
<span class="token function">grep</span> <span class="token parameter variable">--include</span><span class="token operator">=</span><span class="token punctuation">\</span>*.<span class="token punctuation">{</span>c,h<span class="token punctuation">}</span> <span class="token parameter variable">-rnw</span> <span class="token string">'/path/to/somewhere/'</span> <span class="token parameter variable">-e</span> <span class="token string">"pattern"</span>

<span class="token comment"># This will exclude searching all the files ending with .o extension:</span>
<span class="token function">grep</span> <span class="token parameter variable">--exclude</span><span class="token operator">=</span>*.o <span class="token parameter variable">-rnw</span> <span class="token string">'/path/to/somewhere/'</span> <span class="token parameter variable">-e</span> <span class="token string">"pattern"</span>

<span class="token comment"># For directories it's possible to exclude a particular directory(ies) through --exclude-dir parameter. For example, this will exclude the dirs dir1/, dir2/ and all of them matching *.dst/:</span>
<span class="token function">grep</span> --exclude-dir<span class="token operator">=</span><span class="token punctuation">{</span>dir1,dir2,*.dst<span class="token punctuation">}</span> <span class="token parameter variable">-rnw</span> <span class="token string">'/path/to/somewhere/'</span> <span class="token parameter variable">-e</span> <span class="token string">"pattern"</span></code></pre>
<h3>Working with file owner and permission</h3>
<h4>Changing file permissions</h4>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Change permission of a file using octal number</span>
<span class="token function">chmod</span> <span class="token number">600</span> key.pem
<span class="token comment"># (note: don't use same octal number on both files and directories)</span>

<span class="token comment"># Add run (execute) permission to all users</span>
<span class="token function">chmod</span> a+x key.pem

<span class="token comment"># Add write permission to user, remove read permission from group</span>
<span class="token function">chmod</span> u+w,g-r key.pem

<span class="token comment"># Recursively set exact permission</span>
<span class="token function">chmod</span> <span class="token parameter variable">-R</span> <span class="token assign-left variable">u</span><span class="token operator">=</span>r project/</code></pre>
<h4>Changing file owner</h4>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Change owner of files and directories recursively to user:group</span>
<span class="token function">chown</span> <span class="token parameter variable">-R</span> thanh:admin /usr/local/</code></pre>
<p>Note: add <code>sudo</code> if needed.</p>
<h3>Viewing files content:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># print content of a whole file</span>
<span class="token function">cat</span> file.txt

<span class="token comment"># print only the last 20 lines of a text file</span>
<span class="token function">tail</span> <span class="token parameter variable">-n</span> <span class="token number">20</span> errors.log</code></pre>
<h3>Make new files &amp; directories:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Make an empty file</span>
<span class="token function">touch</span> filename

<span class="token comment"># Make a directory</span>
<span class="token function">mkdir</span> src

<span class="token comment"># Make a deeply nested directory and any directories between</span>
<span class="token function">mkdir</span> <span class="token parameter variable">-p</span> project/private/devops/nginx</code></pre>
<h3>Copy and link files</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># copy a file</span>
<span class="token function">cp</span> from/path to/path

<span class="token comment"># create symbolic link</span>
<span class="token function">ln</span> <span class="token parameter variable">-s</span> source_file target_file</code></pre>
<h3>Move files and folders</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Move and rename a file</span>
<span class="token function">mv</span> from_file to_file
<span class="token comment"># Move multiple files to a target directory</span>
<span class="token function">mv</span> file1 file2 file3 directory</code></pre>
<h3>Edit file content:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># edit a file</span>
<span class="token function">vim</span> README.md
<span class="token comment"># Easier editor on Linux</span>
<span class="token function">nano</span> README.md

<span class="token comment"># set content of a file with echo</span>
<span class="token builtin class-name">echo</span> <span class="token string">'hello'</span> <span class="token operator">></span> <span class="token function">file</span>
<span class="token comment"># append some text to an existing file (on new line)</span>
<span class="token builtin class-name">echo</span> <span class="token string">'world'</span> <span class="token operator">>></span> <span class="token function">file</span>

<span class="token comment"># set file content using tee (where sudo is required)</span>
<span class="token builtin class-name">echo</span> <span class="token string">"replication:"</span> <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token function">tee</span> <span class="token parameter variable">-a</span> /etc/mongod.conf
<span class="token comment"># -a is for append</span></code></pre>
<h3>Replace text inline inside a text file:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token function">sed</span> <span class="token parameter variable">-i</span> <span class="token parameter variable">-e</span> <span class="token string">"s/old_text/new_text/g"</span> hello.txt</code></pre>
<ul>
<li><code>-i</code> replace inline</li>
<li><code>-e</code> followed by an expression</li>
<li><code>s/old_text/new_text/g</code> replace string from -&gt; to</li>
</ul>
<h3>Compress and uncompress</h3>
<h4>Unzip (uncompress) .zip archives:</h4>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># unzip and extract to same folder</span>
<span class="token function">unzip</span> file.zip
<span class="token comment"># unzip and extract to another folder</span>
<span class="token function">unzip</span> file.zip <span class="token parameter variable">-d</span> another/folder</code></pre>
<blockquote>
<p>In Ubuntu, if <code>unzip</code> command does not exist, install with <code>sudo apt install unzip</code></p>
</blockquote>
<h4>Compress a whole folder with tar + gzip</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">tar</span> <span class="token parameter variable">-czvf</span> dump.tar.gz dump/</code></pre>
<p>Mnemonic for the command flags <code>-czvf</code> (with some joking): <em><strong>C</strong>ompress <strong>Z</strong>e <strong>V</strong>ucking <strong>F</strong>ile</em></p>
<h4>Uncompress a tar.gz file:</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">tar</span> <span class="token parameter variable">-xzvf</span> dump.tar.gz
<span class="token function">tar</span> <span class="token parameter variable">-xzvf</span> dump.tar.gz <span class="token parameter variable">-C</span> target/folder/</code></pre>
<p>Mnemonic for the command flags <code>-xzvf</code> (with some joking): <em>E<strong>x</strong>tract <strong>Z</strong>e <strong>V</strong>ucking <strong>F</strong>ile</em></p>
<h3>Remove files &amp; directories</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Remove a file</span>
<span class="token function">rm</span> file.txt

<span class="token comment"># Remove a directory</span>
<span class="token function">rm</span> <span class="token parameter variable">-r</span> directory

<span class="token comment"># Remove all html file in current folder</span>
<span class="token function">rm</span> *.html</code></pre>
<ul>
<li><code>-r</code> recursive (required for directory)</li>
<li><code>-f</code> force remove (if files are read-only)</li>
</ul>
<h2>Get server / machine info</h2>
<h3>Monitor system resource and workload with <code>top</code> command:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token function">top</span></code></pre>
<h3>To sort and configure <code>top</code> command</h3>
<h4>In Linux:</h4>
<ul>
<li>Capital <code>P</code> sort by CPU</li>
<li>Capital <code>M</code> sort by Mem</li>
<li><code>c</code> to toggle full command path</li>
<li><code>e</code> to switch memory unit</li>
<li><code>m</code> to switch memory total display</li>
</ul>
<h4>In macOS:</h4>
<ul>
<li>Type <code>o</code>, then key in <code>cpu</code> to sort by CPU</li>
<li>Type <code>o</code>, then key in <code>mem</code> to sort by Memory</li>
</ul>
<h3>Get CPU, memory info (Linux only)</h3>
<pre class="language-shell"><code class="language-shell"><span class="token function">cat</span> /proc/cpuinfo
lscpu

<span class="token function">cat</span> /proc/meminfo</code></pre>
<h3>List all disks on machine (Linux only)</h3>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> lsblk <span class="token parameter variable">-o</span> NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL</code></pre>
<h3>Shows the amount of disk space used and available on current machine</h3>
<pre class="language-shell"><code class="language-shell"><span class="token function">df</span>

<span class="token comment">#With file system type (EXT4, XFS...)</span>
<span class="token function">df</span> <span class="token parameter variable">-Th</span></code></pre>
<h2>Working with remote servers</h2>
<h3>Connect to remote server shell via SSH:</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Connect via provided username and password</span>
<span class="token function">ssh</span> username@hostdomain.com
<span class="token comment"># Connect via secret *.pem key</span>
<span class="token function">ssh</span> username@hostdomain.com <span class="token parameter variable">-i</span> /path/to/key.pem</code></pre>
<p>Note: <code>key.pem</code> must have permission octal less than or equal 600</p>
<h3>Check which distro &amp; distro version</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># try either</span>
<span class="token function">uname</span> <span class="token parameter variable">-r</span>
lsb_release <span class="token parameter variable">-a</span></code></pre>
<h4>For CentOS only:</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">rpm</span> <span class="token parameter variable">--query</span> centos-release</code></pre>
<h3>Copying from and to remote server with <code>scp</code></h3>
<h4>Copy the file “foobar.tgz” from the remote host to current dir in local host</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">scp</span> remote-host:/home/user/foobar.tgz ./</code></pre>
<p><code>remote-host</code> is a pre-configured host name in <code>~/.ssh/config</code></p>
<h4>Copy the file “foobar.tgz” from the local host to a remote host</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">scp</span> <span class="token parameter variable">-i</span> key_file.pem foobar.tgz remote-host:/some/remote/directory</code></pre>
<h4>Copy whole directory from the local host to a remote host</h4>
<pre class="language-shell"><code class="language-shell"><span class="token function">scp</span> <span class="token parameter variable">-r</span> uploads/ remote-host:/some/remote/directory</code></pre>
<p>Result will be new folder copied to <code>/some/remote/directory/uploads</code> at remote.</p>
<h2>Git and file download</h2>
<h3>Some Git tips</h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Check diff change list with a COMMIT hash</span>
<span class="token function">git</span> <span class="token function">diff</span> COMMIT^<span class="token operator">!</span>

<span class="token comment"># Check diff against last change</span>
<span class="token function">git</span> log <span class="token parameter variable">-p</span> <span class="token punctuation">[</span>--follow<span class="token punctuation">]</span> <span class="token punctuation">[</span>-1<span class="token punctuation">]</span> <span class="token operator">&lt;</span>path<span class="token operator">></span>
<span class="token comment"># Use --follow if file renamed</span></code></pre>
<p>More: <a href="https://github.com/trongthanh/dotfiles/blob/master/ubuntu/.git_aliases">git commands and aliases</a>.</p>
<h3>Download files with <code>curl</code></h3>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Download and display file content on terminal</span>
<span class="token function">curl</span> google.com
<span class="token comment"># Download a file and specify a new filename</span>
<span class="token function">curl</span> http://example.com/file.zip <span class="token parameter variable">-o</span> new_file.zip
<span class="token comment"># Download multiple files (and save exact file names from remote)</span>
<span class="token function">curl</span> <span class="token parameter variable">-O</span> URLOfFirstFile <span class="token parameter variable">-O</span> URLOfSecondFile
<span class="token comment"># Download a file and follow redirects</span>
<span class="token function">curl</span> <span class="token parameter variable">-L</span> http://example.com/file
<span class="token comment"># Resume a previously failed download</span>
<span class="token function">curl</span> <span class="token parameter variable">-C</span> - <span class="token parameter variable">-o</span> partial_file.zip http://example.com/file.zip</code></pre>
<h3>Download all URL listed in a text file (each link on a line)</h3>
<pre class="language-shell"><code class="language-shell"><span class="token function">cat</span> photos.txt <span class="token operator">|</span> <span class="token function">xargs</span> <span class="token parameter variable">-n</span> <span class="token number">1</span> <span class="token function">curl</span> <span class="token parameter variable">-LO</span></code></pre>
<h2>Media conversion and manipulation</h2>
<p>More often than not, you’ll have the need to convert or manipulate photos or even videos on the remote server or on your local machine where installing a full GUI software is restricted or too troublesome. Luckily, there are <a href="https://www.imagemagick.org/"><code>imagemagick</code></a> and <code>ffmpeg</code> CLI tools that can help with most media manipulation needs.</p>
<h3>Convert a PNG to ICO to make favicon.ico</h3>
<p>Need to install <a href="https://www.imagemagick.org/"><code>imagemagick</code></a> first:</p>
<pre class="language-shell"><code class="language-shell">convert favicon.png <span class="token parameter variable">-define</span> icon:auto-resize<span class="token operator">=</span><span class="token number">64,48</span>,32,16 favicon.ico</code></pre>
<h3>Convert a PDF to multiple jpg files</h3>
<p>Require <code>imagemagick</code>:</p>
<pre class="language-shell"><code class="language-shell">convert <span class="token parameter variable">-density</span> <span class="token number">300</span> <span class="token parameter variable">-trim</span> test.pdf <span class="token parameter variable">-quality</span> <span class="token number">100</span> test.jpg</code></pre>
<h3>Merge multiple jpg files into one PDF document</h3>
<p>Need <code>imagemagick</code> as well.</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># jpg files are named so that they appear in correct order</span>
convert <span class="token parameter variable">-density</span> <span class="token number">150</span> *.jpg passport.pdf</code></pre>
<h3>Convert mp4 to webm with FFMPEG</h3>
<p><a href="https://gist.github.com/clayton/6196167">https://gist.github.com/clayton/6196167</a></p>
<h3>Convert videos to animated gif with FFMPEG</h3>
<p>To make best looking as well as optimized animated gif, you need to run multiple commands, so save below script as <code>gifmaker.sh</code></p>
<pre class="language-shell"><code class="language-shell"><span class="token shebang important">#!/bin/sh</span>
<span class="token comment"># Usage: ./gifmaker.sh video.mkv anim.gif</span>
<span class="token assign-left variable">palette</span><span class="token operator">=</span><span class="token string">"/tmp/palette.png"</span>

<span class="token assign-left variable">filters</span><span class="token operator">=</span><span class="token string">"fps=15,scale=640:-1:flags=lanczos"</span>

ffmpeg <span class="token parameter variable">-v</span> warning <span class="token parameter variable">-i</span> <span class="token variable">$1</span> <span class="token parameter variable">-vf</span> <span class="token string">"<span class="token variable">$filters</span>,palettegen"</span> <span class="token parameter variable">-y</span> <span class="token variable">$palette</span>
ffmpeg <span class="token parameter variable">-v</span> warning <span class="token parameter variable">-i</span> <span class="token variable">$1</span> <span class="token parameter variable">-i</span> <span class="token variable">$palette</span> <span class="token parameter variable">-lavfi</span> <span class="token string">"<span class="token variable">$filters</span> [x]; [x][1:v] paletteuse"</span> <span class="token parameter variable">-y</span> <span class="token variable">$2</span></code></pre>
<p>Edit <code>fps=15</code> for more or less frame rate; <code>scale=640</code> for larger or smaller size based on max width. Add execution permission to  <code>gifmaker.sh</code>.</p>
<p>The script is thanks to <a href="http://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html">this article on blog.pkh.me</a>.</p>
<h2>Miscellaneous</h2>
<h3>Generate SSH key</h3>
<pre class="language-shell"><code class="language-shell">ssh-keygen <span class="token parameter variable">-t</span> rsa <span class="token parameter variable">-C</span> <span class="token string">"your_email@example.com"</span></code></pre>
<h3>Tunnel MongoDB connection from remote to local</h3>
<pre class="language-shell"><code class="language-shell"><span class="token function">ssh</span> user@host <span class="token parameter variable">-i</span> private-key.pem <span class="token parameter variable">-L</span> <span class="token number">27018</span>:localhost:27017</code></pre>
<p>(27018 is local, 27017 is remote server)</p>
<hr>
<p>That’s it for now. To be updated…</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Những điều cần biết về ECMAScript</title>
    <link href="https://int3ractive.com/blog/2019/nhung-dieu-can-biet-ve-ecmascript/"/>
    <updated>2019-01-16T04:09:09Z</updated>
    <id>https://int3ractive.com/blog/2019/nhung-dieu-can-biet-ve-ecmascript/</id>
    <content type="html"><![CDATA[
      <blockquote>
<p>Lấy cảm hứng từ trang blog mới của Dan Abramov’s <a href="https://overreacted.io">Overreacted.io</a> và từ trang <a href="https://blogs.msdn.microsoft.com/oldnewthing/">the Old New Thing</a> mà chính blog của Dan <a href="https://twitter.com/dan_abramov/status/1069253352180121600">lấy ý tưởng</a>, để mở đầu cho những bài viết của năm 2019, tôi sẽ <strong>viết nhiều hơn về những “câu chuyện mới” từ những điều quen thuộc</strong>, <strong>những câu chuyện “tiểu tiết” nhưng thú vị</strong> về những thứ mà lập trình viên vẫn gặp hằng ngày, hay <strong>những ngóc ngách của kỹ thuật</strong> mà chúng ta vẫn thường dùng nhưng quá bận rộn để tìm hiểu tường tận…</p>
</blockquote>
<p>Để mở đầu chuỗi bài viết này, tôi sẽ bàn về một đặc tả mà chắc các bạn code JavaScript vẫn nghe về nó hằng ngày nhưng tôi dám cá ít bạn biết về cách nó đang vận hành. Đó chính là <strong>ECMAScript</strong>. Bạn có thắc mắc vì sao khi nói đến những cải tiến của JavaScript, người ta thường nói về phiên bản ECMAScript? Hay khi nói về JavaScript hiện đại, người ta thường dùng chữ <strong>ES6+</strong>? Tại sao ECMAScript 6 còn được gọi là ECMAScript 2015?.. Bài viết này sẽ giải đáp những thắc mắc đó của bạn.</p>
<h2>Nguồn gốc ECMAScript</h2>
<p>Để hiểu về ECMAScript chúng ta cần biết chút lịch sử của JavaScript.</p>
<p>JavaScript được sáng tạo bởi <strong>Brendan Eich</strong> (đọc là /aik/) vào năm <strong>1995</strong> chỉ trong <strong>10 ngày</strong> cho trình duyệt lúc bấy giờ là <strong>Nescape Navigator</strong>. Công ty Nescape sau đó vào 1996 đã gửi đặc tả JavaScript lên tổ chức <a href="https://en.wikipedia.org/wiki/Ecma_International">ECMA International</a> để biến nó thành một đặc tả tiêu chuẩn cho các trình duyệt dưới sự bảo hộ của tổ chức ECMA. Ngôn ngữ scripting cho trình duyệt Nescape chính thức trở thành tiêu chuẩn ECMA với phiên bản đầu tiên được xuất bản vào tháng 06 1997 dưới tên mã <strong>ECMA-262</strong>, và JavaScript trở thành hiện thực (implementation) của đặc tả này.</p>
<p>Một điều thú vị với giai đoạn khởi đầu của ECMAScript đó là JavaScript là một cái tên được sở hữu nhãn hiệu (trademarked) bởi Sun Microsystems (cũng là chủ sở hữu của cái tên Java) và chỉ có Nescape mới có quyền sử dụng. Để cạnh tranh, <strong>Internet Explorer 3</strong> của Microsoft cũng hiện thực một ngôn ngữ scripting tương tự, nhưng để tránh rắc rối về quyền nhãn hiệu, phải dùng cái tên là <strong>JScript</strong>. Do đó khi được chuẩn hóa, để đảm bảo ai cũng có thể sử dụng tên của ngôn ngữ lập trình định nghĩa bởi đặc tả ECMA-262, cái tên <strong>ECMAScript</strong> đã được chọn.</p>
<h2>Các phiên bản ECMAScript đầu tiên</h2>
<p>Thời điểm ECMAScript mới được phát hành, bản thân Nescape cũng tiếp tục hiện thực JavaScript và có phiên bản riêng. Cụ thể phiên bản ES đầu tiên tương đương với <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.3"><strong>JavaScript 1.3</strong></a>. <strong>ECMAScript 2</strong> chỉ là phiên bản hiệu chỉnh để tương thích với tiêu chuẩn ISO/IEC 16262. <strong>ECMAScript 3</strong> là phiên bản có một số cải tiến đáng lưu ý như RegularExpression, try/catch… và tương đương với <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.5"><strong>JavaScript 1.5</strong></a> của Nescape Navigator 6.0, Firefox 1.0 và <strong>JScript 5.5</strong> của Internet Explorer 5.5.</p>
<p><strong>ECMAScript 4</strong> với đặc tả nổi bật là class, khai báo kiểu, generator, iterator, và E4X (ECMAScript for XML) đã có sự không đồng thuận giữa hai tổ chức có thị phần trình duyệt lớn nhất lúc bấy giờ là Microsoft và Nescape/Mozilla dẫn đến việc phiên bản này <strong>bị loại bỏ</strong>. Tuy nhiên vẫn có một hiện thực khá nổi tiếng sử dụng đặc tả này đó chính là <strong>ActionScript 3</strong> dành cho Flash.</p>
<p><strong>ECMAScript 5</strong> là phiên bản thay thế ES4, là sự thỏa hiệp của Brendan Eich (lúc này đã là CTO của Mozilla, tổ chức phi lợi nhuận thành lập bởi Nescape và chịu trách nhiệm phát triển trình duyệt nguồn mở Firefox) với các bên phản đối ES4 (trong đó có Yahoo, Microsoft và Google). Những cải tiến trong ES5 không nhiều và vốn ban đầu được Microsoft đưa ra dưới phiên bản đề nghị là <strong>ES3.1</strong>. Một số thay đổi đáng chú ý trong ES5: strict mode, JSON, các phương thức của Object và Array, getter &amp; setter… ES5 được chính thức phát hành vào tháng 12/2009, tương đương với <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.8.5"><strong>JavaScript 1.8.5</strong></a> (Firefox 4, và là phiên bản JavaScript độc lập cuối cùng) và chỉ được hỗ trợ hoàn toàn kể từ Internet Explorer 9. Giai đoạn này cũng đánh dấu sự xuất hiện của Node.js, nền tảng server side thành công nhất của JavaScript.</p>
<p>Phiên bản tiếp theo sau ECMAScript 5 mất một khoảng thời gian dài để hoàn tất. Lúc này Firefox đã chiếm được thị phần đáng kể, IE vẫn chiếm đa số nhưng đang mất dần thị phần và Chrome là anh lính mới nhưng phát triển rất nhanh. JavaScript nhận được sự quan tâm lớn từ xu hướng phát triển web app nặng về phía Front End với cách tiếp cận AJAX. Tiếp theo sau đó là sự nở rộ của các JavaScript frameworks.</p>
<p>Các công ty nắm thị phần trình duyệt đa số đã đạt được sự đồng thuận cao nên dự án cho phiên bản ES tiếp theo được đặt tên là <strong>ECMAScript Harmony</strong>. ECMAScript Harmony cũng đánh dấu quy trình làm việc mới của tiểu ban ECMA <strong>TC39</strong> (Technical Committee 39) với các đặc tả mới được tiến hành <strong>hoàn thiện theo module</strong> và <strong>chuẩn hóa qua 5 bước</strong> (tương tự quy trình của W3C cho các module của HTML &amp; CSS).</p>
<h2>ECMAScript 6 (ECMAScript 2015)</h2>
<p>Các đặc tả của ES6 được khóa sổ vào tháng 6 2015 và phiên bản ES được đổi từ số thứ tự thành năm phát hành, <strong>ECMAScript 2015</strong>. Đây là phiên bản có rất nhiều cải tiến về cú pháp khiến cho JavaScript gần như lột xác hoàn toàn.</p>
<p>Một số đặc tả mới đáng chú ý (không phải tất cả):</p>
<ul>
<li>class và public method</li>
<li>block scope và từ khóa <code>let</code>, <code>const</code></li>
<li>arrow function</li>
<li>template string</li>
<li>generator và iterator</li>
<li>Promise</li>
<li>destructuring assignment</li>
<li>module (còn gọi là ECMAScript module / esm)</li>
<li>…</li>
</ul>
<p>Với nhiều cú pháp không tương thích cho trình duyệt cũ, ES6 cũng đánh dấu sự phát triển của xu hướng viết JavaScript hiện đại và biên dịch thành JavaScript cũ với trình biên dịch nổi bật nhất là <strong>6to5</strong> mà sau này được biết đến với cái tên <a href="https://github.com/babel/babel"><strong>Babel</strong></a>.</p>
<p>Hiện nay các trình duyệt hiện đại đều đã <a href="http://kangax.github.io/compat-table/es6/">hỗ trợ hết các đặc tả ES6</a> trong đó có: Chrome, Firefox, Safari, MS Edge. Phiên bản cuối cùng của IE, IE11 chỉ hỗ trợ một vài đặc tính của ES6. Node.js hỗ trợ hoàn toàn ES6 (trừ module) từ phiên bản 6.0.</p>
<h2>ECMAScript Next và quy trình 5 bước</h2>
<p>Kể từ ES2015, các phiên bản ECMAScript tiếp theo được phát hành định kỳ hằng năm, tập hợp những module đã được hoàn thiện qua <a href="http://2ality.com/2015/11/tc39-process.html">quy trình 5 bước</a>:</p>
<ul>
<li><strong>Stage 0 strawman</strong>: Ý tưởng cho ES mới được đệ lên TC39 bởi thành viên hoặc TC39 contributor. Những ý tưởng này rất thô nhám và hoàn toàn có thể bị loại bỏ, không được hiện thực.</li>
<li><strong>Stage 1 proposal</strong>: Được sự đồng thuận bởi các thành viên TC39, ý tưởng ở stage 0 trở thành <em>đặc tả đề nghị</em>. Một thành viên của TC39 được phân làm người chịu trách nhiệm chính (champion). Đặc tả stage 1 phải có các tài liệu mô tả API, ví dụ và đôi khi là có sẵn polyfill.</li>
<li><strong>Stage 2 draft</strong>: Đặc tả mới phải được định nghĩa đầy đủ như trong <em>văn bản đặc tả chính thức</em> (ECMAScript specification). Phải có hiện thực thử nghiệm bởi các JavaScript engine hoặc biên dịch thông qua Babel. Đến bước này, đặc tả đã có nhiều khả năng thành tiêu chuẩn và chỉ cho phép những thay đổi nhỏ.</li>
<li><strong>Stage 3 candidate</strong>: Đặc tả gần như hoàn thiện. Phải có ít nhất 02 hiện thực thử nghiệm từ các trình duyệt hoặc JavaScript engine (có thể nằm phía sau cờ config). Đặc tả được lấy đánh giá từ người dùng thông qua hiện thực thử nghiệm và cuối cùng phải được xem xét và duyệt bởi các thành viên khác của TC39.</li>
<li><strong>Stage 4 finished</strong>: Đặc tả đã trở thành tiêu chuẩn ECMAScript. Acceptance test trong bộ “Test 262” cho đặc tả phải được viết ra. Người <em>biên tập viên ECMAScript</em> phải ký duyệt để đặc tả trở thành tiêu chuẩn ECMA và đặc tả mới sẽ được chỉ định cho phiên bản ECMAScript tiếp theo gần nhất.</li>
</ul>
<p>Với quy trình hoàn thiện dần theo module như trên, có thể thấy ECMAScript trở thành tiêu chuẩn tiến hóa liên tục. Các phiên bản ES sau ES6/ES2015 có ít đặc tả mới hơn trong từng phiên bản. Việc gọi ES với phiên bản tăng dần không còn mấy ý nghĩa. Qua đó ta cũng thấy lý do phiên bản ES bây giờ được đặt theo năm phát hành.</p>
<p>Phiên bản ECMAScript mới nhất tại thời điểm tôi viết bài này là ECMAScript 2018.</p>
<h2>Hiểu biết về ECMAScript giúp cài đặt Babel hợp lý hơn:</h2>
<p>Sự phổ biến của việc dùng Babel để biên dịch các cú pháp ES mới và một số boilerplate / starter-kit lạm dụng Babel stage preset (<code>@babel/preset-stage-#</code>) khiến cho các lập trình viên hay nhầm lẫn các đặc tả chuẩn và thử nghiệm của JavaScript. Bản thân tôi cũng từng nhầm lẫn.</p>
<p>Theo quan sát của tôi khi làm việc với React, có 2 đặc tả hay bị nhầm thuộc ES6 đó là: <a href="https://github.com/tc39/proposal-object-rest-spread"><code>object spread</code></a> và <a href="https://github.com/tc39/proposal-class-fields"><code>class field</code></a>.</p>
<p>Object spread được phổ biến nhờ JSX và Redux reducer:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token comment">// property spread để truyền tự động props từ component cha sang con</span>
<span class="token keyword">const</span> <span class="token function-variable function">Container</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Child</span></span> <span class="token spread"><span class="token punctuation">{</span><span class="token operator">...</span>props<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Redux reducer là pure function:</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">reducer</span><span class="token punctuation">(</span><span class="token parameter">state <span class="token operator">=</span> defaultState<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token constant">SOME_TYPE</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span>state<span class="token punctuation">,</span> <span class="token operator">...</span>action<span class="token punctuation">.</span>payload <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token keyword">default</span><span class="token operator">:</span>
      <span class="token keyword">return</span> state<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Nhiều bạn vẫn nhầm lẫn đây là một đặc tả của ES6 bởi ES6 đã có rest và spread cho Array. Nhưng <strong>object spread chỉ thành đặc tả chính thức trong <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Specifications">ES2018</a></strong>.</p>
<p>Một cú pháp thường được sử dụng để khởi tạo property và auto-bind các method của React class component đó là class (public) fields:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">class</span> <span class="token class-name">MyComponent</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span>
  <span class="token comment">// class property khởi tạo state</span>
  state <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">counter</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token comment">// class property và arrow function cho phép this luôn được bind với instance của MyComponent</span>
  <span class="token function-variable function">onIncrement</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">counter</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>counter <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onIncrement<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Đây là một đặc tả được review khá chậm và kỹ lưỡng, và tại thời điểm viết bài này, nó vẫn đang ở <a href="https://github.com/tc39/proposal-class-fields">stage 3</a>. Vì đây là đặc tả mở rộng trên đặc tả class của ES6, trong khi các boilerplate lại hay sử dụng preset-stage-0, nhiều dev sử dụng class field vẫn không biết rằng đây vẫn là đặc tả chưa hoàn tất.</p>
<p>Để tránh những nhầm lẫn ở trên cũng như tránh cho dev lạm dụng những cú pháp thử nghiệm mà không có nhận thức về tiêu chuẩn ES, Babel 7.0 đã <a href="https://babeljs.io/blog/2018/07/27/removing-babels-stage-presets">chính thức khuyến cáo</a> và sẽ từ bỏ stage preset trong thời gian tới. Thay vào đó, Babel 7 khuyến khích bạn sử dụng <a href="https://babeljs.io/docs/en/babel-preset-env">@babel/preset-env</a> cho phép lập trình viên <strong>sử dụng cú pháp đã trở thành chuẩn ES vào thời điểm hiện tại</strong>. Và nếu muốn sử dụng những cú pháp thử nghiệm (stage &lt;4), bạn phải khai báo tường minh plugin của Babel cho đặc tả đó. Cụ thể với <em>class field</em>, bạn phải thêm plugin <a href="https://babeljs.io/docs/en/babel-plugin-syntax-class-properties"><code>babel-plugin-syntax-class-properties</code></a> vào <code>package.json</code> và <code>.babelrc</code>.</p>
<h2>Một vài chuyện bên lề thú vị khác về JavaScript và ECMAScript</h2>
<p>JavaScript ban đầu được đặt tên là <strong>Mocha</strong>, sau đó trong giai đoạn beta được đổi tên thành <strong>LiveScript</strong>. Tuy nhiên lúc phát hành chính thức, lại được đổi thành <strong>JavaScript</strong> với mục đích marketing và để ăn theo ngôn ngữ lập trình hiện đại đang nổi lúc bấy giờ là Java. Việc Nescape sử dụng tên JavaScript phải được sự đồng ý của Sun Microsystems, chủ sở hữu của Java và <strong>Sun giữ quyền sở hữu nhãn hiệu với JavaScript™</strong>.</p>
<p>Sau khi mua lại Sun Microsystems, <strong>Oracle</strong> hiển nhiên trở thành chủ sở hữu của Java và nhãn hiệu JavaScript™. Mozilla (công ty kế tục của Nescape) đã có thỏa thuận đặc biệt từ trước với Sun, và vẫn tiếp tục với Oracle, được quyền sử dụng miễn phí vô thời hạn nhãn hiệu JavaScript™. Tuy nhiên, bất kỳ tổ chức, hay cá nhân nào khác muốn thương mại hóa JavaScript™ phải được phép và phải trả phí sử dụng cho Oracle. Vì vậy bạn để ý sẽ thấy các conference về JavaScript không bao giờ dùng chữ JavaScript mà chỉ viết tắt <strong>JS</strong>. Năm ngoái đã có một app <a href="https://www.techrepublic.com/article/why-its-finally-time-to-give-up-on-the-name-javascript/">bị từ chối cho lên iOS app store</a> vì trong tựa app có chữ JavaScript!</p>
<p><strong>TypeScript</strong>, phát triển bởi Microsoft, một ngôn ngữ biên-dịch-sang-JavaScript, không phải là ngôn ngữ theo tiêu chuẩn ECMAScript. Mặc dù TypeScript hỗ trợ hoàn toàn các cú pháp của ES, TS có nhiều cú pháp bên ngoài ES chẳng hạn như decorators, interface, và đặc biệt là khai báo kiểu (mặc dù đã xuất hiện trong ES4, cho đến hiện tại khai báo kiểu vẫn không được TC39 xem xét ở bất cứ stage nào)… Dù vẫn mang tiếng là ngôn ngữ viết để biên dịch, TypeScript đã trở thành ngôn ngữ chính thức cho server side platform mới có tên <a href="https://github.com/denoland/deno">Deno</a> được viết bởi chính tác giả của Node.js.</p>
<h2>Lời kết</h2>
<p>Những đặc tả mới của ECMAScript luôn hướng đến việc giúp cho công việc của lập trình viên dễ dàng hơn. Nếu bạn đang có ý định phát triển thư viện hoặc framework trên JavaScript, hiểu biết về ECMAScript là rất cần thiết để cân nhắc những cú pháp mới cho thư viện của mình, ví dụ: Koa framework, Redux Saga tận dụng generator; GraphQL, styled-components tận dụng tagged template string…</p>
<p>Nếu quan tâm đến các cú pháp và tính năng mới đang trong giai đoạn hoàn thiện, bạn có thể tham khảo <a href="https://github.com/tc39/proposals">danh sách các đặc tả đề nghị</a> và <a href="https://github.com/tc39/proposals/blob/master/finished-proposals.md">danh sách các đặc tả đã sẵn sàng</a> của TC39 tại Github. Nếu bạn muốn tham khảo cách dùng một cú pháp cụ thể, nơi tham khảo tin cậy nhất chính là <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">tài liệu MDN của Mozilla</a>. Để biết có những đặc tả mới nào trong một phiên bản cụ thể, VD: ES2016, ES2017… bạn có thể google những bài blog tổng hợp.</p>
<p>Cuối cùng, nếu bạn có thắc mắc hay muốn trao đổi thêm, bạn có thể để lại comment bên dưới bài viết này.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Hướng dẫn: Cài đặt hoàn chỉnh Nodejs app lên VPS Ubuntu - Phần 2</title>
    <link href="https://int3ractive.com/blog/2018/huong-dan-cai-dat-nodejs-app-len-vps-phan-2/"/>
    <updated>2018-09-26T16:14:10Z</updated>
    <id>https://int3ractive.com/blog/2018/huong-dan-cai-dat-nodejs-app-len-vps-phan-2/</id>
    <content type="html"><![CDATA[
      <p>Tóm tắt <a href="https://int3ractive.com/2017/09/huong-dan-cai-dat-nodejs-app-len-vps-phan-1.html">phần 1</a>:</p>
<ul>
<li>Bạn đã cài các phần mềm cần thiết để chạy app: NodeJS, MongoDB, Nginx, Git.</li>
<li>App deploy bằng source từ Git host, và clone về tại <code>/apps/my-node-app</code></li>
<li>App đã được build và chạy tại port 3000 của server</li>
</ul>
<h2>Hạn chế quyền truy cập của app</h2>
<p>Đây là bước không bắt buộc, tuy nhiên tôi khuyến cáo không nên bỏ qua, nhất là bạn đang truy cập vào VPS bằng tài khoản root. Chúng ta sẽ tạo một Linux user mới và gán cho thư mục của app.</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Tạo một Linux user mới, nên dùng tên của app và không để khoảng trắng</span>
<span class="token function">sudo</span> <span class="token function">useradd</span> my-node-app
<span class="token comment"># Chuyển quyền sở hữu (owner) thư mục app và các thư mục con cho user mới</span>
<span class="token function">sudo</span> <span class="token function">chown</span> <span class="token parameter variable">-R</span> my-node-app /apps/my-node-app</code></pre>
<p>Trong bước tiếp theo, khi chạy app như dịch vụ, app sẽ được chạy với quyền của user mới này để hạn chế quyền truy cập của app lên các thư mục hệ thống.</p>
<h2>Chạy app như dịch vụ</h2>
<p>Tiếp theo chúng ta sẽ cài đặt để chạy app như dịch vụ và tự động chạy lại khi server được restart. Có một số tutorial hướng dẫn chạy app với <a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04"><strong>pm2</strong></a>, nhưng hôm nay tôi sẽ hướng dẫn dùng công cụ quản lý ứng dụng dịch vụ <strong>systemd</strong> trên Ubuntu 16 và các HĐH Linux mới.</p>
<p>Đầu tiên, chúng ta sẽ chạy một số lệnh để lấy thông tin cho config systemd:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Lấy đường dẫn tuyệt đối đến node VM</span>
<span class="token function">which</span> <span class="token function">node</span>
<span class="token comment"># -> /usr/bin/node</span>

<span class="token comment"># Lấy đường dẫn tuyệt đối đến thư mục của app</span>
<span class="token builtin class-name">pwd</span>
<span class="token comment"># -> /apps/my-node-app</span>

<span class="token comment"># Lấy thông tin user hiện tại (bỏ qua nếu chúng ta đã tạo user ở trên)</span>
<span class="token function">id</span>
<span class="token comment"># -> uid=0(root) gid=0(root) groups=0(root)</span></code></pre>
<p>Tiếp theo, tạo file service config cho systemd:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">nano</span> /etc/systemd/system/my-node-app.service</code></pre>
<ul>
<li><code>nano</code> là editor trên terminal dễ dùng nhất. Bạn có thể thay <code>nano</code> bằng <code>vim</code> nếu nó là editor quen thuộc với bạn hơn.</li>
<li>Tên file <code>my-node-app.service</code> là do bạn đặt nhưng cần giữ nguyên đuôi <code>.service</code></li>
</ul>
<p>Paste vào editor nội dung sau:</p>
<pre class="language-ini"><code class="language-ini"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Unit</span><span class="token punctuation">]</span></span>
<span class="token key attr-name">Description</span><span class="token punctuation">=</span><span class="token value attr-value">Thay bằng nội dung mô tả app của bạn</span>
<span class="token key attr-name">Requires</span><span class="token punctuation">=</span><span class="token value attr-value">mongod.service</span>
<span class="token key attr-name">After</span><span class="token punctuation">=</span><span class="token value attr-value">mongod.service</span>

<span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Service</span><span class="token punctuation">]</span></span>
<span class="token key attr-name">ExecStart</span><span class="token punctuation">=</span><span class="token value attr-value">/usr/bin/node /apps/my-node-app/keystone.js</span>
<span class="token key attr-name">WorkingDirectory</span><span class="token punctuation">=</span><span class="token value attr-value">/apps/my-node-app</span>
<span class="token key attr-name">Restart</span><span class="token punctuation">=</span><span class="token value attr-value">always</span>
<span class="token key attr-name">StandardOutput</span><span class="token punctuation">=</span><span class="token value attr-value">syslog</span>
<span class="token key attr-name">StandardError</span><span class="token punctuation">=</span><span class="token value attr-value">syslog</span>
<span class="token key attr-name">SyslogIdentifier</span><span class="token punctuation">=</span><span class="token value attr-value">my-node-app</span>
<span class="token key attr-name">User</span><span class="token punctuation">=</span><span class="token value attr-value">my-node-app</span>
<span class="token key attr-name">Group</span><span class="token punctuation">=</span><span class="token value attr-value">my-node-app</span>
<span class="token key attr-name">Environment</span><span class="token punctuation">=</span><span class="token value attr-value">PORT=3000</span>
<span class="token key attr-name">Environment</span><span class="token punctuation">=</span><span class="token value attr-value">MONGO_URL=mongodb://localhost:27017/my-node-app</span>

<span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">Install</span><span class="token punctuation">]</span></span>
<span class="token key attr-name">WantedBy</span><span class="token punctuation">=</span><span class="token value attr-value">multi-user.target</span></code></pre>
<p>Một vài điều lưu ý khi chỉnh sửa file .service trên:</p>
<ul>
<li>Hai thuộc tính <code>Requires</code> và <code>After</code> để cho systemd biết chỉ kích hoạt dịch vụ này khi service chỉ định tại <code>Requires</code> và <code>After</code> đã được chạy (Trong trường hợp server phải restart và có rất nhiều service cần chạy lúc khởi động). Trong ví dụ này, <code>mongod.service</code> là tên service của MongoDB khi được cài như hướng dẫn trong phần một.</li>
<li><code>ExecStart</code> là nơi thực thi lệnh cho dịch vụ, và yêu cầu đường dẫn phải tuyệt đối.</li>
<li><code>WorkingDirectory</code> là thư mục ngữ cảnh khi lệnh được thực thi.</li>
<li><code>SyslogIdentifier</code> là tên định danh của dịch vụ trong logger hệ thống, chúng ta sẽ dùng nó để lọc các output hoặc báo lỗi của app như trong phần tiếp theo.</li>
<li><code>User</code> và <code>Group</code> là tên của Linux user mà chúng ta muốn app sử dụng khi chạy. Như đã nói ở trên, bạn có thể dùng user mới tạo là <code>my-node-app</code> hoặc tên của user trả về ở dòng lệnh <code>id</code>.</li>
<li><code>Environment</code> là nơi để bạn gán các biến môi trường lúc thực thi app. Với Keystonejs thì có thể bạn không cần sử dụng thuộc tính này vì nó sử dụng <code>.env</code> (dotenv).</li>
<li>Những thuộc tính còn lại nên để giá trị như ví dụ.</li>
</ul>
<p>Sau khi bạn đã tạo xong file .service, bạn có thể thử chạy app ngay thông qua lệnh sau:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Bắt đầu chạy app như dịch vụ (không cần đường dẫn đến file .service)</span>
<span class="token function">sudo</span> systemctl start my-node-app.service

<span class="token comment"># Kiểm tra trạng thái app đang chạy hay không</span>
<span class="token function">sudo</span> systemctl status my-node-app.service
<span class="token comment"># -> Nếu app chạy thành công, output sẽ có dòng: ...Active: active (running)...</span></code></pre>
<p>Cuối cùng, sau khi app đã được chạy thành công và bạn có thể vào qua port 3000, bật chức năng dịch vụ tự khởi động khi server được restart:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> my-node-app.service
<span class="token comment"># -> Created symlink from ... to ...</span></code></pre>
<h2>Proxy app ra cổng 80 bằng NGINX</h2>
<p><strong>Nginx</strong> sẽ đóng vai trò <em>reversed proxy</em> và <em>static file server</em>. Nó sẽ tiếp nhận request từ ngoài Internet thông qua port mặc định 80 (http) và 443 (https) và forward request qua port của app là 3000.</p>
<p>Đối với Ubuntu[^1], 2 file config chính của Nginx nằm ở: <code>/etc/nginx/nginx.conf</code> (config toàn server) và <code>/etc/nginx/sites-available/default</code> (config cho từng web host ảo[^2]).</p>
<p>Bước này yêu cầu bạn đã cấu hình DNS của domain trỏ đến địa chỉ IP tĩnh của VPS (VD: <a href="http://mynodeapp.com">mynodeapp.com</a>). Sau đó bạn vào chỉnh sửa file <code>/etc/nginx/sites-available/default</code>, thay toàn bộ nội dung mặc định bằng mẫu bên dưới.</p>
<pre class="language-nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">{</span>
    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span> default_server</span><span class="token punctuation">;</span>
    <span class="token directive"><span class="token keyword">listen</span> [::]:80 default_server</span><span class="token punctuation">;</span>

    <span class="token comment"># File mặc định khi vào thư mục</span>
    <span class="token directive"><span class="token keyword">index</span> index.html index.htm</span><span class="token punctuation">;</span>

    <span class="token comment"># Điều chỉnh kích thước gói upload tối đa</span>
    <span class="token directive"><span class="token keyword">client_max_body_size</span> <span class="token number">25M</span></span><span class="token punctuation">;</span>

    <span class="token comment"># Domain name của web app, có thể một hoặc nhiều domain cùng trỏ đến</span>
    <span class="token directive"><span class="token keyword">server_name</span> mynodeapp.com www.mynodeapp.com</span><span class="token punctuation">;</span>

    <span class="token comment"># Forward toàn bộ request sang web app</span>
    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">{</span>
        <span class="token comment"># Thay đổi port nếu node-web-app chạy trên port khác 3000</span>
        <span class="token directive"><span class="token keyword">proxy_pass</span> http://127.0.0.1:3000</span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">proxy_http_version</span> 1.1</span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">proxy_set_header</span> Upgrade <span class="token variable">$http_upgrade</span></span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">proxy_set_header</span> Connection <span class="token string">'upgrade'</span></span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">proxy_set_header</span> Host <span class="token variable">$host</span></span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">proxy_cache_bypass</span> <span class="token variable">$http_upgrade</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Nếu muốn dùng cùng config cho nhiều web host ảo, bạn có thể chuyển một số directive ở trên như <code>index</code>, <code>client_max_body_size</code> vào trong config toàn server tại <code>/etc/nginx/nginx.conf</code>.</p>
<p>Sau khi chỉnh sửa xong Nginx config như trên. Bạn có thể thử kiểm tra config mới có hợp lệ hay không bằng lệnh:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> nginx <span class="token parameter variable">-t</span>
<span class="token comment"># -> nginx: the configuration file /etc/nginx/nginx.conf syntax is ok</span>
<span class="token comment"># -> nginx: configuration file /etc/nginx/nginx.conf test is successful</span></code></pre>
<p>Nếu config mới OK, bạn khởi động lại Nginx bằng lệnh sau:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> systemctl restart nginx</code></pre>
<p>Sau khi Nginx được restart, bạn vào thử website tại domain đã cài đặt ở trên với URL không thêm port (<a href="http://my-node-app.com">http://my-node-app.com</a>). Nếu website hiện ra thì bạn đã cài đặt thành công. Nếu bạn thấy lỗi “Bad Gateway”, tức là cấu hình Nginx vừa rồi chưa thành công và cần phải rà soát lại.</p>
<h2>Serve file tĩnh bằng NGINX</h2>
<p>Một trong những lý do tôi hướng dẫn bạn sử dụng Nginx, ngoài việc để bật https, còn là để serve file tĩnh (static file) hiệu quả hơn. Nếu như các file tĩnh của web app được thiết kế sử dụng CDN thì bạn có thể không cần bước này.</p>
<p>Nginx serve file tĩnh cực nhanh với lượng kết nối đồng thời cao (concurrency). Việc bật header <code>cache-ontrol</code> với Nginx rất dễ dàng sẽ giúp tăng hiệu quả tải trang. Ngoài ra bạn còn có thể bật <strong>gzip</strong> khi serve file tĩnh, là một yêu cầu không thể thiếu khi tối ưu hóa việc tải trang từ phía server.</p>
<p>Để serve file tĩnh, chúng ta sẽ thêm bộ lọc <code>location</code> vào block <code>server</code> của host config ở trên. Đối với KeystoneJS, chúng ta có một thư mục file tĩnh mặc định đó là <code>public</code> và với ví dụ từ đầu đến giờ, đường dẫn đến thư mục này sẽ là <code>/apps/my-node-app/public</code>. Ngoài ra, nếu bạn có một thư mục để upload riêng và nằm ngoài thư mục public này, thì bạn cũng cần ghi lại đường dẫn để config như tiếp theo sau đây:</p>
<pre class="language-nginx"><code class="language-nginx"><span class="token comment"># thêm directive location trong config /etc/nginx/sites-available/default</span>
<span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">{</span>
    <span class="token comment"># ...Các config khác đã ẩn...</span>

    <span class="token comment"># Hướng dẫn cho Nginx serve tĩnh các file và folder bên trong public,</span>
    <span class="token comment"># có tên bắt đầu bằng một trong những pattern như bên dưới</span>
    <span class="token directive"><span class="token keyword">location</span> ~ ^/(fonts/|images/|javascript/|js/|script/|css/|stylesheets/|flash/|media/|static/|upload/|robots.txt|humans.txt|favicon.ico)</span> <span class="token punctuation">{</span>
        <span class="token comment"># đường dẫn tuyệt đối đến thư mục file tĩnh</span>
        <span class="token directive"><span class="token keyword">root</span> /apps/my-node-app/public</span><span class="token punctuation">;</span>
        <span class="token directive"><span class="token keyword">access_log</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>
        <span class="token comment"># bật cache-control lên với thời gian expire tối đa</span>
        <span class="token directive"><span class="token keyword">expires</span> max</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>

	<span class="token comment"># Nếu bạn có thư mục upload bên ngoài, bạn cần thêm một directive `location` đến thư mục này</span>
	<span class="token comment"># Xem document của Nginx để biết thêm cách cấu hình location</span>

    <span class="token comment"># Đặt directive location / (app reversed proxy) ở dưới cùng</span>
    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">{</span>
        <span class="token comment"># ...</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Một vài vấn đề có thể gặp với việc serve file tĩnh bằng Nginx:</p>
<ul>
<li>Nếu bạn bị lỗi 403 Forbidden: khả năng là Nginx chưa có quyền truy cập thư mục của app. Bạn cần thêm quyền truy cập cho thư mục <code>public</code> bằng lệnh <code>sudo chmod o+rx -R public</code>.</li>
</ul>
<p>Để bật gzip, bạn có thể vào file <code>/etc/nginx/nginx.conf</code>, và bỏ comment (dấu #) ở những dòng config gzip như bên dưới:</p>
<pre class="language-nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">http</span></span> <span class="token punctuation">{</span>
    <span class="token comment"># ...Các config khác đã ẩn...</span>

    <span class="token comment">##</span>
    <span class="token comment"># Gzip Settings</span>
    <span class="token comment">##</span>

    <span class="token directive"><span class="token keyword">gzip</span> <span class="token boolean">on</span></span><span class="token punctuation">;</span>
    <span class="token directive"><span class="token keyword">gzip_disable</span> <span class="token string">"msie6"</span></span><span class="token punctuation">;</span>

    <span class="token directive"><span class="token keyword">gzip_vary</span> <span class="token boolean">on</span></span><span class="token punctuation">;</span>
    <span class="token directive"><span class="token keyword">gzip_proxied</span> any</span><span class="token punctuation">;</span>
    <span class="token comment"># gzip_comp_level 6;</span>
    <span class="token comment"># gzip_buffers 16 8k;</span>
    <span class="token comment"># gzip_http_version 1.1;</span>
    <span class="token directive"><span class="token keyword">gzip_types</span> text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Trong danh sách các loại file tĩnh được nén với gzip ở trên (<code>gzip_types</code>), tôi đã thêm SVG. Bạn có thể thêm các loại file khác nếu danh sách chưa có, nhưng không nên thêm các file ảnh bởi chúng đã được nén bằng thuật toán riêng và sẽ không hiệu quả khi nén tiếp với gzip.</p>
<h2>Lấy chữ ký số từ Let’s Encrypt và cài đặt cho NGINX</h2>
<p>Để một trang web được mã hóa an toàn thông qua giao thức HTTPS, bạn cần một chứng thư số (certificate) TLS/SSL để chứng thực cho những domain mà bạn sử dụng. TLS/SSL certificate phải được ký bởi một CA (Certificate Authority) hợp lệ, và trước đây chúng ta phải trả một khoản phí để đăng ký với CA. Tuy nhiên, từ bây giờ chúng ta đã có thêm <a href="https://letsencrypt.org/">Let’s Encrypt</a> là một CA cung cấp TLS/SSL certificate hoàn toàn miễn phí.</p>
<p>Có nhiều cách để cài đặt certificate Let’s Encrypt nhưng đơn giản nhất trên Linux kết hợp với Nginx là sử dụng công cụ dòng lệnh <a href="https://certbot.eff.org/lets-encrypt/ubuntuxenial-nginx">Certbot</a>. Ở đây tôi sẽ tóm tắt các bước cần thực hiện:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Chạy các lệnh sau để cài đặt lệnh certbot kèm plugin Nginx trên Ubuntu</span>
<span class="token function">sudo</span> <span class="token function">apt-get</span> update
<span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> software-properties-common
<span class="token function">sudo</span> add-apt-repository ppa:certbot/certbot
<span class="token function">sudo</span> <span class="token function">apt-get</span> update
<span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> python-certbot-nginx</code></pre>
<p>Sau khi <strong>certbot</strong> được cài, bạn có thể chạy lệnh sau để bắt đầu tiến trình cài đặt certificate cho website với Nginx plugin:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> certbot <span class="token parameter variable">--nginx</span></code></pre>
<p>Sau khi gọi lệnh trên, bạn sẽ nhập thông tin theo yêu cầu:</p>
<ul>
<li>Đầu tiên, certbot sẽ đọc Nginx config và liệt kê các tên miền hiện có. Bạn sẽ nhập vào con số gắn với tên miền (1, 2…) hoặc Enter bỏ trống để chọn tất cả.</li>
<li>Certbot cũng sẽ hỏi bạn có muốn thêm Nginx config để tự động redirect từ HTTP sang HTTPS không[^3]. Tùy vào yêu cầu dự án, nhưng khả năng cao là bạn nên chọn “2: Redirect”.</li>
<li>Certbot cũng sẽ hỏi một số thông tin về email liên lạc và một số thỏa thuận khác.</li>
</ul>
<p>Certbot sẽ tự động xác nhận quyền sở hữu domain thông qua Nginx server và domain của bạn đã được trỏ về IP của VPS trước đó. Certbot cũng sẽ tự động lưu certificate xuống VPS, cấu hình lại Nginx config và khởi động lại Nginx giùm bạn. Ngay sau khi kết thúc cài đặt với certbot, bạn đã có thể thử vào website với scheme <code>https://</code>.</p>
<p>Certificate mà Let’s Encrypt cấp cho bạn chỉ có thời hạn 3 tháng. Trước đây, khi gần đến thời hạn 3 tháng, bạn phải gọi lại <code>sudo certbot renew</code> để xin cấp lại certificate mới và phải khởi động lại Nginx. Giờ đây với Nginx plugin thì certbot sẽ tự động renew cho bạn và bạn không cần phải làm gì nữa cả sau khi hoàn tất bước này.</p>
<h2>Thêm: Xem log và thông báo lỗi của app</h2>
<p>Ngoài lệnh <code>systemctl status</code> để biết trạng thái chạy của app, với các chương trình chạy bằng systemd, bạn có thể xem log (cả console log và thông báo lỗi) của chúng bằng lệnh <code>journalctl</code>.</p>
<p>Sau đây là một số lệnh tôi thường dùng để xem lại console log của app trong lúc đang chạy:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Xem lại tất cả các log output của app</span>
<span class="token comment"># Bạn còn nhớ `SyslogIdentifier` ở trên?</span>
<span class="token comment"># Đặt chuỗi đó sau tham số -u để chỉ hiển thị log cho my-node-app</span>
<span class="token function">sudo</span> journalctl <span class="token parameter variable">-u</span> my-node-app
<span class="token comment"># Nếu log quá nhiều, bạn có thể nhảy dòng bằng các phím tắt của vim</span>

<span class="token comment"># Hiển thị 100 dòng log gần nhất</span>
<span class="token function">sudo</span> journalctl <span class="token parameter variable">-n</span> <span class="token number">100</span> <span class="token parameter variable">-u</span> my-node-app

<span class="token comment"># Hiển thị log của app trong khoảng thời gian chỉ định</span>
<span class="token function">sudo</span> journalctl <span class="token parameter variable">-u</span> my-node-app <span class="token parameter variable">--since</span> <span class="token string">"2018-09-20"</span> <span class="token parameter variable">--until</span> <span class="token string">"2018-09-26 03:00"</span>

<span class="token comment"># Hiển thị log gần đây nhất của app, sau đó tiếp tục chờ để</span>
<span class="token comment"># hiển thị các log tiếp theo khi app đang chạy</span>
<span class="token comment"># `-f` là tiếp tục chờ,</span>
<span class="token comment"># `-o cat` là hiển thị log không có timestamp và id phía trước</span>
<span class="token function">sudo</span> journalctl <span class="token parameter variable">-f</span> <span class="token parameter variable">-o</span> <span class="token function">cat</span> <span class="token parameter variable">-u</span> my-node-app</code></pre>
<h2>Lời kết</h2>
<p>Vậy là chúng ta đã hoàn tất cài đặt một Node Web app lên Ubuntu VPS với cách thức tối ưu nhất và tiết kiệm tài nguyên nhất. Với cấu hình này, bạn có thể chạy nhiều web app trên cùng VPS, bằng cách chạy app thứ hai trên một port mới (VD: 3001) và thêm một web host ảo trong Nginx config như ở trên, với <code>server_name</code> là tên domain cho web app thứ hai…</p>
<p>Tuy nhiên đây là cách cài đặt gắn chặt với môi trường của HĐH Ubuntu. Nói như vậy để phân biệt với một số cách cài đặt sản phẩm phần mềm được cho là <em>hiện đại</em> hơn, sử dụng container, mà phổ biến nhất là <a href="https://www.docker.com/">Docker</a>. Theo tôi việc deploy sản phẩm bằng container sẽ giúp quy trình CI[^4] được thực hiện dễ dàng hơn, không còn phụ thuộc vào Linux distro, và developer có thể giao việc deploy hoàn toàn cho devops mà không phải bận tâm. Tuy nhiên nó đòi hỏi developer phải có thêm kiến thức khá sâu về devops cũng như cách sử dụng docker ở vai trò người tạo.</p>
<p>Docker vẫn là một thứ khá mới mẻ đối với tôi và tôi vẫn đang nghiên cứu cách thức triển khai sản phẩm Node app trên Docker. Nếu nó thật sự hiệu quả và dễ tiếp cận, tôi sẽ viết tiếp chủ đề này với container.</p>
<hr>
<p>[^1]: Đối với CentOS hay distro khác, đường dẫn đến config của Nginx sẽ khác.</p>
<p>[^2]: Tùy cách quản lý, bạn có thể tạo nhiều file conf khác nhau trong <code>/etc/nginx/sites-available</code>, mỗi file dùng để config một web host ảo khác nhau. Nếu bạn tạo thêm file khác, bạn phải tạo một symlink từ <code>/etc/nginx/sites-available</code> sang thư mục <code>/etc/nginx/sites-enabled/</code> thì config cho site mới mới có hiệu lực. Dù vậy, thói quen riêng của tôi là để các block <code>server</code> vào cùng file <code>default</code> để dễ quản lý và theo dõi hơn vì số lượng web host trên một VPS không quá nhiều.</p>
<p>[^3]: Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.</p>
<p>[^4]: Continuous integration - test, build, deploy tự động và liên tục</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Making the best of MacBook Air touchpad on Ubuntu</title>
    <link href="https://int3ractive.com/blog/2018/make-the-best-of-MacBook-touchpad-on-Ubuntu/"/>
    <updated>2018-09-16T17:07:16Z</updated>
    <id>https://int3ractive.com/blog/2018/make-the-best-of-MacBook-touchpad-on-Ubuntu/</id>
    <content type="html"><![CDATA[
      <p>If you are a long time MacBook (Air) user and recently switch to Linux, I bet one of the things you’ll miss most is the multi-touch touchpad. As I have <a href="https://int3ractive.com/2018/08/on-dual-booting-linux-on-a-macbook-air.html">blogged earlier</a> that I decided to dual boot Ubuntu on this MacBook Air, at first, I also struggled to find the best setup for the touchpad to retain my productivity while not having to rely much on mouse.</p>
<p>In this post, I’m detailing my touchpad setup that I feel best so far and that it is as close to MacOS experience as I can get.</p>
<p>Although <strong>libinput</strong> is the default driver on latest Linux distros, we’ll switch to <strong>mtrack</strong>[^1] driver which supports many more of multi-touch gestures with flexible configurations, especially the three finger drag, which is also the main reason for my move. Thanks to this <a href="https://williambharding.com/blog/technology/toward-a-linux-touchpad-as-smooth-as-macbook-pro/">blog post</a>, I got a much faster head start, but there were still a lot of other things I did to get to my current setup.</p>
<p>Before we begin, please be noted that mtrack currently and will only support Xorg environment, which I am fine since I don’t find Wayland is any better in terms of performance and resource usage on current Ubuntu 18.04. I’m staying with Xorg for now (which is default session of Ubuntu 18.04 by the way).</p>
<h2>Compile and install mtrack driver</h2>
<p>Compile a Linux package by yourself might be a little scary for newbies so you just follow these steps carefully, then get to know the ins and outs later:</p>
<p>First, open terminal and install the necessary tools and dependencies for the compilation of the driver:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Update Ubuntu to latest packages</span>
<span class="token function">sudo</span> <span class="token function">apt</span> update <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">apt</span> upgrade

<span class="token comment"># These dependencies were noted by me on default Ubuntu 18.04</span>
<span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> build-essential <span class="token function">git</span> pkg-config libmtdev-dev mtdev-tools xserver-xorg-dev xutils-dev</code></pre>
<p>Then we’ll clone source code and compile the mtrack driver from its currently active <a href="https://github.com/p2rkw/xf86-input-mtrack">repo</a>:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># execute line by line:</span>
<span class="token builtin class-name">cd</span> /tmp
<span class="token function">git</span> clone https://github.com/p2rkw/xf86-input-mtrack.git
<span class="token builtin class-name">cd</span> xf86-input-mtrack
./configure --with-xorg-module-dir<span class="token operator">=</span>/usr/lib/xorg/modules
<span class="token function">sudo</span> <span class="token function">make</span></code></pre>
<p>You are most li kely not be able to compile the package at the <code>sudo make</code> command. Look carefully at the error messages which will tell the missing dependencies for it. If you are stuck, post a comment here and I’ll see if I can help.</p>
<p>Finally, install the driver into system:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">make</span> <span class="token function">install</span></code></pre>
<h2>Configure the new touchpad driver</h2>
<p>The new driver won’t be used until there’s a proper config file set up. Create the config file at <code>/usr/share/X11/xorg.conf.d/50-mtrack.conf</code> (root or admin permission needed) and edit it with your favorite text editor. Or use these commands:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">touch</span> /usr/share/X11/xorg.conf.d/50-mtrack.conf
<span class="token function">sudo</span> gedit /usr/share/X11/xorg.conf.d/50-mtrack.conf</code></pre>
<p>This will open the file with Gedit (Text Editor) with proper permission to save. Then, copy and paste my current mtrack config below:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Install mtrack driver 0.5.0++</span>
<span class="token comment"># Save this file to /usr/share/X11/xorg.conf.d/50-mtrack.conf</span>
<span class="token comment"># This config is specialized for MacBook Air 2012 (5,2)</span>
Section <span class="token string">"InputClass"</span>
        MatchIsTouchpad <span class="token string">"on"</span>
        Identifier      <span class="token string">"Touchpads"</span>
        MatchDevicePath <span class="token string">"/dev/input/event*"</span>
        Driver          <span class="token string">"mtrack"</span>
        <span class="token comment"># The faster you move, the more distance pointer will travel, using "polynomial" profile</span>
        Option          <span class="token string">"AccelerationProfile"</span> <span class="token string">"2"</span>
        <span class="token comment"># Tweak cursor movement speed with this</span>
        Option          <span class="token string">"Sensitivity"</span> <span class="token string">"0.05"</span>
        <span class="token comment"># Pressure at which a finger is detected as a touch</span>
        Option          <span class="token string">"FingerHigh"</span> <span class="token string">"5"</span>
        <span class="token comment"># Pressure at which a finger is detected as a release</span>
        Option          <span class="token string">"FingerLow"</span> <span class="token string">"5"</span>
        <span class="token comment"># I often use thumb to press down the physical button, so let's not ignore it</span>
        Option          <span class="token string">"IgnoreThumb"</span> <span class="token string">"false"</span>
        Option          <span class="token string">"ThumbRatio"</span> <span class="token string">"70"</span>
        Option          <span class="token string">"ThumbSize"</span> <span class="token string">"25"</span>
        <span class="token comment"># Ignore palm, with palm takes up to 30% of your touch pad</span>
        Option          <span class="token string">"IgnorePalm"</span> <span class="token string">"true"</span>
        Option          <span class="token string">"PalmSize"</span> <span class="token string">"30"</span>
        <span class="token comment"># Trigger mouse button when tap: 1 finger - left click, 2 finger - right click, 3 - middle click</span>
        Option          <span class="token string">"TapButton1"</span> <span class="token string">"1"</span>
        Option          <span class="token string">"TapButton2"</span> <span class="token string">"3"</span>
        Option          <span class="token string">"TapButton3"</span> <span class="token string">"2"</span>
        Option          <span class="token string">"TapButton4"</span> <span class="token string">"0"</span>
        Option          <span class="token string">"ClickTime"</span> <span class="token string">"25"</span>
        <span class="token comment"># Disable tap-to-drag, we're using three finger drag instead</span>
        Option          <span class="token string">"TapDragEnable"</span> <span class="token string">"false"</span>
        <span class="token comment"># While touching the touch pad with # fingers, press the touchpad physical click button</span>
        Option          <span class="token string">"ClickFinger1"</span> <span class="token string">"1"</span>
        Option          <span class="token string">"ClickFinger2"</span> <span class="token string">"3"</span>
        Option          <span class="token string">"ClickFinger3"</span> <span class="token string">"2"</span>
        Option          <span class="token string">"ButtonMoveEmulate"</span> <span class="token string">"false"</span>
        Option          <span class="token string">"ButtonIntegrated"</span> <span class="token string">"true"</span>
        <span class="token comment"># The momentum after scroll fingers released</span>
        Option          <span class="token string">"ScrollCoastDuration"</span> <span class="token string">"300"</span>
        Option          <span class="token string">"ScrollCoastEnableSpeed"</span> <span class="token string">".1"</span>
        <span class="token comment"># Natural scrolling with two fingers</span>
        Option          <span class="token string">"ScrollSmooth"</span> <span class="token string">"true"</span>
        Option          <span class="token string">"ScrollUpButton"</span> <span class="token string">"5"</span>
        Option          <span class="token string">"ScrollDownButton"</span> <span class="token string">"4"</span>
        Option          <span class="token string">"ScrollLeftButton"</span> <span class="token string">"7"</span>
        Option          <span class="token string">"ScrollRightButton"</span> <span class="token string">"6"</span>
        <span class="token comment"># Tweak scroll sensitivity with ScrollDistance, don't touch ScrollSensitivity</span>
        Option          <span class="token string">"ScrollDistance"</span> <span class="token string">"250"</span>
        Option          <span class="token string">"ScrollClickTime"</span> <span class="token string">"10"</span>
        <span class="token comment"># Three finger drag</span>
        Option          <span class="token string">"SwipeDistance"</span> <span class="token string">"1"</span>
        Option          <span class="token string">"SwipeLeftButton"</span> <span class="token string">"1"</span>
        Option          <span class="token string">"SwipeRightButton"</span> <span class="token string">"1"</span>
        Option          <span class="token string">"SwipeUpButton"</span> <span class="token string">"1"</span>
        Option          <span class="token string">"SwipeDownButton"</span> <span class="token string">"1"</span>
        Option          <span class="token string">"SwipeClickTime"</span> <span class="token string">"0"</span>
        Option          <span class="token string">"SwipeSensitivity"</span> <span class="token string">"1500"</span>
        <span class="token comment"># Four finger swipe, 8 &amp; 9 are for browsers navigating back and forth respectively</span>
        Option          <span class="token string">"Swipe4LeftButton"</span> <span class="token string">"9"</span>
        Option          <span class="token string">"Swipe4RightButton"</span> <span class="token string">"8"</span>
        <span class="token comment"># Mouse button >= 10 are not used by Xorg, so we'll map them with xbindkeys and xdotool later</span>
        Option          <span class="token string">"Swipe4UpButton"</span> <span class="token string">"11"</span>
        Option          <span class="token string">"Swipe4DownButton"</span> <span class="token string">"10"</span>
        <span class="token comment"># Mouse buttons triggered by 2-finger pinching gesture</span>
        Option          <span class="token string">"ScaleDistance"</span> <span class="token string">"300"</span>
        Option          <span class="token string">"ScaleUpButton"</span> <span class="token string">"12"</span>
        Option          <span class="token string">"ScaleDownButton"</span> <span class="token string">"13"</span>
        <span class="token comment"># Mouse buttons trigger by 2-finger rotating gesture, disabled to enhance the pinch gesture</span>
        Option          <span class="token string">"RotateLeftButton"</span> <span class="token string">"0"</span>
        Option          <span class="token string">"RotateRightButton"</span> <span class="token string">"0"</span>
EndSection</code></pre>
<p>Few things to note from above config file:</p>
<ul>
<li>This config file is tested on Macbook Air 2012 (5,2)</li>
<li>You’ll most likely need to tweak the cursor sensitivity. Do so at <code>Option &quot;Sensitivity&quot; &quot;0.10&quot;</code>, replacing value 0.10 to any other values between 0 and 1. The larger, the more movement.</li>
<li>You can tweak 2 finger scrolling sensitivity at <code>ScrollDistance</code>.</li>
<li>These scroll and swipe are natural, so you may swap the button number if you want the reverse.</li>
<li>Click on tap is enabled. If you don’t want that, set those <code>TapButton#</code> value to “0”</li>
<li>My config doesn’t ignore thumb. I often press the physical touchpad button with thumb. If you want to ignore thumb, set <code>IgnoreThumb</code> to “true”.</li>
</ul>
<p>If you want further tweaks, head to <a href="https://github.com/p2rkw/xf86-input-mtrack">the driver’s Github README</a> and read the configuration instructions.</p>
<p><strong>Updated 2019-08-19:</strong> I have added <code>AccelerationProfile</code> and tweak <code>Sensitivity</code> and <code>SwipeSensitivity</code> to make the experience with touchpad even more closer to that on macOS.</p>
<p><strong>Updated 2018-09-18</strong>: There’s another key point in my notes that I forgot to include: During my first setup with <code>mtrack</code>, the driver didn’t work until I add my current Linux user to the <code>input</code> group. Do so with following command:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> adduser <span class="token string">"<span class="token variable"><span class="token variable">`</span><span class="token function">whoami</span><span class="token variable">`</span></span>"</span> input</code></pre>
<p>After that, log out and log in to your desktop. You’ll know the driver is being used if you can drag or make selection immediately with three fingers on the touchpad.</p>
<h2>Disable touchpad while typing with <code>dispad</code></h2>
<p>After using <strong>mtrack</strong> for a while, I notice one of the annoying things is that touchpad is not disabled while typing which make the caret jump if you accidentally tap on it (and because I enabled tap to click). If you have troubles with this, install the <code>dispad</code> daemon from the original author of <code>mtrack</code>:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># install addition dev dependencies for dispad</span>
<span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> libconfuse-dev libxi-dev
<span class="token comment"># get code</span>
<span class="token builtin class-name">cd</span> /tmp
<span class="token function">git</span> clone https://github.com/BlueDragonX/dispad.git
<span class="token builtin class-name">cd</span> dispad
<span class="token comment"># compile the daemon</span>
./configure
<span class="token function">make</span>
<span class="token function">sudo</span> <span class="token function">make</span> <span class="token function">install</span></code></pre>
<p>Go ahead and start <code>dispad</code> by execute this command in terminal. A config file <code>~/.dispad</code>[^2] is created for you with default options. You can keep those, or change some options to mine like below:</p>
<pre class="language-ini"><code class="language-ini"><span class="token key attr-name">poll</span> <span class="token punctuation">=</span> <span class="token value attr-value">48</span>
<span class="token key attr-name">delay</span> <span class="token punctuation">=</span> <span class="token value attr-value">500</span></code></pre>
<p>Lastly, we need to start <code>dispad</code> automatically every time we log in, so go to <strong>Activities</strong>, search and open <strong>Startup Applications</strong>. Add new entry, with name as “dispad”, command as <code>/usr/local/bin/dispad</code> and with an optional comment to remind you what it does.</p>
<h2>Add more gestures with xbindkeys &amp; xdotool</h2>
<p>With above <strong>mtrack</strong> config, I already have these gestures (if it’s not obvious for you):</p>
<ul>
<li>Left mouse click with one finger tap; right mouse with two fingers tap; middle mouse with three fingers tap</li>
<li>Scroll with two fingers (both horizontal &amp; vertical)</li>
<li>Drag with three fingers</li>
<li>Swipe left and right with 4 fingers will simulate mouse button number 9 &amp; 8. This means I can navigate back and forth in browsers and many applications.</li>
</ul>
<p><code>mtrack</code> can simulate mouse button up to 15 with different gestures. However, Ubuntu only uses mouse buttons up to 9. To make use of other gestures, we need 2 additional tools: <code>xbindkeys</code> and <code>xdotool</code>.[^3]</p>
<p>Luckily, there’s no need for manual compilation this time. Just open terminal and install via command:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> xbindkeys xdotool</code></pre>
<h3>So what are xbindkeys &amp; xdotool?</h3>
<p><code>xbindkeys</code> is a daemon listening to your inputs from any input devices including keyboard, mouse and touchpad. You’ll define a rule at which, if an input or combination of inputs matches, some command can be executed. That’s where <code>xdotool</code> come in. <code>xdotool</code> is the command line tool which is able to simulate other key inputs. So by combining <code>xbindkeys</code> and <code>xdotool</code>, we’ll be able to map high mouse buttons (&gt; 9) to certain shortcuts that suit our needs.</p>
<p>To define the rules, you’ll need to open <code>xbindkeys-config</code> GUI app, from which you’ll define the keys listened and the actions (command). I won’t give the how-to here (which you can <a href="https://wiki.archlinux.org/index.php/Xbindkeys">look it up here</a>), but will provide my current xbindkeys config which you can copy and save it at <code>~/.xbindkeysrc</code>:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Next Workspace</span>
<span class="token string">"xdotool key super+Page_Down"</span>
   b:11

<span class="token comment"># Move Next Workspace</span>
<span class="token string">"xdotool key --clearmodifiers super+shift+Page_Down"</span>
   Control + b:11 + release

<span class="token comment"># Previous Workspace</span>
<span class="token string">"xdotool key super+Page_Up"</span>
   b:10

<span class="token comment"># Move Previous Workspace</span>
<span class="token string">"xdotool key --clearmodifiers super+shift+Page_Up"</span>
   Control + b:10 + release

<span class="token comment"># Zoom in</span>
<span class="token string">"xdotool key ctrl+21"</span>
   b:12

<span class="token comment"># Zoom out</span>
<span class="token string">"xdotool key ctrl+20"</span>
   b:13</code></pre>
<h3>What are these rules doing then?</h3>
<p>Combined with my <strong>mtrack</strong> config above, and with assumption that default shortcuts in Ubuntu is unchanged, these <code>xbindkeys</code> will allow you:</p>
<ul>
<li>4 finger <strong>swipe up</strong>: switch to next workspace</li>
<li>4 finger <strong>swipe down</strong>: switch to previous workspace</li>
<li>While holding <strong>ctrl</strong>, 4 finger <strong>swipe up</strong>: Move active window to next workspace</li>
<li>While holding <strong>ctrl</strong>, 4 finger <strong>swipe down</strong>: Move active window to previous workspace</li>
<li>Pinch scaling down (move 2 fingers closer): trigger <strong>ctrl</strong> and <strong>-</strong> combination, which is zoom out in browsers and reduce font size in some apps</li>
<li>Pinch scaling up (move 2 fingers away): trigger <strong>ctrl</strong> and <strong>=</strong> combination, which is zoom in in browsers and enlarge font size in some apps</li>
</ul>
<p>I haven’t found a use case for rotating gesture (button 14 &amp; 15) so I currently disabled them.</p>
<p>Finally, don’t forget to add this command <code>/usr/bin/xbindkeys_autostart</code> to <strong>Startup Applications</strong> so that it is automatically started at reboot.</p>
<h2>Bonus: pixel perfect scrolling on Firefox</h2>
<p><strong>Updated 2018-08-19:</strong> FWIW, GTK3+ has started support for pixel perfect scrolling (no jumping, pixel by pixel scrolling) for many of its applications. That has greatly enhanced UX for laptop users or users with trackpad. However, Firefox, the default browser on many Linux distros, still uses the jumping scroll (or fake smooth with easing movement). I have searched a lot for how Firefox will support pixel perfect scrolling, like it does on macOS, but only found answers to current fake smooth option.</p>
<p>Thankfully, I’ve got a hint from a Redditor replying on my post on <a href="https://www.reddit.com/r/Ubuntu/comments/9ggqv6/make_the_best_of_macbook_touchpad_on_ubuntu/">Reddit</a>. The reply points to <a href="https://np.reddit.com/r/linux/comments/72mfv8/psa_for_firefox_users_set_moz_use_xinput21_to/?st=jm8n2iqu&amp;sh=5e7163c1">this post</a> which I’ll quote here:</p>
<blockquote>
<p>I know this works for Firefox 55 or newer, but don’t know the earliest version which supports it. I assume it will be enabled by default at some point, but it isn’t yet in Firefox 58 (the current nightly).</p>
<ol>
<li>Run this command:
<code>echo export MOZ_USE_XINPUT2=1 | sudo tee /etc/profile.d/use-xinput2.sh</code></li>
<li>Log out and back in.</li>
<li>Firefox should now use xinput 2.</li>
<li>(optional) Open Firefox and go to about:preferences -&gt; Advanced (or about:preferences -&gt; Browsing for Firefox Nightly), and uncheck “Use smooth scrolling”. This disables the old style “smooth scrolling”, which just causes an annoying delay when using xinput2 style scrolling imo.</li>
</ol>
</blockquote>
<p>So by following above steps, pixel pefect scrolling is turned on for latest Firefox 62 and it’s working great.</p>
<h2>Final words</h2>
<p>That’s my whole setup for multi-touch touchpad and it has made my life on Linux a lot easier! However, I discovered some issues with <code>mtrack</code> driver after a lot of use, but they are trivial and won’t dismiss the whole experience:</p>
<ul>
<li>Scroll coast are sometimes sticky and make scroll move quickly in subsequence scroll gestures</li>
<li>Dispad sometimes doesn’t detect typing and lets the caret jump</li>
</ul>
<p>Finally, this may just be temporary since <code>libinput</code> and Wayland are already chosen to be the future and they are actively developed. I will revisit <code>libinput</code> once it get better multi-touch support and more configurations, but <code>mtrack</code> is the way to go, for now.</p>
<hr>
<p>[^1]: Here’s a brief touchpad driver 101: There are three known drivers for laptop touchpad on Linux, i.e. <strong>synaptics</strong> (discontinued), <strong>libinput</strong> and <strong>mtrack</strong>. For latest Ubuntu and other popular distros, libinput is the chosen driver because it has decent multi touch support (and being improved) and most importantly, it supports <a href="https://en.wikipedia.org/wiki/Wayland_(display_server_protocol)">Wayland</a> environment. There are few flaws with current libinput driver though, for example: I cannot adjust the sensitive of scroll with two fingers, I cannot disable tap-and-drag easily (some manual commands involved), I cannot drag with three fingers…</p>
<p>[^2]: The <code>~/</code> sign means this file is stored at current user’s home folder.</p>
<p>[^3]: These tools also require Xorg.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>On dual booting Linux on a Macbook Air</title>
    <link href="https://int3ractive.com/blog/2018/on-dual-booting-linux-on-a-macbook-air/"/>
    <updated>2018-08-27T18:19:44Z</updated>
    <id>https://int3ractive.com/blog/2018/on-dual-booting-linux-on-a-macbook-air/</id>
    <content type="html"><![CDATA[
      <p>I have been using a MacBook Air for both personal use and work since 2012. Apple’s hardware back then was top notch and reliable. When I did a feature and price comparison between a MacBook Air and other ultrabook offers, MacBook Air can easily rise up to the number one choice for a laptop that is portable, well-built and powerful enough at a reasonable price.</p>
<p>Fast forward to 2018. Apple is not itself anymore, at least in the interest of MacBook. Bad reviews and incidents of the MacBook line just happened one after another. Here are just a few:</p>
<ul>
<li>Apple’s <a href="https://weblog.rogueamoeba.com/2018/06/14/on-the-sad-state-of-macintosh-hardware/">slow on updating</a> its laptops hardware</li>
<li>The <a href="https://theoutline.com/post/2402/the-new-macbook-keyboard-is-ruining-my-life">shallow and dirt-prone butterfly keyboards</a> on the new MacBook and MacBook Pro</li>
<li>The <a href="https://www.reddit.com/r/mac/comments/5w3wpy/q_people_who_have_used_the_touch_bar_is_it_worth/">unwanted touch bar</a></li>
<li>The <a href="https://www.macrumors.com/2018/07/17/core-i9-chip-macbook-pro-throttling/">core i9 chip MacBook throttling</a></li>
<li>And for MacBook Air, its chips are <a href="https://buyersguide.macrumors.com/#MacBook_Air">now outdated</a> (as of 08/2018) and worse its peripheral design hasn’t change since… forever.</li>
</ul>
<p>With all of that, I seriously consider moving away from Apple walled garden and embrace Linux where I can freely choose hardware from other vendors.</p>
<p>However, my aged MacBook Air is still working great. So my strategy for now is to dual boot a Linux distro along with macOS on this machine, first to get familiar with modern Linux desktop experience, and secondly, to explore the tools and software that can replace my current ones on macOS.</p>
<p>My chosen distro is Ubuntu, because I am very much used to it, and it’s stable, especially on exotic hardware like MacBook Air. Besides, being the most popular Linux distro, it will be easier for me to find answers to issues if I come across.</p>
<p>At first I installed the default Ubuntu 18.04 with GNOME Shell and felt <strong>really irritated</strong>. After that I tried 2 other desktop environments: Pantheon (of Elementary OS) over Ubuntu 18.04 and MATE (full install of Ubuntu MATE 18.04). I kept a note name <em>“Linux Grudges”</em> to list down what I personally dislike and like about each desktop environments (desktop UI experience only, other functionalities are almost the same), so here they are:</p>
<h3>GNOME Desktop &amp; GNOME Shell (Standard Ubuntu):</h3>
<p><img src="/images/2018/ubuntu-1804-with-nautilus.jpg" alt="Ubuntu 18.04 default"><em>Default Ubuntu 18.04 with Nautilus</em></p>
<p>I tried GNOME 3 desktop with GNOME shell for the first time after long time with the old Unity DE and macOS. I have a lot of irritation with it and God forbid, GNOME shell, on the contrary to its claim, often steps in my way to get things done!</p>
<h4>Like:</h4>
<ul>
<li>Activities overview and Show applications screen</li>
<li>Type to search anything (similar to macOS Spotlight)</li>
<li>Dash to dock by default (this make GNOME Shell on Ubuntu suck less)</li>
<li>Support legacy application indicators by default (this is another Ubuntu fix for GNOME Shell)</li>
<li>Most GNOME apps support pixel perfect scrolling with touch pad</li>
</ul>
<h4>Dislike:</h4>
<ul>
<li>A huge <strong>waste of space on the top panel</strong> and hide everything in the system tray and app menu dropdowns</li>
<li>If I want to do anything, other than with current windows, I have to visit that Activities overview, like: launch another app, search for files, search for apps, switch workspace… which <strong>became annoying and distracting to current task</strong></li>
<li>It’s 2018 and people are moving away from hamburger menus and dropdowns. But for GNOME Apps, they <strong>hide everything in that menu</strong></li>
<li>Some of my favorite apps like Firefox, Sublime Text are still using fake smooth scrolling. (Not GNOME per se, but it just add up some irritation.)</li>
<li>Crashy and sometimes CPU-hog GNOME Shell. I have to run: <code>gnome-shell --replace</code> once in a while.</li>
</ul>
<p>If you’d like some more rants on the problematic GNOME 3, check out <a href="https://liam-on-linux.livejournal.com/52807.html">this post</a>.</p>
<h3>Pantheon Desktop on Ubuntu 18.04:</h3>
<p><img src="/images/2018/elementary-os.jpg" alt="Elementary OS with Slingshot application menu"><em>Elementary OS with Slingshot application menu</em></p>
<p>I was curious about Elementary OS which has minimalist and similar UI to macOS, so I tried out its <strong>Pantheon DE</strong> on default Ubuntu 18.04.</p>
<h4>Like:</h4>
<ul>
<li>Simple but clean and aesthetic UI, resemble macOS</li>
<li>It’s default Terminal app can use Ctrl-C &amp; Ctrl-V for copy &amp; paste</li>
<li>Files explorer with column view similar to macOS Finder</li>
<li>Nice and clean app store</li>
</ul>
<h4>Dislike:</h4>
<ul>
<li>Terminal lack of customization (other shortcuts, color theme…)</li>
<li>No global menu, so most of the top panel space is also wasted</li>
<li>Old system tray icons won’t show at top bar (iBus, Fcitx, Electron apps…). This is show-stopper for me.</li>
<li>Log out crash the session (may be due to Pantheon desktop on top Ubuntu, not real Elementary OS)</li>
<li>Currently, its configuration ability is limited.</li>
</ul>
<h3>Ubuntu MATE:</h3>
<p><img src="/images/2018/ubuntu-mate-mutiny.jpg" alt="Ubuntu MATE Desktop with Mutiny layout "><em>Ubuntu MATE Desktop with Mutiny layout</em></p>
<p>I tried <strong>Ubuntu MATE</strong> (with Unity-like layout) solely because I wanted the global menu which, for me, is the best solution of app menu. (Easier to target since it’s sticked to top edge; space of top panel is well used; and leave more working area for app window…). I did enjoy Ubuntu MATE and invested some tweaking with it. But after a while, I felt that the MATE experience is not very polished and feel dated.</p>
<h4>Like:</h4>
<ul>
<li>Low resource footprint</li>
<li>Global menu</li>
<li>HUD (menu items search like macOS)</li>
<li>App Launcher (like macOS)</li>
<li>Dock (again, like macOS)</li>
</ul>
<h4>Dislike:</h4>
<ul>
<li>App switcher popup is too small and not having a thumbnail preview</li>
<li>MATE doesn’t have something similar to Activities overview</li>
<li>Panel icons occasionally hang, and have to restart with: <code>mate-panel --replace &amp;</code></li>
<li>Lack of theme dedicated for MATE desktop, and the default MATE themes, IMO, lack some taste</li>
<li>Lack of animation (this should be fine if I’m on very old hardware)</li>
<li>No built-in color profile manager (this is important, without custom color profile, MacBook Air screen color look very off)</li>
</ul>
<h3>Ubuntu Budgie:</h3>
<p>I learned about <strong>Ubuntu Budgie</strong> after I already chose my distro and DE. I did not tried it but viewed its screen cast walk-through. My immediate impression is that it’s just like another Elementary OS and still waste the top panel.</p>
<p><img src="/images/2018/budgie-maximized.png" alt="Budgie desktop maximized window"><em>Maximized window on Budgie desktop on a 1920x1080 screen. Imagine it runs a traditional app with title, menu… on a 1366x768 laptop screen, the top bar is wasted and how narrow the space left for actual content.</em></p>
<h2>Settle on GNOME Desktop and GNOME Shell</h2>
<p>After actually trying the three different desktops, I decided, though, to settle on GNOME with these reasons:</p>
<ul>
<li>GNOME desktop has the most popular community and is actively developed.</li>
<li>Crashy and resource-hog problems of GNOME Shell often come from lousy extensions. With some experiment and trials, I have spotted the problematic ones and removed them.</li>
<li>Although it has many UX problems (that even <a href="https://www.zdnet.com/article/linus-torvalds-finds-gnome-3-4-to-be-a-total-user-experience-design-failure/">Linus bashed it</a>), it is still very configurable and extensible.</li>
<li>After finding out <strong>Switcher</strong>, and <strong>Unite</strong> GNOME Shell extensions, GNOME desktop experience is now bearable for me.</li>
<li>With the main Ubuntu distro chose GNOME as default desktop, I’m in hope that better GNOME enhancements will land from Ubuntu developers as they did for Unity.</li>
<li>GNOME Shell has JavaScript API and its extensions are written with JavaScript; which really excites a JS guy like me that I’ll be able to jump into “hacking” my desktop real soon. I’m going through tutorials during spare time right now.</li>
</ul>
<h2>The journey has just begun</h2>
<p>That said, I have been using Ubuntu on this MacBook Air for two months non-stop and have got used to it to the level of efficiency that I had with macOS.</p>
<p><img src="/images/2018/ubuntu-1804-unite.jpg" alt="My Ubuntu desktop with Unite extension"><em>My current Ubuntu desktop with Unite extension which allows me to move window title and buttons up the top panel for maximized windows, making good use of its space.</em></p>
<p>I did a lot of tweaks and configurations wherever I found it make sense and made the transition from macOS to Linux as quick as possible. For alternative software, I have also found most of the needed applications to avoid switching back to macOS.</p>
<p>If you are interested in installing Ubuntu on a MacBook, stay tuned. In the coming blog posts, I’ll share my experience and things I did to configure my current Ubuntu desktop, including: fixing GNOME shell with some extensions, making good use of the multi-touch touch pad, keyboard shortcuts and key swaps for Mac keyboard, fixing the screen color profile, mounting the APFS Macintosh drive, finding the software alternatives, and a lot more…</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Giới thiệu phần mềm nghe nhạc Tizonia</title>
    <link href="https://int3ractive.com/blog/2018/gioi-thieu-phan-mem-nghe-nhac-tizonia/"/>
    <updated>2018-08-09T04:31:14Z</updated>
    <id>https://int3ractive.com/blog/2018/gioi-thieu-phan-mem-nghe-nhac-tizonia/</id>
    <content type="html"><![CDATA[
      <p><a href="http://tizonia.org">Tizonia</a> là một phần mềm trên Linux cho phép chơi nhạc online từ Youtube, Spotify, Google Music, SoundCloud bằng… dòng lệnh. Lý do số một mình thích là nó chơi nhạc từ Youtube cực nhẹ vì không cần video và giao diện.</p>
<p><img src="/images/2018/tizonia-terminal.png" alt="Tizonia on gnome-terminal"></p>
<h2>Cài đặt</h2>
<p>Để cài đặt, bạn có thể tìm cài trong Software của Ubuntu (snap package) hoặc thông qua gói .deb với dòng lệnh:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Cho Debian/Ubuntu/Raspbian</span>
<span class="token function">curl</span> <span class="token parameter variable">-kL</span> https://github.com/tizonia/tizonia-openmax-il/raw/master/tools/install.sh <span class="token operator">|</span> <span class="token function">bash</span></code></pre>
<p>Xem thêm cách cài cho các distro khác <a href="http://tizonia.org/docs/">tại đây</a>.</p>
<p>Sau khi cài đặt, mở terminal và chạy lệnh:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Xem hướng dẫn chung</span>
tizonia <span class="token parameter variable">-h</span>

<span class="token comment"># Xem các phím tắt điều khiểu trong lúc đang chơi:</span>
tizonia <span class="token parameter variable">-h</span> keyboard

<span class="token comment"># Xem hướng dẫn cho Youtube...</span>
tizonia <span class="token parameter variable">-h</span> youtube</code></pre>
<h2>Dùng với Youtube</h2>
<p>Với Youtube, bạn không cần cài đặt tài khoản gì cả.</p>
<p>Một số dòng lệnh mình thường dùng với YouTube:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Nghe một video / bài hát cụ thể (qua URL hoặc ID)</span>
tizonia --youtube-audio-stream https://www.youtube.com/watch?v<span class="token operator">=</span>tCV4dSMeQzE

<span class="token comment"># Nghe một playlist cụ thể (qua playlist URL hoặc ID)</span>
tizonia --youtube-audio-playlist https://www.youtube.com/playlist?list<span class="token operator">=</span>PLsIRiRj6jaw7Z6bHs5V99yAvlMUf2icOG

<span class="token comment"># Nghe mix nhạc tự động dựa trên từ khóa search</span>
tizonia --youtube-audio-mix-search <span class="token string">"Lam Trường"</span></code></pre>
<h2>Dùng với Spotify</h2>
<p>Để sử dụng Tizonia với Spotify bạn phải đang dùng tài khoản trả phí. Cách tiện nhất là bạn sẽ set sẵn <code>spotify.user</code> và <code>spotify.password</code> trong file <code>~/.config/tizonia/tizonia.conf</code>[^1] (nếu file này chưa tồn tại, bạn cần chạy lệnh tizonia lần đầu).</p>
<blockquote>
<p>Có một lưu ý với người dùng đăng nhập Spotify bằng Facebook như mình, đó là bạn sẽ không có password để đăng nhập với email mà sẽ phải tạo thêm mật khẩu thiết bị (device password) bằng cách vào phần tài khoản tại <a href="https://www.spotify.com/vn-vi/account/set-device-password/">spotify.com</a>, tìm đến mục <strong>Cài đặt mật khẩu thiết bị</strong> và làm theo hướng dẫn. Sau đó, trường <code>spotify.user</code> bạn sẽ set là <strong>mã số tên người dùng</strong> cho thiết bị.</p>
</blockquote>
<p>Một số dòng lệnh mình thường dùng với Spotify:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Nghe một danh sách các bài hát theo từ khóa tìm thấy trong tên bài hát</span>
tizonia --spotify-tracks <span class="token string">"Frozen Heart"</span>

<span class="token comment"># Nghe nhạc từ một ca sĩ đầu tiên theo từ khóa</span>
tizonia --spotify-artist <span class="token string">"Ed Sheeran"</span>

<span class="token comment"># Nghe playlist do bạn tạo</span>
tizonia --spotify-playlist <span class="token string">"Programming Music"</span>

<span class="token comment"># Nghe playlist do user "Spotify" tạo</span>
tizonia --spotify-owner <span class="token string">"spotify"</span> --spotify-playlist <span class="token string">"Sleep"</span>
</code></pre>
<h2>Lệnh tắt (bash alias)</h2>
<p>Lệnh để nhập cho Tizonia khá dài, nên mình đã tạo một số alias để gõ cho nhanh.</p>
<p>Ví dụ, thay vì gõ “<strong>ti</strong>zonia --<strong>s</strong>potify-<strong>ar</strong>tist”, bạn chỉ cần gõ: <code>tisar</code> sau đó là tham số. Hoặc thay vì gõ “<strong>ti</strong>zonia --<strong>y</strong>outube-audio-<strong>m</strong>ix-<strong>s</strong>earch”, bạn sẽ gõ <code>tiyms</code>.</p>
<p>Để cài các alias này, bạn chỉ cần copy nội dung của <a href="https://gist.github.com/trongthanh/34dee70f4f1fbe36aa2c223be5892e45">gist bên dưới</a> và paste phía cuối file <code>~/.bashrc</code> và sau đó khởi động lại Terminal.</p>
<script src="https://gist.github.com/trongthanh/34dee70f4f1fbe36aa2c223be5892e45.js"></script>
<hr>
<p>[^1]: Dành cho newbie: ký tự <code>~</code> trong terminal dùng để thay thế cho thư mục HOME của user hiện tại. Đôi khi cũng được viết là <code>$HOME</code>.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Jekyll Read Time Helper without Plugins</title>
    <link href="https://int3ractive.com/blog/2018/jekyll-read-time-without-plugins/"/>
    <updated>2018-08-07T07:04:35Z</updated>
    <id>https://int3ractive.com/blog/2018/jekyll-read-time-without-plugins/</id>
    <content type="html"><![CDATA[
      <p>Searching the web for a Jekyll / Liquid template helper that show “read time” of a post without plugins (so that it’ll work for GitHub Page) will probably land you at <a href="https://carlosbecker.com/posts/jekyll-reading-time-without-plugins/">this post</a> by Carlos Alexandro Becker. I also tried the solution of that post which I’ll quote it here (assuming <strong>180 word-per-minute</strong>):</p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>reading-time<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Estimated read time<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">assign</span> words <span class="token operator">=</span> content <span class="token operator">|</span> <span class="token function filter">number_of_words</span> <span class="token delimiter punctuation">%}</span></span>
    <span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">if</span> words <span class="token operator">&lt;</span> <span class="token number">360</span> <span class="token delimiter punctuation">%}</span></span>
        1 min
    <span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">else</span> <span class="token delimiter punctuation">%}</span></span>
        <span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> words <span class="token operator">|</span> <span class="token function filter">divided_by</span><span class="token operator">:</span><span class="token number">180</span> <span class="token delimiter punctuation">}}</span></span> mins
    <span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">endif</span> <span class="token delimiter punctuation">%}</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></code></pre>
<p>This partial is okay except for those posts that has words count between 180 - 360 which will result as 1 min instead of 2, and words count between 360 - 539 will result as 2 min instead of 3…</p>
<p>So I have revised the solution with my own as following:</p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>reading-time<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Estimated read time<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">assign</span> words <span class="token operator">=</span> <span class="token keyword">include</span><span class="token punctuation">.</span>content <span class="token operator">|</span> <span class="token function filter">strip_html</span> <span class="token operator">|</span> <span class="token function filter">number_of_words</span> <span class="token delimiter punctuation">%}</span></span>
    <span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> words <span class="token operator">|</span> <span class="token function filter">divided_by</span><span class="token operator">:</span> <span class="token number">180</span> <span class="token operator">|</span> <span class="token function filter">plus</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token delimiter punctuation">}}</span></span> min read.
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></code></pre>
<p>Since Liquid filter <code>divided_by</code> will round down the result if input is integer (0.5 to 0, etc.), adding back 1 will correct this, with the only flaw that any fractions of minute will now be rounded up to one minute.</p>
<p>Besides the new read-time algorithm, I’ve also added the <code>strip_html</code> filter to the partial and use <a href="https://jekyllrb.com/docs/includes/#passing-parameters-to-includes">include parameter</a> so that it’ll work correctly with consistent <code>min read</code> value regardless of the context it is used. For example, if it is placed in <strong>post</strong> layout, we will add the partial like so:</p>
<pre class="language-liquid"><code class="language-liquid"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>meta<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Posted by <span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> <span class="token object">page</span><span class="token punctuation">.</span>author <span class="token delimiter punctuation">}}</span></span> on <span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> <span class="token object">page</span><span class="token punctuation">.</span><span class="token object">date</span> <span class="token delimiter punctuation">}}</span></span>.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">include</span> read<span class="token operator">-</span>time<span class="token punctuation">.</span>html content<span class="token operator">=</span>content <span class="token delimiter punctuation">%}</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre>
<p>If it is used in blog index, such as <code>index.html</code>, it’ll be added like this:</p>
<pre class="language-liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">for</span> post <span class="token keyword">in</span> paginator<span class="token punctuation">.</span>posts <span class="token delimiter punctuation">%}</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post-preview<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> post<span class="token punctuation">.</span>url <span class="token operator">|</span> <span class="token function filter">prepend</span><span class="token operator">:</span> site<span class="token punctuation">.</span>baseurl <span class="token delimiter punctuation">}}</span></span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> post<span class="token punctuation">.</span>title <span class="token delimiter punctuation">}}</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post-meta<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Posted by <span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> post<span class="token punctuation">.</span>author <span class="token delimiter punctuation">}}</span></span> on <span class="token liquid language-liquid"><span class="token delimiter punctuation">{{</span> post<span class="token punctuation">.</span><span class="token object">date</span> <span class="token delimiter punctuation">}}</span></span>.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
        <span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">include</span> read<span class="token operator">-</span>time<span class="token punctuation">.</span>html content<span class="token operator">=</span>post<span class="token punctuation">.</span>content <span class="token delimiter punctuation">%}</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>hr</span><span class="token punctuation">></span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">{%</span> <span class="token keyword">endfor</span> <span class="token delimiter punctuation">%}</span></span></code></pre>
<p>My blog has been updated with <a href="https://github.com/trongthanh/trongthanh.github.com/blob/master/_includes/read-time.html">read-time partial</a> with the adjustment that I’m using <strong>265 WPM</strong> as per <a href="https://help.medium.com/hc/en-us/articles/214991667-Read-time">Medium recommendation</a>[^1].</p>
<p>So, that’s it. Any comments are welcomed.</p>
<hr>
<p>[^1]: It was 275, but it seems they recently updated.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>macOS Mojave dynamic wallpaper for Linux</title>
    <link href="https://int3ractive.com/blog/2018/macos-mojave-dynamic-wallpaper-for-linux/"/>
    <updated>2018-07-25T08:05:40Z</updated>
    <id>https://int3ractive.com/blog/2018/macos-mojave-dynamic-wallpaper-for-linux/</id>
    <content type="html"><![CDATA[
      <p>I’m a Mac owner but also a Linux enthusiast and currently dual boot macOS and Linux. That’s why when I learned about new <a href="https://www.cultofmac.com/553577/grab-all-16-macos-mojave-dynamic-wallpapers-right-here/">dynamic wallpaper feature</a> of macOS Mojave, and recalled Ubuntu / Linux has a similar feature (note built-in) called <a href="https://help.ubuntu.com/community/SlideshowWallpapers">wallpaper slideshow</a>, I realized “Hey why not recreate the dynamic Mojave sand dune backgrounds on Linux with each image reflect the right moment of the day?”.</p>
<p>So after several minutes crafting <a href="https://gist.github.com/trongthanh/7d632e90687e1bc219e1f3262d337702">this mojave.xml</a> and actually testing and tweaking it on Ubuntu for two days, I posted the XML on <a href="https://gist.github.com/trongthanh/7d632e90687e1bc219e1f3262d337702">Github Gist</a> and <a href="https://twitter.com/trongthanh/status/1011470275957800960">tweeted about it</a>. It was amid my busy days, so I didn’t write a proper blog post. Fortunately, the guys at <em>OMG! Ubuntu!</em> was interested and wrote <a href="https://www.omgubuntu.co.uk/2018/06/macos-mojave-dynamic-background-linux">a detailed article about it</a> and got many positive comments.</p>
<p>This post is not intended to repeat the instructions that were well written at the <em>OMG! Ubuntu!</em> article. But as a place for further update announcements and discussion since <strong>GitHub Gist sucks at notify commenters and owners</strong> (if not at all) about gist updates.</p>
<p>So from now on, please leave any comments at the bottom of this article (and not on the gist anymore).</p>
<p>From the commenters and my own tests, these are support status of different DE for slideshow XML:</p>
<ul>
<li><strong>GNOME</strong> &amp; <strong>Unity</strong>: Use gnome-tweak to select the XML file from any folder</li>
<li><strong>MATE</strong>: Just use the built-in Wallpaper selector from Control panel, make sure <strong>all files</strong> filter is selected at the file chooser.</li>
<li><strong>Cinnamon</strong>: From terminal, run <code>gsettings set org.gnome.desktop.background picture-uri &quot;file:/home/USERNAME/Pictures/wallpapers/mojave-background/mojave.xml&quot;</code></li>
<li><strong>Xfce</strong>: It reportedly supports background XML, but I have not yet tested to confirm.</li>
<li><strong>Budgie</strong>: Sorry, no support. :(</li>
<li><strong>KDE</strong>: ???</li>
<li><strong>Pantheon</strong> (Elementary): ???</li>
</ul>
<p>Here I’m embedding the XML again with short instructions for your convenience:</p>
<script src="https://gist.github.com/trongthanh/7d632e90687e1bc219e1f3262d337702.js"></script>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Giới thiệu Progressive Web App</title>
    <link href="https://int3ractive.com/blog/2018/gioi-thieu-progressive-web-app/"/>
    <updated>2018-05-13T10:43:06Z</updated>
    <id>https://int3ractive.com/blog/2018/gioi-thieu-progressive-web-app/</id>
    <content type="html"><![CDATA[
      <p><img src="/images/2018/pwa/pwa-logo.png" alt="logo không chính thức của PWA"> <em>logo <a href="https://medium.com/samsung-internet-dev/we-now-have-a-community-approved-progressive-web-apps-logo-823f212f57c9">không chính thức</a> của PWA</em></p>
<p><strong class="drop-cap">P</strong>rogressive Web App (PWA) là một dạng ứng dụng web (web app) mới đang thu hút rất nhiều sự quan tâm từ các nhà phát triển web khắp thế giới đặc biệt là các doanh nghiệp hoạt động trực tuyến, tuy nhiên nó vẫn còn khá mới mẻ tại Việt Nam.</p>
<p>Đã có nhiều bài viết liên quan đến PWA dành cho <a href="https://addyosmani.com/blog/getting-started-with-progressive-web-apps/">lập</a> <a href="https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/">trình</a> <a href="https://www.smashingmagazine.com/2016/08/a-beginners-guide-to-progressive-web-apps/">viên</a>, cho nên trong bài viết này tôi sẽ cố gắng giải thích PWA để người dùng Web phổ thông vẫn có thể hiểu.</p>
<h2>Progressive Web App là gì?</h2>
<p><strong>PWA là ứng dụng web được viết để tận dụng những tính năng mới nhất của trình duyệt Web trên máy tính để bàn (desktop) lẫn điện thoại thông minh, nhưng đồng thời vẫn chạy được trên những trình duyệt và thiết bị cũ hơn. PWA lấy phương pháp <a href="https://www.youtube.com/watch?v=5oUSzo1oRv0">Cải Tiến Tăng Dần (Progressive Enhancement)</a> làm cốt lõi (nên mới có chữ Progressive).</strong></p>
<p>Đối với những trình duyệt và thiết bị cũ, PWA hoạt động như một mobile website thông thường. Nhưng với những trình duyệt trên thiết bị di động mới nhất, PWA hoạt động như một <em>mobile app</em>[^1] thực thụ.</p>
<p>Những tác giả của khái niệm PWA (đến từ nhóm phát triển trình duyệt Chrome) đã đưa ra những đặc tính cần có của một PWA như sau:</p>
<ul>
<li><strong>Progressive</strong> - Chạy được trên <em>mọi</em> (nên hiểu: tuyệt đại đa số) thiết bị, do được phát triển với phương pháp Cải Tiến Tăng Dần.</li>
<li><strong>Responsive</strong> - Có thiết kế <em>giao diện tùy ứng</em> (responsive design), hiển thị và sử dụng được trên mobile, tablet, laptop hay bất kỳ cỡ màn hình nào trong tương lai.</li>
<li><strong>Connectivity independent</strong> - PWA vẫn có thể hoạt động tốt với điều kiện kết nối mạng chập chờn hoặc mất hẳn (offline).</li>
<li><strong>App-like</strong> - Có giao diện và trải nghiệm như mobile app thực thụ.</li>
<li><strong>Fresh</strong> - Dù nó hoạt động như mobile app, nhưng tính năng và giao diện luôn được cập nhật tức thời nhờ nền tảng Web (không cần người dùng update từ Apple App Store hay Google Play - gọi chung là app store).</li>
<li><strong>Safe</strong> - PWA phải được tải thông qua giao thức TLS (hay nôm na là HTTPS), để đảm bảo việc trao đổi dữ liệu không bị bên thứ ba can thiệp.</li>
<li><strong>Discoverable</strong> - Thông qua file khai báo chuẩn (được thống nhất bởi tổ chức W3C), mà các PWA dễ dàng được các cỗ máy tìm kiếm đánh dấu và thông báo cho người dùng.</li>
<li><strong>Re-engageable</strong> - PWA cho phép việc tái tiếp cận người dùng dễ dàng hơn nhờ những tính năng đặc biệt như là push notification (thông báo chủ động).</li>
<li><strong>Installable</strong> - PWA cho phép người dùng dễ dàng lưu lại web app trên điện thoại (thường là trên màn hình home screen) mà không cần phải vào app store</li>
<li><strong>Linkable</strong> - Dễ dàng share app chỉ với đường link và không cần người nhận phải cài đặt phức tạp chỉ để xem được nội dung bạn muốn share.</li>
</ul>
<h2>Những điểm khác biệt của Progressive Web App?</h2>
<p>Trước tiên cần hiểu rằng, sự tiến hóa của mobile web app cần sự hợp tác của rất nhiều bên liên quan trong đó có các nhà phát triển trình duyệt, hệ điều hành di động, và cả những chuyên gia về ngôn ngữ lập trình cho Web. Sự tiến hóa của mobile web thường đi cùng với sự phát triển và chuẩn hóa của nền tảng Web do tổ chức <strong>W3C</strong>[^2] chịu trách nhiệm.</p>
<p><a href="http://www.evolutionoftheweb.com"><img src="/images/2018/pwa/evolutionoftheweb.jpg" alt="Sự tiến hóa của nền tảng Web" title="Sự tiến hóa của nền tảng Web"></a></p>
<p>Khi tôi tư vấn và phát triển app cho khách hàng, rất nhiều lần doanh nghiệp từ chối lựa chọn giải pháp web app hoặc hybrid app với lý do chính là <em>“HTML5 không nhanh bằng native”</em>. Tuy nhiên điều này không còn đúng tại thời điểm hiện tại.</p>
<p>Nhờ những cải tiến của phần cứng thiết bị, hệ điều hành di động, trình duyệt, và nhất là đặc tả Web trong vài năm gần đây mà web app đã thêm những khả năng không thua kém native app như:</p>
<ul>
<li>Giao diện tương tác mượt mà hơn, đặt biệt là hỗ trợ đồ họa 3D, animation từ phần cứng (hardware accelerated)</li>
<li>Khả năng chơi video, audio thông qua trình duyệt mobile đã hoàn thiện và định dạng gần như đã thống nhất.</li>
<li>Bàn phím ảo thích ứng với trường nhập web form khác nhau: email, URL, telephone…</li>
<li>Có khả năng truy xuất các sensor và bộ phận đa phương tiện của thiết bị: định vị GPS, con quay hồi chuyển, trạng thái pin, network, camera, microphone…</li>
<li>Cơ sở dữ liệu (CSDL) tại trình duyệt cho phép tìm kiếm và truy cập nhanh lượng dữ liệu lớn và cho phép người dùng trở lại trang web app nhanh hơn.</li>
<li>Đặc tả mới về CSS cho phép designer và front end developer tạo giao diện tùy ứng (responsive design) và giao diện giống app dễ dàng hơn.</li>
</ul>
<p><img src="/images/2018/pwa/web-apps-showcase.jpg" alt="Web app showcase"><em>Từ trái qua, các web app nổi tiếng đã chứng minh được sự thành công của web app trên mobile: <a href="https://app.ft.com">app.ft.com</a>, <a href="https://flipboard.com">flipboard.com</a>, <a href="https://m.aliexpress.com">m.aliexpress.com</a></em></p>
<p>Dù vậy, web app vẫn còn một số hạn chế so với native app. Chúng ta hãy xem PWA đã được bổ sung những khả năng gì để có thể xóa dần khoảng cách giữa web và native:</p>
<h3>Shortcut trên home screen và hỗ trợ theme từ trình duyệt</h3>
<figure class="figure figure--right">
    <img class="figure__image" src="/images/2018/pwa/safari-add-to-home-screen.jpg" alt="Chức năng Add to Home Screen trên Safari">
    <figcaption class="figure__caption" style="width:300px">Chức năng Add to Home Screen trên Safari. Ảnh từ <a href="https://www.any-data-recovery.com/iphone-data/how-to-change-safari-default-homepage-on-mac-iphone-and-ipad.html">any-data-recovery.com</a>.
    </figcaption>
</figure>
<p>Ngay từ những thế hệ iPhone đầu tiên, iOS Safari đã có chức năng cho phép người dùng lưu shortcut của một website vào home screen (add to home screen) để truy cập nhanh vào lần sau. Và với những website được người dùng mở từ home screen, chúng có thể có giao diện toàn màn hình (không còn thanh địa chỉ và phần giao diện của Safari), đem tới trải nghiệm như mobile app.</p>
<p>Tuy nhiên những khả năng trên vẫn chỉ là sự hỗ trợ đơn lẻ từ nhà phát triển Apple cho những chiếc iPhone của mình. Giờ đây, tổ chức W3C đã thống nhất đặc tả cho web app với file khai báo <strong>manifest.json</strong> (tên chính thức: Web App Manifest) cho phép lập trình viên có thể tùy chỉnh:</p>
<ul>
<li>Màu theme (màu của giao diện trình duyệt và thanh status)</li>
<li>Màu nền và icon trên splash screen</li>
<li>Icon và tên app trên home screen</li>
<li>Khóa hướng xoay màn hình</li>
<li>Và một số tùy chỉnh kỹ thuật khác…</li>
</ul>
<p><a href="/images/2018/pwa/manifest-customizations.jpg" target="_blank" role="figure"><img src="/images/2018/pwa/manifest-customizations.jpg" alt="Một số tùy chỉnh có thể thấy được từ manifest.json"></a> <em>Ảnh chụp từ một <a href="https://pwa-shop.firebaseapp.com/">PWA demo do tôi viết</a> để minh họa cho một bài thuyết trình về PWA.</em></p>
<h3>Banner cài đặt web app và tích hợp sâu hơn trong Android</h3>
<figure class="figure figure--right">
    <video class="figure__image" src="/images/2018/pwa/native-add-to-home-screen.mp4" poster="/images/2018/pwa/native-add-to-home-screen.jpg" controls onclick="this.paused ? this.play() : this.pause();"
    ></video>
    <figcaption class="figure__caption" style="width:300px">Banner cài đặt web app. Bấm lên hình để play.</figcaption>
</figure>
<p>Ngoài chức năng “Add To Home Screen” bằng tay đã được hỗ trợ bởi đa số trình duyệt di động hiện nay, một số trình duyệt mới hiện nay còn có thể <strong>chủ động</strong> hiện một banner mời gọi user cài web app lên home screen.</p>
<p>Theo <a href="https://addyosmani.com/blog/getting-started-with-progressive-web-apps/">Addy Osmani</a>, người dùng sẽ được gợi ý cài web app lên home screen của Android nếu:</p>
<ul>
<li>Web app có khai báo manifest.json</li>
<li>Được tải bằng giao thức HTTPS</li>
<li>Có sử dụng service worker (xem tiếp mục sau)</li>
<li>Được ghé thăm ít nhất hai lần, với mỗi lần cách nhau ít nhất 5 phút</li>
</ul>
<p>Ngoài ra Chrome và Android đang được cải thiện để tích hợp PWA tốt hơn. Kể từ Chrome cho Android phiên bản 57, khi một PWA được lưu lại, icon của nó không chỉ xuất hiện tại home screen mà ở cả trong app drawer (trang danh sách tất cả app) và kết quả tìm kiếm app. Không những thế, Android sẽ hỗ trợ PWA của bạn có riêng một “Intent Filter” để khi có bất kỳ app khác trên Android link đến URL của web app của bạn, PWA sẽ được mở ra thay vì URL mở ở trình duyệt mặc định. <a href="https://developers.google.com/web/updates/2017/02/improved-add-to-home-screen">Xem thêm tại đây.</a></p>
<p><a href="/images/2018/pwa/pwa-integrated.jpg" target="_blank" role="figure"><img src="/images/2018/pwa/pwa-integrated.jpg" alt="Một số cải tiến tích hợp vào Android của PWA trên Chrome 57"></a> <em>Một số cải tiến tích hợp vào Android của PWA trên Chrome 57</em></p>
<h3>Hoạt động offline</h3>
<figure class="figure figure--right">
    <video class="figure__image" src="/images/2018/pwa/offline-viewing.mp4" poster="/images/2018/pwa/offline-viewing.jpg" controls onclick="this.paused ? this.play() : this.pause();"
    ></video>
    <figcaption class="figure__caption" style="width:300px">Offline demo. Bấm lên hình để play.</figcaption>
</figure>
<p>Một trong những hạn chế của web app so với native app khiến nó chưa thật sự hữu dụng và được triển khai rộng rãi đó chính là khả năng hoạt động ngay cả khi người dùng offline. Khi người dùng mất kết nối (tắt mobile data, tắt wifi, bật flight mode…) hoặc kết nối Internet chậm, web app sẽ không thể sử dụng được do nó phải lấy dữ liệu từ máy chủ trung tâm, và người dùng sẽ nhanh chóng bỏ cuộc hoặc tìm đến native app.</p>
<p>Nhờ một đặc tả mới của Web với tên gọi là <strong>Service Worker</strong>, kết hợp với CSDL tại trình duyệt, PWA đã có thể lưu lại dữ liệu bao gồm văn bản, hình ảnh hay bất kỳ định dạng nào cần thiết cho việc hoạt động offline.</p>
<h3>Nhận push notification</h3>
<p>Một tính năng đáng chú ý nữa của native app mà web app trước đây không thể làm được, đó chính là việc nhận push notification (thông báo chủ động). Push notification là một công cụ khá quan trọng cho các nhà phát hành mobile app, kích thích người dùng quay trở lại hoặc suy trì sự tương tác giữa người dùng và app của mình. Push notification cũng đang nhận được sự chú ý đặc biệt của bộ phận marketing cho những doanh nghiệp có mobile app của mình.</p>
<p>Cũng nhờ <strong>Service Worker</strong>, là một chương trình nhỏ viết bằng ngôn ngữ Web JavaScript nhưng nó chạy ngầm và độc lập với web app chính, PWA có khả năng nhận push notification như native app. Điều này đồng nghĩa với việc ngay cả khi web app và trình duyệt đã được đóng hẳn, chúng vẫn có thể nhận được notification[^5].</p>
<figure>
    <video src="/images/2018/pwa/push-notification-demo.mp4" poster="/images/2018/pwa/push-notification-demo.jpg" controls onclick="this.paused ? this.play() : this.pause();"
    ></video>
    <figcaption>Push notification demo. Bấm lên hình để play.</figcaption>
</figure>
<h3>Tự động đồng bộ khi có mạng trở lại</h3>
<p>Một khả năng khác của Service Worker, đó là hỗ trợ PWA tự động đồng bộ những yêu cầu từ phía người dùng lên server trung tâm ngay khi thiết bị có mạng trở lại.</p>
<p>Lấy ví dụ: ứng dụng nhắn tin tức thời, người dùng gửi một tin nhắn đi khi điện thoại của họ mất kết nối. Ngay khi điện thoại của họ có Internet trở lại, Service Worker sẽ tiếp tục gửi tin nhắn đi cho người dùng hoặc bất kỳ tác vụ nào cần đến Internet.</p>
<figure>
    <video src="/images/2018/pwa/background-sync.mp4" poster="/images/2018/pwa/background-sync.jpg" controls onclick="this.paused ? this.play() : this.pause();"
    ></video>
    <figcaption>Demo tự động gửi tin sau khi online. Video lấy từ <a href="https://www.youtube.com/watch?v=cmGr0RszHc8">bài thuyết trình của Jake Archibald</a>. Bấm lên hình để play.</figcaption>
</figure>
<h3>Chia sẻ bằng native banner của hệ điều hành</h3>
<figure class="figure figure--right">
    <video class="figure__image" src="/images/2018/pwa/web-share.mp4" poster="/images/2018/pwa/web-share.jpg" controls onclick="this.paused ? this.play() : this.pause();"
    ></video>
    <figcaption class="figure__caption" style="width:300px">Demo share bằng banner native của Android. Bấm lên hình để play.</figcaption>
</figure>
<p>Một tính năng tương đối hữu dụng nữa của PWA đó chính là <strong>Web Share</strong>. Để dễ hình dung, nếu bạn đang đọc bài viết này trên điện thoại, cách duy nhất để bạn chia sẻ nó là copy URL[^3] của nó và paste vào app bạn muốn share, hoặc bạn sẽ mở menu của trình duyệt ra, và bấm vào nút share. Chức năng Web Share của PWA sẽ giống như cách thứ hai vừa nêu.</p>
<p>Với PWA có sử dụng Web Share, khi bạn bấm vào nút share ngay trong trang web, banner chia sẻ mặc định của HĐH sẽ hiện ra với tất cả các app và thao tác mà bạn có thể thực hiện với một chuỗi URL hoặc chuỗi băn bản. Một sự tiện lợi giúp tăng sự tương tác trên thiết bị di động.</p>
<p>Để tiếp cận Web Share theo cách Progressive, lập trình viên sẽ kiểm tra nếu trình duyệt không hỗ trợ Web Share, nút share sẽ gọi các widget chia sẻ thông thường như trên máy tính.</p>
<h3>Quản lý đăng nhập và tự động đăng nhập</h3>
<figure class="figure figure--right">
    <video class="figure__image" src="/images/2018/pwa/credential-management.mp4" poster="/images/2018/pwa/credential-management.jpg" controls onclick="this.paused ? this.play() : this.pause();"
    ></video>
    <figcaption class="figure__caption" style="width:300px"><a href="https://credential-management-sample.appspot.com/">Demo login vào app với "1 chạm"</a>. Bấm lên hình để play.</figcaption>
</figure>
<p>Một tính năng đang dần trở thành yêu cầu phải có của trình duyệt đó là khả năng đồng bộ giữa các thiết bị và hệ điều hành khác nhau (nhưng cùng một loại trình duyệt). Hiện nay bạn đã có thể tạo một tài khoản đồng bộ trên Firefox, Opera, MS Edge và Chrome. Bạn sẽ thấy việc đồng bộ tạo sự tiện lợi cho người dùng rất nhiều đặc biệt là những ai lướt web trên nhiều thiết bị khác nhau: bookmark, lịch sử, các tab đang mở, thông tin nhập form và đặc biệt là thông tin đăng nhập (username &amp; password) của các website.</p>
<p>Với tính năng trên, người dùng sẽ dễ dàng đăng nhập vào các website trên nhiều thiết bị nhờ vào việc trình duyệt sẽ tự điền vào form đăng nhập. Tuy nhiên, một đặc tả mới dành riêng cho PWA với tên gọi <strong>Credential Management API</strong> cho phép web app thực hiện thao tác đăng nhập cho người dùng chỉ với một cú chạm và không cần phải nhập lại mật khẩu. Đây là một trong những tiện lợi của native app với tài khoản lưu sẵn mà giờ đây web app cũng có thể làm được.</p>
<h3>Quản lý thanh toán và hỗ trợ thanh toán trực tuyến</h3>
<figure class="figure figure--right">
    <video class="figure__image" src="/images/2018/pwa/web-payment.mp4" poster="/images/2018/pwa/web-payment.jpg" controls onclick="this.paused ? this.play() : this.pause();"
    ></video>
    <figcaption class="figure__caption" style="width:300px"><a href="https://emerald-eon.appspot.com/">Demo Payment Request API</a>. Bấm lên hình để play.</figcaption>
</figure>
<p>Nếu như thanh toán trên mobile và bằng mobile đang trở thanh xu hướng và đem đến sự tiện lợi chưa từng có cho người dùng, thì Web App cũng không đứng ngoài cuộc.</p>
<p>Với tên gọi <strong>Payment Request API</strong>, một đặc tả mới nữa của W3C, nó cho phép PWA chuyển thao tác thanh toán vốn nhập nhằng và dễ sai sót cho một giao diện chung hỗ trợ bởi trình duyệt. Giao diện này bao gồm các bước: hiển thị tóm tắt đơn hàng (shopping cart), thông tin giao hàng, loại thanh toán, thông tin thẻ và cả việc thực hiện thanh toán. Các form liên quan đều được hỗ trợ tự động điền vào từ thông tin thanh toán đã được lưu trên điện thoại. Và vì giao diện thanh toán lúc này là của trình duyệt nên thông tin thanh toán sẽ được đảm bảo an toàn vì các đoạn mã độc nếu được vô tình nhúng vào website cũng không có khả năng lấy được.</p>
<p>Một khi chuẩn Web này được áp dụng rộng rãi trên tất cả các HĐH mobile, việc xây dựng web app cho các platform thương mại điện tử sẽ trở nên dễ dàng và thuận tiện hơn bao giờ hết.</p>
<h2>Tiến độ hỗ trợ PWA từ các trình duyệt</h2>
<p>Đến đây chắc hẳn bạn cũng đã rất hào hứng với PWA. Tuy nhiên, một số bạn am hiểu về Web cũng sẽ có thắc mắc rằng khi nào thì những tính năng  trên của PWA sẽ đến được với đa số người dùng?</p>
<p>Tin tốt lành là đến thời điểm tôi viết bài này, các trình duyệt phổ biến nhất[^4] đã hỗ trợ <strong>Service Worker</strong>, đặc tả quan trọng nhất của PWA. Bảng bên dưới tóm tắt tiến độ hỗ trợ từng tính năng riêng rẽ của PWA tại các trình duyệt khác nhau.</p>
<p><a href="/images/2018/pwa/state-of-pwa-2018.jpg" target="_blank" role="figure"><img src="/images/2018/pwa/state-of-pwa-2018.jpg" alt="Bảng tham khảo tiến độ hỗ trợ PWA từ các trình duyệt khác nhau."></a><em>Bảng tham khảo tiến độ hỗ trợ PWA từ các trình duyệt khác nhau. Ảnh chụp từ slide <a href="https://www.youtube.com/watch?v=NITk4kXMQDw">giới thiệu PWA tại Google I/O 2018</a></em></p>
<p>Tuy nhiên tôi muốn nhắc lại rằng với cơ chế Cải Tiến Tăng Dần, PWA có thể được áp dụng ngay từ bây giờ bất kể tính năng bạn cần chưa được hỗ trợ rộng rãi. Và với tiến độ hiện tại, những tính năng vừa nêu trên sẽ được hỗ trợ hoàn toàn trên hai nền tảng di động quan trọng và phổ biến nhất (Chrome trên Android và Safari trên iOS) trong vài tháng tới đây.</p>
<h2>Hiệu quả của PWA</h2>
<p>PWA có được thế mạnh của cả hai giải pháp Web và Native. Điểm mạnh của Web đó là sự tiện lợi và dễ truy cập khi mà người dùng chỉ việc mở trình duyệt và tìm đến địa chỉ của trang web app hoặc mở từ đường link được chia sẻ thông qua mạng xã hội hoặc tin nhắn. Một khi người dùng thấy app hữu dụng và có nhu cầu quay lại, họ sẽ lưu lại shortcut của app tại home screen. Và lúc này, người dùng sẽ có được trải nghiệm của PWA như một native app thực thụ mà không phải cất công vào app store để tải về.</p>
<p>PWA đã chứng minh được hiệu quả của mình thông qua một vài con số thống kê với những app đã được triển khai thực tế:</p>
<ul>
<li><strong>02 lần</strong> là <a href="https://blog.chromium.org/2018/05/the-state-of-web-at-google-io-2018.html">số lượt sử dụng tăng</a> sau khi Starbucks chuyển từ web app sang PWA.</li>
<li>Sau khi <a href="https://developers.google.com/web/showcase/2016/alibaba">Alibaba.com triển khai PWA</a>, số giao dịch thành công (conversions) tăng <strong>76%</strong>, số lượt truy cập tăng <strong>14%</strong> trên iOS, <strong>30%</strong> trên Android và tỉ lệ tương tác với app sau khi Add to home screen tăng gấp <strong>4 lần</strong>.</li>
<li>Sau khi triển khai PWA, lượt truy cập Tinder trên mobile web tăng. Và <a href="https://medium.com/@addyosmani/a-tinder-progressive-web-app-performance-case-study-78919d98ece0">Tinder PWA có kích thước tải về nhỏ hơn</a> so với native app của nó trên Android đến <strong>90%</strong>.</li>
<li>Thương hiệu Lancôme đã cho thiết kế lại trang web mobile (<a href="http://lancome-usa.com">lancome-usa.com</a>) và <a href="https://developers.google.com/web/showcase/2017/lancome">sử dụng một số tính năng của PWA</a> với kết quả: conversions tăng <strong>17%</strong>, số lượt sử dụng trên mobile tăng <strong>51%</strong>, và đặc biệt là số lượt người dùng quay lại giỏ hàng và hoàn tất thanh toán nhờ push notification gửi nhắc nhở lên đến <strong>12%</strong>.</li>
<li><a href="http://www.niemanlab.org/2017/03/forbes-rebuilt-its-new-mobile-website-as-a-progressive-web-app/">Trang PWA thử nghiệm của Forbes</a> nhận được gấp <strong>2 lần</strong> thời gian sử dụng trung bình của người dùng so với mobile site cũ, dẫn đến số lượt bài đăng được đọc tăng đến <strong>6 lần</strong>…</li>
</ul>
<p>Xem thêm những con số thống kê về hiệu quả của PWA tại: <a href="https://www.pwastats.com/">PWAStats.com</a>.</p>
<p><img src="/images/2018/pwa/pwa-showcase.jpg" alt="PWA showcase"><em>Một số PWA đã chứng minh được hiệu quả, từ trái qua: <a href="https://m.alibaba.com">m.alibaba.com</a>, <a href="https://tinder.com">tinder.com</a>, <a href="https://m.forbes.com">m.forbes.com</a></em></p>
<h2>Kết luận</h2>
<p>Được giới thiệu chính thức <a href="https://en.wikipedia.org/wiki/Progressive_Web_Apps">từ 2015</a>, PWA đã trải qua thời gian thử nghiệm và trưởng thành đủ lâu để giờ đây chúng ta có thể khẳng định PWA chính là tương lai của Web và Web App.</p>
<p>PWA đóng góp thêm một giải pháp ứng dụng di động nhiều hứa hẹn, giải phóng doanh nghiệp khỏi sự lệ thuộc vào app store, những hạn chế của native app. Và nếu được thiết kế hợp lý, PWA sẽ là giải pháp hợp nhất cho “mọi nền tảng” từ desktop đến mobile.</p>
<hr>
<h4>Ghi chú:</h4>
<p>[^1]: Xin tóm tắt lại một số thuật ngữ về <strong>“app”</strong> trên thiết bị di động:
- Mobile app hoặc native app: (ở Việt Nam thường gọi tắt là “app”) là ứng dụng được cài đặt từ app store, được viết bằng ngôn ngữ lập trình dành riêng cho từng hệ điều hành di động khác nhau.
- (Mobile) web app: là website chạy trên trình duyệt của smart phone nhưng có trải nghiệm giống app và thường trao đổi nhiều dữ liệu giữa người dùng và website.
- Hybrid app: là ứng dụng được cài đặt từ app store, tuy nhiên được viết bằng cùng ngôn ngữ lập trình với web app. Dù hybrid app có thể cài được trên nhiều HĐH khác nhau nhưng nó chỉ cần được viết cùng một bộ mã nguồn với một ít điều chỉnh riêng cho mỗi loại HĐH mà nó hỗ trợ.</p>
<p>[^2]: Tổ chức World Wide Web Consortium có trách nhiệm chuẩn hóa các đặc tả về Web và khuyến khích các trình duyệt khác nhau phải tuân theo để các website hoạt động một cách đồng nhất bất kể trình duyệt dùng để hiển thị.</p>
<p>[^3]: URL là đường link đến một trang web bất kỳ</p>
<p>[^4]: Các trình duyệt phổ biến nhất bao gồm: Chrome, Firefox, Safari, MS Edge, Opera, Samsung Internet, UC Browser. Tại Việt Nam, trình duyệt phổ biến thứ 2 sau Chrome là CocCoc. Tuy nhiên CocCoc cũng là một trình duyệt biến thể từ mã nguồn mở của Chrome nên những tính năng của PWA cũng sẽ được hỗ trợ.</p>
<p>[^5]: Người dùng sẽ vẫn nhận được push notification cho dù họ không lưu app về home screen chỉ cần họ đã bấm đồng ý nhận push notification. Việc yêu cầu gửi push notification cần thận trọng và chỉ thực hiện khi người dùng đã thể hiện sự quan tâm đến dịch vụ của bạn. (Nếu không khả năng người dùng từ chối nhận push notification là rất cao)</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Hướng dẫn: Cài đặt hoàn chỉnh Nodejs app lên VPS Ubuntu - Phần 1</title>
    <link href="https://int3ractive.com/blog/2017/huong-dan-cai-dat-nodejs-app-len-vps-phan-1/"/>
    <updated>2017-09-27T18:07:53Z</updated>
    <id>https://int3ractive.com/blog/2017/huong-dan-cai-dat-nodejs-app-len-vps-phan-1/</id>
    <content type="html"><![CDATA[
      <h2>Giới Thiệu</h2>
<p>NodeJS tuy phát triển mạnh mẽ những năm gần đây nhưng tại Việt Nam vẫn còn ít lựa chọn để triển khai (deploy) lên Internet cho công chúng. Các dịch vụ “app engine” cho NodeJS của nước ngoài như <a href="https://www.heroku.com/">Heroku</a>, <a href="https://nodejitsu.com/">Nodejitsu</a>, <a href="https://zeit.co/now">now.sh</a>… khó tiếp cận cho developer ở Việt Nam. Ngoài ra các dịch vụ trên còn nhiều hạn chế chẳng hạn: chưa có data center đặt tại Việt Nam, không kèm giải pháp database hoặc nếu có cũng là dạng add-on.</p>
<p>Để cài đặt một web app viết bằng NodeJS, cách đơn giản nhất và tiết kiệm chi phí nhất hiện nay chính là sử dụng <strong>Cloud VPS</strong>[^1]. Cloud VPS là một server toàn quyền được ảo hóa trên một server vật lý, có tài nguyên và băng thông được dành riêng. Ở Việt Nam, hiện đã có nhiều nhà cung cấp dịch vụ Cloud VPS với chi phí khá tiết kiệm (cấu hình thấp nhất có chi phí khoảng 150k/tháng). (Vì đây là bài hướng dẫn kỹ thuật nên tôi sẽ không giới thiệu cụ thể nhà cung cấp nào).</p>
<p>Trong bài viết này, tôi sẽ hướng dẫn bạn cài đặt một NodeJS app (cụ thể viết bằng <a href="http://keystonejs.com/">KeystoneJS</a>) lên một VPS <strong>Ubuntu 16.04 LTS</strong>[^2] với kết quả mong muốn như sau:</p>
<ul>
<li>Website tải cực nhanh</li>
<li>Các tài nguyên tĩnh có cache header để tối ưu thời gian tải cho lần xem sau</li>
<li>Các tài nguyên tĩnh được gzip để tối ưu băng thông</li>
<li>Được mã hóa TLS với chữ ký số hợp lệ (miễn phí)</li>
<li>Có thể cài đặt và chạy thêm app trên cùng server</li>
</ul>
<h2>Cài Đặt Server</h2>
<p>Sau khi bạn tạo một Cloud VPS mới, thường thì nó sẽ ở trạng thái mặc định, tức là chưa có thêm bất cứ ứng dụng nào khác được cài thêm. Một số nhà cung cấp VPS thì có thể “nhanh nhảu” cài sẵn Apache HTTP server, tuy nhiên chúng ta sẽ không dùng Apache trong hướng dẫn này, nên có thể bạn phải cần <a href="https://askubuntu.com/questions/176964/permanently-removing-apache2" target="_blank">remove</a> nó khỏi hệ thống.</p>
<p>Ngoài ra, tùy nhà cung cấp VPS mà bạn sẽ được cấp tài khoản <strong>root</strong> hoặc tài khoản user bình thường nhưng có quyền <code>sudo</code>. Trong trường hợp bạn có tài khoản root thì sẽ không cần chạy những dòng lệnh bắt đầu bằng <code>sudo</code>[^3].</p>
<p>Bạn sẽ truy cập vào server thông qua giao thức SSH và sẽ cấu hình server bằng dòng lệnh trong một cửa sổ terminal. Nếu bạn dùng Windows, tham khảo hướng dẫn kết nối SSH vào Linux server tại <a href="https://support.rackspace.com/how-to/connecting-to-linux-from-windows-by-using-putty/" target="_blank">đây</a> và <a href="http://www.wikihow.com/SSH-to-a-Server" target="_blank">đây</a></p>
<p><img src="/images/2017/ssh-terminal-macos.png" alt="SSH terminal window"><em>Giao diện dòng lệnh SSH terminal trên macOS</em></p>
<p>Trước khi tiến hành cài đặt các phần mềm cần thiết, bạn cần cập nhật server Ubuntu với những package mới nhất:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">apt</span> update <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">apt</span> upgrade <span class="token parameter variable">-y</span></code></pre>
<h3>Cài đặt NGINX và Git</h3>
<p>Đầu tiên chúng ta sẽ cài 2 phần mềm có sẵn trong repository của Ubuntu: <strong>nginx</strong> &amp; <strong>git</strong></p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> nginx <span class="token function">git</span></code></pre>
<blockquote>
<p><strong>NGINX</strong> sẽ đóng vai trò <em>reversed proxy</em> và <em>static file server</em> để tiếp nhận request thông qua port mặc định 80 (http) và 443 (https). <strong>Git</strong> dùng để lấy source code của app để tiến hành build và deploy.</p>
</blockquote>
<h3>Cài đặt NodeJS VM:</h3>
<p>Tùy vào yêu cầu phiên bản Node của web app, bạn sẽ cài phiên bản Node engine tương ứng. Ở đây chúng ta sẽ dùng Node 8 LTS làm ví dụ.</p>
<p>Thêm repository source cho <strong>NodeJS 8 LTS</strong> <a href="https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions">(link tham khảo)</a>:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">curl</span> <span class="token parameter variable">-sL</span> https://deb.nodesource.com/setup_8.x <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token parameter variable">-E</span> <span class="token function">bash</span> -</code></pre>
<p>Sau đó cài NodeJS lên server:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> nodejs</code></pre>
<blockquote>
<p>Hướng dẫn này chỉ sử dụng một phiên bản Node. Nếu có yêu cầu cài đặt nhiều app trên cùng một server và sử dụng nhiều phiên bản Node khác nhau, bạn cân nhắc cài đặt Node thông qua trình quản lý nhiều phiên bản Node như <a href="https://github.com/creationix/nvm">nvm</a> hoặc <a href="https://www.npmjs.com/package/n">n package</a></p>
</blockquote>
<h3>Cài đặt MongoDB:</h3>
<p>KeystoneJS yêu cầu <a href="https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/">database MongoDB</a>. Đầu tiên là thêm PGP key cho MongoDB repository:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> apt-key adv <span class="token parameter variable">--keyserver</span> hkp://keyserver.ubuntu.com:80 <span class="token parameter variable">--recv</span> 0C49F3730359A14518585931BC711F9BA15703C6</code></pre>
<p>Thêm repository source của MongoDB dành riêng cho Ubuntu 16.04:</p>
<pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">echo</span> <span class="token string">"deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse"</span> <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token function">tee</span> /etc/apt/sources.list.d/mongodb-org-3.4.list</code></pre>
<p>Tiến hành cài MongoDB:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">apt</span> update <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> mongodb-org</code></pre>
<p>Khởi động dịch vụ <code>mongod</code> lần đầu tiên và đăng ký để nó tự chạy lúc restart server:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Khởi động mongod service</span>
<span class="token function">sudo</span> systemctl start mongod
<span class="token comment"># Bật chức năng tự chạy khi restart Ubuntu</span>
<span class="token function">sudo</span> systemctl <span class="token builtin class-name">enable</span> mongod</code></pre>
<h3>Tất cả trong một</h3>
<p>Trên đây là hướng dẫn từng bước để các bạn hiểu rõ mình đang làm những gì để khởi tạo server mới. Một khi đã hiểu rõ, bạn có thể viết tất cả những dòng lệnh đó vào một file bash script như <a href="https://gist.github.com/trongthanh/e05524446249ad7727b78941f0e93a01">ở Gist này</a> và thực thi nó:</p>
<pre class="language-shell"><code class="language-shell"><span class="token comment"># Thêm quyền thực thi cho file bash script</span>
<span class="token function">chmod</span> +x initialize.sh

<span class="token comment"># Chạy file bash script này</span>
./intialize.sh</code></pre>
<h2>Tải mã nguồn của app từ Git host và build app</h2>
<p>Trong hướng dẫn này, chúng ta sẽ lấy mã nguồn của app từ một trong 3 Git host phổ biến là Github, Bitbucket, và Gitlab và build ngay tại server.</p>
<p>Trước tiên, chúng ta sẽ tạo khóa SSH mặc định trên server bằng các bước sau (Enter mặc định với tất cả các câu hỏi):</p>
<pre class="language-shell"><code class="language-shell">ssh-keygen <span class="token parameter variable">-t</span> rsa <span class="token parameter variable">-b</span> <span class="token number">4096</span> <span class="token parameter variable">-C</span> <span class="token string">"your_email@example.com"</span></code></pre>
<p>Xuất nội dung của public key ra terminal để copy:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">cat</span> ~/.ssh/id_rsa.pub</code></pre>
<p>Tại trang settings của project trên Git host, thêm deploy key và paste nội dung của file <code>id_rsa.pub</code> vừa mới copy ở trên.</p>
<ul>
<li>Tại Bitbucket, vào Settings &gt; Chọn tiếp Access Keys</li>
<li>Tại Github, vào Settings &gt; Chọn Deploy Keys</li>
<li>Tại Gitlab, vào Settings &gt; Repository &gt; Deploy Keys</li>
</ul>
<p><img src="/images/2017/bitbucket-deploy-key.png" alt="Add deploy key"><em>Ảnh chụp popup thêm Access key của Bitbucket.</em></p>
<p>Quay trở lại terminal của server, tạo thư mục để chứa mã nguồn của app sẽ được clone vào:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">sudo</span> <span class="token function">mkdir</span> <span class="token parameter variable">-p</span> /apps/my-node-app
<span class="token comment"># Đổi owner của thư mục về user hiện tại để tiện chạy các lệnh sau đó</span>
<span class="token function">sudo</span> <span class="token function">chown</span> <span class="token parameter variable">-R</span> <span class="token environment constant">$USER</span> /apps/my-node-app/</code></pre>
<p>Lệnh ở trên sẽ tự động tạo 2 cấp thư mục <code>/apps/my-node-app</code> tại root.</p>
<blockquote>
<p>Theo quy ước, các app 3rd-party cài trên Linux thường được cài tại thư mục <code>/opt</code>. Tuy nhiên, đây là ứng dụng đặc biệt do chúng ta viết riêng nên chúng ta sẽ cài vào <code>/apps</code> để tách bạch.</p>
</blockquote>
<p>Tiếp theo, clone Git repo của app vào thư mục vừa tạo (lưu ý sử dụng lệnh clone với giao thức SSH).</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">git</span> clone git@bitbucket.org:<span class="token operator">&lt;</span>username<span class="token operator">></span>/<span class="token operator">&lt;</span>repo-name<span class="token operator">></span>.git /apps/my-node-app/</code></pre>
<blockquote>
<p>Với bản Gitlab mới nhất, bạn còn một lựa chọn nữa để lấy source từ Gitlab đó là dùng <a href="https://docs.gitlab.com/ee/user/project/deploy_tokens/">Deploy Token</a>. Khi đó, URL để clone source có dạng: <code>https://&lt;username&gt;:&lt;deploy_token&gt;@gitlab.com/user/my-node-app.git</code></p>
</blockquote>
<h3>Build app</h3>
<p>Với một Node.js app chuẩn, việc đầu tiên chúng ta cần làm là <strong>cd</strong> vào thư mục gốc của project, và chạy lệnh cài tự động các dependency package được liệt kê trong <strong>package.json</strong>:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> <span class="token function">install</span></code></pre>
<p>Sau đó, tùy vào cài đặt của dự án, ta cần chạy các lệnh để build các thành phần cần biên dịch hoặc tối ưu hóa từ mã nguồn.</p>
<p>Theo thông lệ chung của các NodeJS app, việc build project sẽ thông qua một lệnh script được config sẵn trong package.json, VD:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"gulp build"</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Do đó, việc tiếp theo sẽ là chạy script build này bằng npm:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> run build</code></pre>
<p>Tới đây, chúng ta đã có thể chạy thử app bằng lệnh <code>node keystone.js</code> (giả sử <code>keystone.js</code> là điểm start của app) và preview tại IP của server và port mặc định 3000 (VD: <a href="http://12.34.56.789:3000">http://12.34.56.789:3000</a>).</p>
<p>Với những bước cài đặt vừa rồi, bạn đã có thể chạy app cho môi trường TEST hoặc STAGING và có thể demo với khách hàng. Để giữ cho app demo tiếp tục chạy sau khi thoát SSH, bạn có thể dùng dòng lệnh <code>screen</code> (xem <a href="https://askubuntu.com/questions/904373/how-to-use-screen-command">hướng dẫn</a>).</p>
<p>Trong phần tiếp theo tôi sẽ hướng dẫn chạy app như service, đưa ra ngoài port chuẩn của web, bật mã hóa TLS/SSL… để sẵn sàng cho Production.</p>
<p>(Xem tiếp <a href="https://int3ractive.com/2018/09/huong-dan-cai-dat-nodejs-app-len-vps-phan-2.html">phần 2</a>)</p>
<hr>
<p>[^1]: Virtual Private Server
[^2]: Có thể bạn sẽ thắc mắc sao không dùng CentOS/RedHat có thiết kế bảo mật cao hơn. Theo tôi, với đại đa số những web app thông thường, Ubuntu là lựa chọn cân bằng giữa sự anh ninh và tính dễ dùng, dễ cài đặt của dòng Linux Debian.
[^3]: Bạn cần có chút kiến thức về Linux và bash command line để làm theo tutorial này dễ dàng hơn.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Font chữ cho Lập Trình Viên</title>
    <link href="https://int3ractive.com/blog/2017/font-chu-cho-lap-trinh-vien/"/>
    <updated>2017-03-27T23:37:03Z</updated>
    <id>https://int3ractive.com/blog/2017/font-chu-cho-lap-trinh-vien/</id>
    <content type="html"><![CDATA[
      <blockquote>
<p>Cập nhật 2020-03-01: Bài viết này mình viết cũng đã lâu nhưng nó vẫn có lượt view cao trên trang blog này, nên mình quyết định bổ sung thêm một số bộ font code đẹp mới vào đây thay vì viết bài khác. Các bộ font mình bổ sung ở cuối bài.</p>
</blockquote>
<p>Bạn có biết trình soạn code của mình đang dùng font chữ gì không? Ít người quan tâm đến điều này nhưng việc lựa chọn font chữ cho <a href="https://en.wikipedia.org/wiki/Source_code_editor">code editor</a> cũng ảnh hưởng ít nhiều đến hiệu suất công việc của lập trình viên vì bạn phải nhìn những dòng code nhiều giờ trong một ngày làm việc.</p>
<p>Sau nhiều năm làm việc với nhiều code editor và font khác nhau, tôi rút ra được một số đặc điểm của một <strong>font chữ tốt</strong> dành cho trình soạn code như sau:</p>
<ul>
<li><strong>Monospace</strong>: tất cả các ký tự và khoảng trắng đều cùng một cỡ, điều này cho phép canh cột và lề dễ dàng và code dễ đọc hơn với những đoạn logic lặp lại. Các font mặc định cho code editor và terminal đều là monospace.</li>
<li><strong>Dễ dàng phân biệt các ký tự</strong> <code>Il1i, 0Oo, CG</code>: có nhiều font monospace hiển thị các ký tự kể trên rất giống nhau, khiến cho việc đọc code khó khăn hơn. Với tiêu chí này, tôi đã loại một số font monospace khá phổ biến như <em>Courier New, Noto Mono, Droid Sans Mono…</em></li>
<li>Các ký tự đặc biệt cho cú pháp phải <strong>rõ, dễ đọc</strong>: <code>() [] {} =+-&lt;&gt;:;,.&quot;'</code></li>
<li>Và riêng đối với người Việt mình, thì font cho code cũng cần <strong>hỗ trợ tiếng Việt Unicode</strong> để hiển thị các chuỗi văn bản hoặc ghi chú bằng tiếng Việt (nếu có). Tiêu chí này cũng loại khá nhiều font mono đẹp và phổ biến khác như: <em>Ubuntu Mono, Menlo, Operator Mono…</em> Nếu bạn không lo vấn đề tiếng Việt, bạn có thể tìm và thử các font kể trên.</li>
</ul>
<p>Sau đây tôi sẽ liệt kê một số font tiêu biểu cho code editor đáp ứng tất cả các tiêu chí trên:</p>
<h3>Consolas</h3>
<p>Font này không miễn phí nhưng có sẵn trong Windows hoặc được cài theo bộ Microsoft Office.
<img src="/images/2017/font-consolas.png" alt="font-consolas"><em>Font Consolas hiển thị trên Sublime Text kích cỡ 15px</em></p>
<h3>Monaco</h3>
<p>Font này có sẵn trên macOS.
<img src="/images/2017/font-monaco.png" alt="font-monaco"><em>Font Monaco hiển thị trên Sublime Text kích cỡ 15px</em></p>
<h3>Roboto Mono</h3>
<p>Font monospace của bộ Roboto, font mặc định cho HĐH Android và material design. Download font <a href="https://github.com/google/fonts/tree/master/apache/robotomono">tại đây</a>.</p>
<p><img src="/images/2017/font-roboto-mono.png" alt="font-roboto-mono"><em>Font Roboto Mono (Regular) hiển thị trên Sublime Text kích cỡ 15px</em></p>
<h3>SF Mono</h3>
<p>Font SF Mono dùng để hiển thị code bên trong XCode 8+. Bạn có thể download và dùng cho mục đích cá nhân tại <a href="https://github.com/muhasturk/SFMono">trang github này</a>.</p>
<p><img src="/images/2017/font-sf-mono.png" alt="font-sf-mono"><em>Font SF Mono (Regular) hiển thị trên Sublime Text kích cỡ 15px</em></p>
<h3>Source Code Pro</h3>
<p>Font monospace được dựng bởi Adobe dành riêng cho việc hiển thị code nên rất dễ đọc và tròn trịa. <del>Đây là font yêu thích nhất của tôi.</del>. Download font <a href="https://github.com/adobe-fonts/source-code-pro">tại đây</a>.</p>
<p><img src="/images/2017/font-source-code-pro.png" alt="font-source-code-pro"><em>Font Source Code Pro (Regular) hiển thị trên Sublime Text kích cỡ 15px</em></p>
<h3>Space Mono</h3>
<p>Font monospace được dựng bởi <a href="https://medium.com/google-design/introducing-space-mono-a-new-monospaced-typeface-by-colophon-foundry-for-google-fonts-84367eac6dfb#.ck1mpvy6z">Colophon Foundry</a> cho Google Fonts. Font này có dáng chữ khá lạ và mang hơi hướng mỹ thuật hơn là cho code. Có thể download <a href="https://github.com/googlefonts/spacemono">tại đây</a>.</p>
<p><img src="/images/2017/font-space-mono.png" alt="font-space-mono"><em>Font Space Mono hiển thị trên Sublime Text kích cỡ 15px</em></p>
<h2>Xu hướng code font mới: Programming Ligature (nối chữ)</h2>
<p>Ligature: đây là hiện tượng nối nhiều chữ thành một xuất hiện cùng với kỹ thuật in ấn trong một số ngôn ngữ tự nhiên. Trong thời đại số hóa, ligature cũng được mô phỏng lại (chủ yếu là vì lý do mỹ thuật) thông qua một số <strong>font chữ có hỗ trợ</strong>. Ligature cũng đã được hỗ trợ trên các trình duyệt hiện đại và đặc biệt là từ IE 10 trở về sau.</p>
<p><img src="/images/2017/ligature-drawing.svg" alt="ligature"><em>Ví dụ ligature</em></p>
<p>Các ngôn ngữ lập trình sử dụng rất nhiều biểu tượng và toán tử tuy nhiên chúng thường được tổ hợp từ nhiều ký tự đơn giản có sẵn trên bàn phím (VD. <code>&gt;=</code>, <code>===</code>, <code>=&gt;</code>, <code>!==</code>…). Điều này bắt buộc người đọc code phải có một quá trình giải mã những tổ hợp ký tự đó thành biểu tượng toán mà chúng đang mô phỏng. (“≥”, “≡”, “⇒”, “≢”)</p>
<p>Một số font code mới đây đã bắt đầu hỗ trợ ligature cho tổ hợp các ký tự toán tử và ký hiệu giúp cho việc hiển thị chúng trực quan hơn. Trong số đó là bộ font <a href="https://github.com/tonsky/FiraCode">Fira Code</a> được dựng với rất nhiều tổ hợp ligature cho lập trình.</p>
<p><img src="/images/2017/ligature-vscode.png" alt="Fira Code ligature in VSCode"><em>Font Fira Code và ligature</em></p>
<p>Tuy nhiên Fira Code (và cả Fira Mono mà nó dựa trên) không có các ký tự tiếng Việt Unicode. Để khắc phục, bạn có thể sử dụng một font khác làm fallback khá giống Fira Code đó là <strong>Roboto Mono</strong>.</p>
<p>Hiện nay đã có một số code editor hỗ trợ ligature, trong đó có <a href="https://code.visualstudio.com/">VSCode</a> và <a href="https://atom.io/">Atom</a>. <del>Rất tiếc là Sublime Text 3 chưa hỗ trợ, và tính năng này đang được đặt hàng cho nhà phát triển ST3.</del> Sublime Text 3 kể từ build 3145 cũng <a href="https://news.ycombinator.com/item?id=15413543">đã hỗ trợ ligature</a>.</p>
<p>Sau khi cài Fira Code vào hệ thống, với <strong>VSCode</strong>, cần cài đặt các settings sau để bật ligature và font Fira Code với Roboto Mono làm fallback:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">"editor.fontFamily"</span><span class="token operator">:</span> <span class="token string">"Fira Code, Roboto Mono, monospace"</span><span class="token punctuation">,</span>
    <span class="token property">"editor.fontLigatures"</span><span class="token operator">:</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span></code></pre>
<h2>Cập nhật: Các bộ font mới cho 2020</h2>
<p>Sau đây là một số bộ font mới mà mình thấy khá đẹp và dễ đọc dùng cho code editor (một số font không hoàn toàn hỗ trợ tiếng Việt nhưng có thể dùng thêm font fallback):</p>
<h3>Hack</h3>
<p>Font này không mới và còn thiếu một số ký tự tiếng Việt, tuy nhiên nó khá đẹp và rất giống <strong>Menlo</strong> (font mono space của HĐH Mac trước đây). Nó cũng là font mặc định của trang <a href="https://carbon.now.sh">carbon.now.sh</a> dùng để tạo ảnh chụp các đoạn code để chia sẻ lên MXH.</p>
<p><img src="/images/2020/font-hack.png" alt="font-hack"><em>Font Hack (Regular) xuất ra từ <a href="http://Carbon.now.sh">Carbon.now.sh</a> kích cỡ 16px với trình duyệt Firefox</em></p>
<h3>IBM Plex Mono</h3>
<p>Đây là font monospace trong gia đình font Plex được thiết kế làm font thương hiệu cho IBM. Theo mình đây là một trong những font cho code editor hoàn hảo nhất (nếu không kể đến ligature): hoàn toàn hỗ trợ tiếng Việt, có tất cả weight từ 100 đến 700, có kiểu in nghiêng riêng theo từng weight và đặc biệt các ký tự in nghiêng <code>a, i, f, {}</code> bay bướm theo phong cách của Operator Mono trông rất gì và này nọ ;)</p>
<p><img src="/images/2020/font-ibm-plex-mono.png" alt="font ibm plex mono"><em>Font IBM Plex Mono (Regular) 16px hiển thị trong VSCode trên Ubuntu MATE*</em></p>
<p>IBM Plex Mono hoàn toàn miễn phí và có thể tải về tại trang <a href="https://github.com/IBM/plex">github của bộ IBM Plex ở đây</a>.</p>
<h3>Cascadia Code</h3>
<p>Đây là font được thiết kế để hiển thị trong ứng dụng Terminal mới của Windows và cũng sẽ dần dần được sử dụng làm font monospace mặc định trong các sản phẩm của Microsoft. Font này nhìn tổng thể khá bay bướm nhưng dễ đọc như Operator Mono. Với phiên bản hiện tại, nó hỗ trợ tốt tiếng Việt và ligature. Tuy nhiên, hiện tại nó chỉ có mỗi weight regular và không có kiểu in nghiêng riêng.</p>
<p><img src="/images/2020/font-cascadia-code.png" alt="font Cascadia Code"><em>Font Cascadia Code (Regular) 16px hiển thị trong VSCode trên Ubuntu MATE*</em></p>
<p>Download <a href="https://github.com/microsoft/cascadia-code/releases">font Cascadia Code tại đây</a>.</p>
<h3>JetBrains Mono</h3>
<p>Đây là font monospace rất mới (01/2020) đến từ nhà phát triển JetBrains, công ty đã tạo ra các IDE nổi tiếng như IntelliJ, WebStorm, Android Studio, GoLand… Theo như <a href="https://www.jetbrains.com/lp/mono/">trang web giới thiệu</a>, Jetbrains Mono được thiết kế dành riêng cho việc hiển thị code với phong cách tối giản. Nó có đầy đủ những đặc tính của một font cho code editor hiện đại như: các ký tự dễ nhầm lẫn được phân biệt rõ ràng; kiểu in nghiêng riêng giúp các code editor theme có thêm cách thức để nhấn mạnh hoặc làm nổi bật các đoạn comment; và đặc biệt là các ký tự ligature phong phú dành riêng cho các toán tử. Tuy nhiên, nó có một hạn chế (có thể chỉ là tạm thời) đó là nó chưa hỗ trợ đầy đủ tiếng Việt.</p>
<p><img src="/images/2020/font-jetbrains-mono.png" alt="font JetBrains Mono"><em>Font JetBrains Mono (Regular) 16px với fallback Roboto Mono hiển thị trong VSCode trên Ubuntu MATE*</em></p>
<p>Download <a href="https://www.jetbrains.com/lp/mono/">font JetBrains Mono tại đây</a>.</p>
<h2>Xem thêm:</h2>
<ul>
<li><a href="http://app.programmingfonts.org/#firacode">Programmingfonts.com</a></li>
<li><a href="https://github.com/tonsky/FiraCode#editor-support">Các code editor và terminal hỗ trợ ligature</a></li>
<li><a href="https://github.com/tonsky/FiraCode#alternatives">Các font code có ligature khác</a></li>
</ul>
<hr>
<p><small><strong>*</strong>: Theme được sử dụng là <strong>Boxy Ocean (dimmed bg)</strong> trong bộ theme <a href="https://marketplace.visualstudio.com/items?itemName=trongthanh.theme-boxythemekit">Boxy Theme Kit</a> do tôi port từ Sublime Text sang.</small></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Sử dụng ký pháp BEM cho CSS</title>
    <link href="https://int3ractive.com/blog/2015/ky-phap-bem-trong-css/"/>
    <updated>2015-12-12T04:41:33Z</updated>
    <id>https://int3ractive.com/blog/2015/ky-phap-bem-trong-css/</id>
    <content type="html"><![CDATA[
      <blockquote>
<p>Bài viết này được dịch một phần từ bài viết <a href="https://css-tricks.com/bem-101/">BEM 101</a> của CSS Tricks cùng với một số ý kiến và giải thích của cá nhân.</p>
</blockquote>
<h2>Ký pháp BEM là gì</h2>
<p>BEM viết tắt của Blocks, Elements, Modifiers, là một phương pháp đặt tên class cho HTML và CSS. Được phát triển <a href="https://en.bem.info">tại Yandex</a> giúp lập trình viên hiểu rõ hơn mối quan hệ giữa HTML và CSS trong dự án front end.</p>
<p>Ví dụ sau đây sẽ minh hoạ cách sử dụng ký pháp BEM:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Một Block (khối) độc lập */</span>
<span class="token selector">.btn</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

<span class="token comment">/* Element (phần tử) con, phụ thuộc vào Block ở trên */</span>
<span class="token selector">.btn__price</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

<span class="token comment">/* Modifier (bộ điều chỉnh) thay đổi trạng thái của Block */</span>
<span class="token selector">.btn--orange</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.btn--big</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre>
<p>Với cách đặt tên class này, ta có <strong>Block</strong> sẽ đại diện cho một component, và trong ví dụ ở đây, là một button <code>.btn</code>. Block cũng sẽ đóng vai trò là một <em>parent</em> mà trong nó sẽ có một hoặc nhiều hơn <strong>Element</strong> con liên quan. Tên class cho Element và mối quan hệ của nó với Block sẽ được diễn tả bằng tên của Block, tiếp theo là <em>hai gạch dưới</em>, và cuối cùng là tên của Element <code>.btn__price</code>. Thành phần thứ ba của BEM là các <strong>Modifier</strong> mà chúng sẽ giúp điều chỉnh các trạng thái hoặc phái sinh khác của Block / Element. Tên của Modifier sẽ được nối với tên Block / Element phía trước bởi <em>02 gạch ngang</em> <code>.btn--orange</code>.</p>
<p>Trong HTML, ký pháp BEM sẽ được dùng như sau:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn--big btn--orange<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://int3ractive.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn__price<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>$9.99<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn__text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Subscribe<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p><a href="http://codepen.io/team/css-tricks/pen/226a65c8f7d64615aabd45048d1d3b6d"><img src="/images/2015/bem-btn-example.jpg" alt="BEM buttons example" title="BEM buttons example"><em>Xem demo của ví dụ trên tại CodePen</em></a></p>
<p>Ấn tượng đầu tiên với bạn có thể là tên class quá xấu và mất thời gian hơn so với việc tạo riêng một class mới cho một kiểu button mới. Tuy nhiên, ký pháp BEM sẽ mang lại nhiều lợi ích mà tôi sẽ phân tích tiếp theo sau đây:</p>
<h2>Tại sao sử dụng ký pháp BEM</h2>
<p>Trước tiên, ký pháp BEM giúp người mới tham gia dự án dễ dàng phát hiện ra các trạng thái và các đối tượng con của một component đã được viết sẵn. Điều này giúp tránh cho họ phải viết lại những kiểu CSS đã có sẵn và hạn chế việc viết thừa code hoặc trùng kiểu CSS, điều mà rất hay xảy ra trong dự án lớn có nhiều người tham gia.</p>
<p>Thứ hai, chỉ cần đọc HTML, bạn vẫn có thể nhanh chóng nắm được các thành phần phụ thuộc lẫn nhau. Trong ví dụ trên, bạn dễ dàng nhìn thấy <code>.btn__price</code> phụ thuộc vào <code>.btn</code> mặc dù bạn chưa biết vai trò cụ thể của nó ngay lập tức.</p>
<p>Thứ ba, với ký pháp BEM, mọi định nghĩa chỉ có một cấp class và không lồng cấp. Điều này giúp cho độ ưu tiên (specificity) chung của hệ thống CSS thấp. Đây là một lợi thế vì sau này bạn không phải “chiến đấu” với specificity của những thuộc tính đã có sẵn (VD: siêu lồng cấp <code>.a .b .c .d .e {...}</code>) cũng như vận dụng những kỹ thuật không hay để thay thế được style (chẳng hạn <code>!important</code> hay inline CSS).</p>
<p>Quy luật thác nước cascading của CSS là con dao hai lưỡi: nó giúp dễ dàng định nghĩa những thuộc tính và kiểu chung trên những selector tổng quát mà không cần phải khai báo lặp lại trên từng phần tử, nhưng nếu không nắm được tầm ảnh hưởng, lập trình viên CSS rất dễ gây ra những tác động phụ đến các đối tượng không liên quan khi chỉnh sửa trên những class có sẵn hoặc thậm chí viết mới. Với ký pháp BEM, lập trình viên sẽ tự tin hơn khi bắt tay chỉnh sửa hoặc viết thêm style vì đã biết rõ tầm ảnh hưởng của selector mà mình đang viết ra.</p>
<p>Tóm lại, ký pháp BEM, nếu áp dụng triệt để, sẽ giúp cải thiện sự phối hợp giữa các thành viên trong nhóm. Ngoài ra, nó buộc người viết CSS phải đầu tư suy nghĩ về việc xây dựng những component độc lập và tái sử dụng được (phù hợp với tiêu chí của <a href="https://github.com/stubbornella/oocss/wiki">OOCSS</a>).</p>
<h2>Sử dụng BEM với SASS</h2>
<p>Với phiên bản SASS mới nhất hiện nay, việc viết theo ký pháp BEM trong SCSS dễ dàng và thuận tiện hơn bao giờ hết.</p>
<p>Bạn vẫn sẽ sử dụng cách viết lồng để cô lập khối component và kết hợp với biểu tượng <em>parent</em> <code>&amp;</code> của SASS để đặt tên cho Element và Modifier mà không phải đánh lại tên của Block. VD:</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.block </span><span class="token punctuation">{</span>

    <span class="token selector"><span class="token parent important">&amp;</span>__element </span><span class="token punctuation">{</span><span class="token punctuation">}</span>

    <span class="token selector"><span class="token parent important">&amp;</span>--mod </span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Mặc dù viết lồng cấp, khi được biên dịch thành CSS, chúng vẫn được trải phẳng thành một cấp class theo đúng tinh thần của BEM:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.block</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

<span class="token selector">.block__element</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

<span class="token selector">.block--mod</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
<p>Nếu bạn sử dụng LibSass (nhanh hơn rất nhiều lần bản gốc Ruby) để biên dịch SASS, thì hãy đảm bảo các công cụ wrapper được cập nhật các phiên bản tương đương hoặc mới hơn như sau: node-sass <a href="https://github.com/sass/node-sass/releases/tag/v3.4.0">3.4.0</a>, gulp-sass <a href="https://github.com/dlmanning/gulp-sass/releases/tag/v2.1.0">2.1.0</a> (nếu sử dụng <a href="https://github.com/gulpjs/gulp">GulpJS</a>) và grunt-sass <a href="https://github.com/sindresorhus/grunt-sass/releases/tag/v1.1.0">1.1.0</a> (nếu sử dụng <a href="https://github.com/gruntjs/grunt">GruntJS</a>)</p>
<p>Thế còn LESS? Vì tôi không sử dụng LESS nên sẽ không đề cập ở đây. Bạn có thể giúp bổ sung hướng dẫn cho LESS nếu nó có cú pháp trợ giúp tương đương.</p>
<h2>Các ý kiến không đồng tình</h2>
<p>Vẫn có một số ý kiến hoài nghi và không đồng tình với phương pháp đặt tên này.</p>
<h3>Tên class quá xấu</h3>
<p>Đồng ý với bạn rằng BEM trông kỳ quặc, tuy nhiên khả năng mà nó đem lại vô cùng lớn và sẽ hoàn toàn xoá mờ hạn chế về mặt “ngoại hình” của nó.</p>
<p>Ngoài ra BEM đòi hỏi phải gõ nhiều chữ hơn và chiếm nhiều byte ký tự hơn, tuy nhiên với việc sử dụng SASS như trên và việc gzip file đã trở thành tiêu chuẩn như hiện nay, những điều đó không còn là vấn đề so với lợi ích mà BEM mang lại.</p>
<h3>Descendant selector vẫn giải quyết được vấn đề như trước giờ</h3>
<p>Có một <a href="https://twitter.com/samuelfine/status/575645771334291456">chỉ trích</a> dành cho BEM thế này: Thay vì viết</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.site-search</span>        <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.site-search__field</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.site-search--full</span>  <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
<p>Họ đặt vấn đề rằng tại sao không viết như thế này:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.site-search</span>        <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.site-search input</span>  <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.site-search.full</span>   <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
<p>Rõ ràng cả hai cách viết đều có thể giúp hiện thực được component cụ thể này và cách thứ hai có vẻ “gọn gàng” hơn. Tuy nhiên khi CSS của toàn bộ dự án trở nên lớn và phức tạp hơn, thì rất khó tránh khỏi các kiểu được định nghĩa chồng chéo lên nhau ngoài tầm kiểm soát.</p>
<p>Thử tưởng tượng <code>.site-search</code> cũng nằm trong một container tên <code>.main</code> và những <code>input</code> bên trong <code>.main</code> cần được style với <code>.main input</code>. Như vậy, <code>input</code> bên trong <code>.site-search</code> sẽ bị điều chỉnh một cách không mong muốn.</p>
<p>Tương tự, nếu như <code>.full</code> trong ví dụ trên hoặc một tên phổ biến như <code>.label</code> được dùng như modifier, thì sẽ có rủi ro (rất cao) là một ngày nào đó một lập trình viên khác định nghĩa một class global trùng tên và sẽ làm hỏng style của element kia.</p>
<p>Ngoài ra, khi bạn đọc trong ngữ cảnh HTML, bạn sẽ khó thấy được quan hệ ràng buộc giữa <code>input</code> và <code>.full</code> với block <code>.site-search</code>.</p>
<h3>“Tôi đơn giản là không thích ký pháp này”</h3>
<p>Một số người khi nhìn thấy cách đặt tên BEM đã ngay lập tức bác bỏ nó. Họ không thích BEM, đó là quyền của họ, tuy nhiên sẽ là vô lý nếu phản bác việc cần có một số quy tắc đặt tên để dễ dàng nắm bắt và quản lý CSS trong dự án trung và lớn.</p>
<p>Hơn nữa, bạn hoàn toàn có thể nghĩ ra cho mình một cách đặt tên khác cho hợp sở thích, nhưng vẫn dựa trên nguyên tắc của BEM đã đề ra. Là kết quả đúc kết từ những kiến trúc CSS lớn và phức tạp trước đây, đề xuất của BEM không phải vô tình lại có một số điểm chung với các phương pháp quản lý CSS khác như SMACSS hay OOCSS. Lấy ví dụ khái niệm module của SMACSS:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Ví dụ một module */</span>
<span class="token selector">.btn</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>

<span class="token comment">/* Modifier của một module */</span>
<span class="token selector">.btn-primary</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>

<span class="token comment">/* Btn Module với State */</span>
<span class="token selector">.btn.is-collapsed</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span></code></pre>
<p>Trong các phương pháp quản lý CSS vừa kể trên thì chỉ có BEM là làm rõ được mối quan hệ với các thành phần con bên trong.</p>
<p>Tóm lại, mỗi phương pháp đều có ưu nhược điểm. Quan trọng là cả team phải có phương pháp tiếp cận khoa học và áp dụng triệt để thì kiến trúc CSS của cả dự án mới vững và dễ bảo trì.</p>
<h2>Câu hỏi thường gặp:</h2>
<p>❓<strong>Hỏi:</strong> Element có modifier hay không?<br>💬️ <strong>Đáp:</strong> Có. Element có thể có modifier riêng của nó. Ví dụ:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.accordion__copy--open</span> <span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>❓<strong>Hỏi:</strong> Có cần phải đặt tên class cho tất cả element (thẻ HTML) trong block hay không?<br>💬️ <strong>Đáp:</strong> Không cần thiết, chỉ những element cần có style riêng được viết trong CSS. Tuy nhiên cũng không nên lạm dụng những thẻ wrapper (phổ biến nhất là DIV) một cách vô tội vạ và không có chức năng vai trò cụ thể nào. Như vậy việc đặt tên element con cũng khiến bạn phải suy nghĩ một tag nào đó có thật sự cần thiết thêm vào trong block hay không.</p>
<p>❓<strong>Hỏi:</strong> Bên trong element con <code>foo</code> có một tag đóng vai trò một element con <code>bar</code> khác của block, vậy việc đặt tên class cho element <code>bar</code> này như thế nào? Có nên đặt là <code>.block__foo__bar</code>?<br>💬️ <strong>Đáp:</strong> Vẫn đặt bằng tên block và hai gạch dưới rồi đến tên element <code>.block__bar</code>, không chen giữa bằng <code>foo__</code>. Nói tóm lại, tên của element chỉ cần thể hiện quan hệ phụ thuộc với block, không cần phải chỉ rõ sự lồng bên trong nhau của các element con. (Xem thêm ví dụ trong câu hỏi tiếp theo)</p>
<p>❓<strong>Hỏi:</strong> Một thẻ HTML có thể là element của 2 block khác nhau không?<br>💬️ <strong>Đáp:</strong> Hoàn toàn có thể. Hãy xem ví dụ sau:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn--big btn--orange<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://int3ractive.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn__price<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>i</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>icon icon--dollar-sign btn__icon<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>i</span><span class="token punctuation">></span></span>9.99<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn__text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Subscribe<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>Button có biểu tượng dollar-sign là một block <code>.icon</code>. Có thể trong block <code>.btn</code>, biểu tượng dollar-sign cần được style riêng, nên cần có một cái tên xác định rõ vai trò và style cho element này là <code>.btn__icon</code>. Nếu block <code>.icon.icon--dollar-sign</code> được dùng ở một ngữ cảnh khác, thì rõ ràng nó không cần class <code>.btn__icon</code> nữa vì tên class đã chỉ rõ sự ràng buộc với block <code>.btn</code> và chỉ được thêm vào khi ở bên trong nó.</p>
<p>❓<strong>Hỏi:</strong> Một element con có thể đóng vai trò là block của riêng nó không? Có thể xây dựng chuỗi component phụ thuộc nhau như <code>.a__b__c</code> không?<br>💬️ <strong>Đáp:</strong> Câu hỏi này thật sự ngoài tầm hiểu biết và kinh nghiệm của tôi. Có thể có những hoàn cảnh đặt biệt như vậy. Tuy nhiên, theo tôi, nếu có cũng không nên quá 2 cấp, tức là element con chỉ đặt đến <code>.a__b__c</code> là tối đa. Điều này là để sự phụ thuộc không quá sâu, làm giảm khả năng dùng lại của block (portability) và sự linh hoạt của các đối tượng CSS theo tinh thần OOCSS. Xem ví dụ bên dưới.</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* block list */</span>
<span class="token selector">.list</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
<span class="token comment">/* item là con của list */</span>
<span class="token selector">.list__item</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
<span class="token comment">/* link là con của block list__item, để phân biệt với list__link
hoặc chỉ rõ mối quan hệ phụ thuộc giữa item và link*/</span>
<span class="token selector">.list__item__link</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span></code></pre>
<h2>Sai lầm hay mắc phải khi sử dụng BEM:</h2>
<p>Tôi xin hẹn lại về vấn đề này trong một bài viết khác, khi mà bản thân đã ứng dụng nhiều và quan sát được những ví dụ thực tiễn hơn để tổng hợp những sai lầm hay mắc phải do ảnh hưởng từ phương pháp cũ cũng như cách hiểu chưa đúng về phương pháp BEM này.</p>
<p><small>Còn tiếp…</small></p>
<p>Xem thêm:</p>
<ul>
<li>Bài viết <a href="http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/">giới thiệu BEM của CSSWizadry</a></li>
<li>Bài viết <a href="http://www.smashingmagazine.com/2012/04/a-new-front-end-methodology-bem/">giới thiệu BEM của Smashing Magazine</a></li>
<li><a href="http://webuniverse.io/css-organization-naming-conventions-and-safe-extend-without-preprocessors/">Sử dụng BEM và @extend của SASS</a></li>
<li>Bài viết <a href="https://medium.com/fed-or-dead/battling-bem-5-common-problems-and-how-to-avoid-them-5bbd23dee319">5 sai lầm phổ biến với BEM</a></li>
</ul>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Goodbye Blogger. Hello GitHub Pages.</title>
    <link href="https://int3ractive.com/blog/2015/goodbye-blogger-hello-github-pages/"/>
    <updated>2015-09-27T06:56:17Z</updated>
    <id>https://int3ractive.com/blog/2015/goodbye-blogger-hello-github-pages/</id>
    <content type="html"><![CDATA[
      <p>I have migrated my blog from Blogger to GitHub Pages. I am so far happy with it.</p>
<h2>Why The Change?</h2>
<p>My ultimate motivation of this move is the frustration of maintaining a long post’s format and hierarchy across multiple platforms and editors. The blog post needed reviewing and editing from different people, so I used Google Doc as the collaborating tool. But its rich format didn’t play nice with Blogger’s WYSWYG editor, so I had to paste the content as plain text and did the formating and URL linking all over again.</p>
<p>It was when I realized that, rich text editors are a nuisance to long and serious writing, and why some new blog platforms adopting plain text editors (with specialized formating syntax) exclusively. Editing in plain text, in fact, encourages me to focus on the ideas and contents. Besides, I’m not writing just texts but using the <a href="https://help.github.com/articles/github-flavored-markdown/">Markdown</a> syntax (you should have heard of it) which allows me to annotate the intended hierarchy, web links and images, etc. without compromising the convenience of version tracking or any means of writing collaboration.</p>
<p>Besides, here are other reasons of the move:</p>
<ul>
<li>Blogger’s WYSWYG editor is way out-dated and lousy. It handles new lines poorly and makes my posts, underneath the markups, like a single paragraph with just line breaks. You can suggest that I could write in HTML since I’m a Front End developer, but authoring HTML is a distraction to my focus on writing.</li>
<li>Blogger’s XML-based template format is difficult to use and customize. Besides it doesn’t provide a separate CSS file but inlining to the output HTML. This has kept me from rewriting my blog’s theme for a long time.</li>
<li>There is no static file storage for the blog post’s extras. Although it come with handy photo uploading service, for other stuff like downloadable assets and code demos, I had to reside on other services like Github or FileDen which often have cross domain issues or risk of service termination.</li>
</ul>
<h2>Moving to GitHub Pages</h2>
<p><a href="https://pages.github.com/">GitHub Pages</a> allows me to overcome all shortcomings above.</p>
<p>Take the issue with text formating for example. Under the hood, GitHub Pages use <a href="http://jekyllrb.com">Jekyll</a> which is a template-enabled static site generator. That means, I can edit and keep my blog posts in markdown text. At GitHub side, my templates and posts are processed automatically to create a nice static website. (Let me discuss how to edit Markdown text effectively in another post).</p>
<p>A static site means I have all the freedom to customize the theme with the tooling of Front End I’m used to. And the Liquid template language offered by Jekyll is quite similar to Handlebars or EJS.</p>
<p>Another good thing with GitHub is that I can check in any kind of files to the blog repository and the post’s extra assets can now be hosted together with the blog for free.</p>
<p>Lastly, Jekyll does have a <a href="http://import.jekyllrb.com/docs/blogger/">Blogger migration tool</a> and it has well documented settings that allows me to migrate my blog without altering the post URL scheme. And GitHub Pages, for long, has support for custom domains.</p>
<h3>Nothing is perfect!</h3>
<p>GitHub Pages has the flaws of any static websites. But in this era of <a href="https://en.wikipedia.org/wiki/Software_as_a_service">SaaS</a>, many of them can be addressed easily, even at no cost:</p>
<h4>Comments</h4>
<p>By using a commenting / discussion service like <a href="https://disqus.com">Disqus</a>, <a href="https://developers.facebook.com/docs/plugins/comments">Facebook Comments Plugin</a>, or <a href="http://googlesystem.blogspot.com/2013/04/add-google-comments-to-any-web-page.html">G+ Comments</a>, etc… my static website can accept readers’ comments and feedbacks although it doesn’t have a database or any server-side scripts. In fact, I have swapped Blogger’s comment system with Disqus for a long time since the latter accepts users with accounts from multiple social networks.</p>
<h4>Site search</h4>
<p>For this, we can use Google’s <a href="https://cse.google.com">Custom Search Engine</a> which can be easily installed on any static HTML pages. The service provides full text search with Google-grade algorithm. You can even force CSE to update your page index if you worry your latest blog won’t show up in the results.</p>
<p>In addition we can write a template for the archive page, in which visitors can have quick glance of all published blog posts.</p>
<h4>RSS</h4>
<p>This can be solved by an RSS/Atom template which outputs an updated feed XML every time I push new blog post. However, the trouble has been recently taken away when GitHub Pages rolled out <a href="https://help.github.com/articles/atom-rss-feeds-for-github-pages/">built-in support</a> for blog feeds.</p>
<h4>Tags &amp; categories</h4>
<p>Currently, Jekyll in GitHub Pages does not support auto tag or category pages generation. However, you can implement a <a href="http://www.minddust.com/post/tags-and-categories-on-github-pages/">custom template</a> for tags and categories, but it involves some manual preparation.</p>
<h3>The new theme</h3>
<p>I have found a nice minimalist blog theme called <a href="http://startbootstrap.com/template-overviews/clean-blog/">Clean Blog</a> created by <a href="http://startbootstrap.com/">Start Bootstrap</a> and <a href="https://github.com/trongthanh/startbootstrap-clean-blog-jekyll">modified</a> it to fit with GitHub Pages and my preferences. You can find the source code and my comments on the changes of this blog theme <a href="https://github.com/trongthanh/startbootstrap-clean-blog-jekyll">here</a>.</p>
<p>At the end of the day, moving my blog from Blogger (<a href="http://int3ractive.blogspot.com">archive site</a>) to GitHub Pages (<a href="https://github.com/trongthanh/trongthanh.github.com">source code</a>) is a smooth transition and returning visitors may only notice the change in theme and a much faster loading time.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Knowledge vs. Experience</title>
    <link href="https://int3ractive.com/blog/2015/knowledge-vs-experience/"/>
    <updated>2015-09-19T06:32:14Z</updated>
    <id>https://int3ractive.com/blog/2015/knowledge-vs-experience/</id>
    <content type="html"><![CDATA[
      <p><img src="/images/2015/knowledge-experience.jpg" alt="Knowledge &amp; Experience" title="Knowledge &amp; Experience"><em>Image courtesy of <a href="http://www.mrichatham.com/2014/01/07/experience-vs-knowledge-and-why-experience-is-more-important/">mrichatham.com</a></em></p>
<p>Recently, I am annoyed with some people thinking they can use their education and training to overcome lack of experience, or in other words, claiming that knowledge can replace experience. Though it has been <a href="http://www.mrichatham.com/2014/01/07/experience-vs-knowledge-and-why-experience-is-more-important/">said</a> <a href="http://robertsontrainingsystems.com/blog/knowledge-vs-experience/">before</a>, I want to express it again in my own thoughts and from my own experience (not a pun):</p>
<blockquote>
<p>Knowledge can be trained. Experience cannot.</p>
<p>Knowledge can be get from books. Experience can only be earned from doing.</p>
<p>Knowledge can be stuffed in a short time. Experience requires time.</p>
<p>Knowledge lets you do a task properly. Experience lets you do that task quicker and more efficiently.</p>
<p>Knowledge shows how to fix problems. Experience shows how to find the causes.</p>
<p>Knowledge reduces the errors you make. Experience helps you correct them gracefully. (And as human, we will never be error-free)</p>
<p>Knowledge can only lead to ability. Experience can lead to mastery.</p>
<p>With knowledge, you can do OK work. With experience, you can do GREAT work.</p>
</blockquote>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Mức Tối Thiểu Của Lập Trình Viên Front End</title>
    <link href="https://int3ractive.com/blog/2015/muc-toi-thieu-cua-lap-trinh-vien-front-end/"/>
    <updated>2015-08-17T07:55:00Z</updated>
    <id>https://int3ractive.com/blog/2015/muc-toi-thieu-cua-lap-trinh-vien-front-end/</id>
    <content type="html"><![CDATA[
      <p><img src="https://2.bp.blogspot.com/-mF8YcFrCO8Q/VXPniJnFrZI/AAAAAAAABDY/T7PQ5bKPoYs/s640/front-end-baseline.png" alt="Tag Cloud" title="Tag Cloud được tạo bằng Wordle.net"></p>
<h3>Mức kỹ năng tối thiểu (baseline) là gì?</h3>
<p>Là hệ thống kỹ năng và kiến thức tối thiểu của một nhân viên kỹ thuật cần có để có làm việc trong nhóm một cách hiệu quả và không cần nhiều sự trợ giúp.</p>
<h3>Tại sao phải có mức tối thiểu cho lập trình viên Front End?</h3>
<p>Từ kinh nghiệm làm việc trong nhiều nhóm phát triển phần mềm lớn nhỏ khác nhau, tôi nhận ra rằng một lập trình viên mới gia nhập rất cần được chỉ dẫn về quy ước và quy trình làm việc của nhóm phát triển để có thể nhận nhiệm vụ cũng như thay thế và hỗ trợ đồng nghiệp một cách trơn tru. Ngoài ra, những lập trình viên ít kinh nghiệm cũng cần được đào tạo những kiến thức tối thiểu để có thể đảm bảo được yêu cầu kỹ thuật cũng như hiệu suất khi thực hiện dự án. Tất cả những kiến thức và kỹ năng đó khi tập hợp lại sẽ thành mức kỹ năng tối thiểu của một lập trình viên trong môi trường phát triển phần mềm.</p>
<p>Khi xây dựng đội phát triển Front End tại <a href="https://naustud.io">Nâu Studio</a>, tôi đã nghiên cứu thật kỹ về những kỹ năng và kiến thức chuyên môn tối cần thiết để được đưa vào hệ thống kiến thức cơ sở của nhóm và làm tâm điểm của việc huấn luyện căn bản.</p>
<p>Lấy cảm hứng từ bài viết <a href="http://rmurphey.com/blog/2012/04/12/a-baseline-for-front-end-developers/">A Baseline for Front End Developers</a> của Rebecca Murphey, tôi sẽ ghi lại dưới đây mức tối thiểu về kiến thức cho các lập trình viên Front End hiện đại với hệ thống phù hợp hơn cho người mới bắt đầu cũng như cập nhật những xu hướng mới nhất của năm 2015.</p>
<p>Để bắt đầu, tôi sẽ bàn về 3 trụ cột của Web Front End:</p>
<h2>HTML</h2>
<p><img src="https://4.bp.blogspot.com/-EVKCwQoon_g/VdGOAEWdqaI/AAAAAAAARiY/YhGiwwAihW8/s400/html-for-baby.jpg" alt="Hình minh hoạ cho phần HTML" title="HTML for baby"></p>
<p>Thực tế cho thấy có rất nhiều lập trình viên xem nhẹ HTML. Theo quan sát của tôi, nhiều lập trình viên dùng tag HTML rất tuỳ tiện, thêm các thẻ bao ngoài một cách vô tội vạ và kết quả là việc xử lý giao diện tuỳ ứng (responsive) cũng như canh lề rất vất vả. Khi làm càng nhiều, bạn sẽ nhận ra rằng HTML được viết gọn gàng và súc tích sẽ giúp ích rất nhiều cho việc xử lý CSS và cải thiện tốc độ website trên trình duyệt (đặc biệt là trên thiết bị di động). Làm được như vậy đòi hỏi một kỹ năng tuyệt vời, và tôi dám nói rằng viết HTML là cả một nghệ thuật.</p>
<p>Vì vậy, để trở thành một lập trình viên HTML thành công, bạn phải có khả năng kết hợp các phần tử (element) HTML để đạt yêu cầu cả về ngữ nghĩa và tính tối ưu. Điều này có nghĩa bạn phải nắm vững các quy luật layout mặc định và ý nghĩa sử dụng của tất cả các thẻ HTML. Ngoài việc tiến bộ dần thông qua kinh nghiệm thực tế, bạn có thể tăng tốc kỹ năng HTML của mình nếu được đào tạo bài bản.</p>
<p>Các tài liệu hỗ trợ:</p>
<ul>
<li><a href="http://html5doctor.com/">HTML5 Doctor</a>: Tập hợp các bài phân tích cách sử dụng các thẻ HTML cho đúng ngữ nghĩa và mục đích.</li>
<li><a href="https://docs.webplatform.org/wiki/html/tutorials">HTML basic tutorials</a>: Tài liệu hướng dẫn HTML căn bản, phù hợp cho người mới bắt đầu.</li>
</ul>
<h2>CSS</h2>
<p><img src="https://i.imgur.com/Q3cUg29.gif" alt="CSS!!!" title="CSS!!!"></p>
<p>Rất nhiều người mới bắt đầu với Web, đặc biệt là sinh viên CNTT ở Việt Nam, được học rất sơ sài về CSS trên lớp và các sách, giáo trình liên quan đều đã lỗi thời. Đa số các bạn sẽ học CSS bằng phép thử-và-sai (trial and error) và đó là một cách học cực kỳ kém hiệu quả.</p>
<p>Điều này không tồn tại trong đội lập trình viên của Nâu. Những khái niệm căn bản của CSS như thứ tự thác nước (cascading), luật về độ ưu tiên (specificity), bộ chọn lọc (selectors), sự thừa kế, mô hình hộp (box model), và ngữ cảnh xếp chồng (stacking context) phải được các bạn hiểu rõ.</p>
<p>Sau những kiến thức căn bản, bạn nên bắt đầu tìm hiểu về <a href="https://github.com/stubbornella/oocss/wiki">CSS hướng đối tượng (OOCSS)</a> hoặc bắt đầu thực hành những chỉ dẫn trong tài liệu <a href="http://cssguidelin.es/">Những nguyên tắc về CSS</a></p>
<p>Ngoài ra, một lập trình viên Front End giỏi luôn thủ sẵn một số thủ thuật về CSS. Chẳng hạn, bạn phải biết tất cả các mẹo canh giữa nội dung theo chiều dọc khác nhau khi mà Flexbox vẫn chưa được áp dụng rộng rãi. Bạn cũng phải biết khi nào cần dùng pseudo-elements, tạo các khối hình học bằng CSS thuần, icon từ webfont, hoặc sprite sheet… để hiện thực giao diện với hiệu suất và độ tương thích tốt nhất.</p>
<p>Cuối cùng, một lập trình viên Front End hiện đại phải biết sử dụng một ngôn ngữ biên dịch sang CSS (như SASS hoặc LESS) để cải thiện khả năng bảo trì và hiệu suất làm việc với CSS.</p>
<p>Một khi nền tảng đã được nắm vững, bạn sẽ thấy việc học thêm hoặc ứng dụng những tính năng mới của CSS3 sẽ chẳng có chút khó khăn.</p>
<p>Tài liệu tham khảo:</p>
<ul>
<li><a href="https://docs.webplatform.org/wiki/css/tutorials">CSS basic tutorials</a>: Hướng dẫn CSS căn bản</li>
<li><a href="https://github.com/stubbornella/oocss/wiki">OOCSS</a>: Các khái niệm về CSS hướng đối tượng</li>
<li><a href="http://cssguidelin.es/">CSS Guidelines</a>: Những nguyên tắc CSS</li>
<li><a href="http://css-tricks.com/">CSS Tricks</a>: Các thủ thuật CSS</li>
</ul>
<h2>JavaScript</h2>
<img align="right" src="https://2.bp.blogspot.com/-bhkZ88s-OXg/VdGOraNblLI/AAAAAAAARig/U7fH8-C9UbU/s320/eloquent-javascript-cover.png " alt="Eloquent JavaScript book cover" />
<p>Nếu như vài năm trước, jQuery là yêu cầu bắt buộc để nhập môn Giao Diện Web thì bây giờ <a href="http://youmightnotneedjquery.com/">không còn nữa</a>. Tuy nhiên theo tôi nó vẫn rất hữu ích cho những người mới bắt đầu thực hành JavaScript trong bối cảnh tính năng và sự tương thích giữa các trình duyệt vẫn chưa đồng nhất.</p>
<p>Tiếp theo sau jQuery, việc nắm vững kiến thức về ngôn ngữ JavaScript thuần vẫn là mục tiêu tối quan trọng cho người làm Front End. Bên cạnh học từ quyển sách kinh điển <a href="http://www.amazon.com/exec/obidos/ASIN/0596517742/wrrrldwideweb">JavaScript: The Good Parts</a> do Rebecca giới thiệu, ngày nay bạn có thêm những lựa chọn miễn phí nhưng nội dung vẫn chất lượng như quyển <a href="http://eloquentjavascript.net/">Eloquent JavaScript</a> hoặc <a href="http://www.javascriptenlightenment.com/">JavaScript Enlightenment</a>.</p>
<p>Từ kinh nghiệm thực tiễn, tôi tin rằng những đặc tính của ngôn ngữ JavaScript sau đây cần được nắm rõ bất kể trình độ bạn đang ở đâu, đó là chuỗi prototype (prototype chain), sự bao đóng (closure), và từ khoá <code>this</code>. Ngoài ra những đặc tính độc đáo khác của JS mà lập trình viên cũng cần phải biết như chuyển đổi kiểu động, xây dựng đối tượng trực tiếp từ giá trị (literal), sự dịch chuyển lên trên vị trí khai báo của biến và hàm (variable and function hoisting)…</p>
<p>Khi đã thành thạo với JavaScript thuần, và muốn tiếp cận cách viết có cấu trúc để dễ mở rộng và bảo trì, bạn sẽ nghiên cứu các đặc ngữ của JS (idiom), mẫu thiết kế (design pattern), cách viết module, và các framework MV* phổ biến hiện nay.</p>
<p>Năm 2015 là năm mà phiên bản tiếp theo của JavaScript, ECMAScript 6 (hay còn gọi là ECMASCript 2015) được thống nhất và thông qua về đặc tả để tiến hành hiện thực dần trong các phiên bản kế tiếp của các trình duyệt. Đi kèm đó là <a href="https://www.youtube.com/watch?v=PlmsweSNhTw">xu hướng</a> sử dụng công cụ biên dịch từ ES6 sang ES5. Để không đứng ngoài xu hướng, bạn cần trang bị kiến thức về ECMAScript 6 ngay từ bây giờ và nên thử nghiệm quy trình viết bằng ES6 và biên dịch thành ES5 để chạy trên các trình duyệt hiện tại.</p>
<p>Nói về NodeJS, theo tôi nó không thuộc hệ thống kiến thức tối thiểu cho người lập trình Front End (trừ khi bạn viết cả back end bằng JavaScript). Tuy nhiên, bạn sẽ dần làm quen với nó như một hệ quả tất yếu khi bạn sử dụng những công cụ trong quy trình Front End (xem bên dưới) mà hầu hết đều được viết trên nền NodeJS.</p>
<p>Các link tham khảo:</p>
<ul>
<li><a href="http://eloquentjavascript.net/">Eloquent JavaScript</a>: tài liệu dành cho người mới học JavaScript rất hay, và miễn phí.</li>
<li><a href="http://www.javascriptenlightenment.com/">JavaScript Enlightenment</a>: Một quyển sách khác dành cho người học JS từ đầu.</li>
<li><a href="https://github.com/rwaldron/idiomatic.js/">Idiomatic JavaScript</a>: Đôi khi bạn đọc những đoạn code JS người khác viết mà không hiểu. Những đoạn “mật mã” đó sẽ được giải mã tại đây. ;)</li>
<li><a href="http://todomvc.com/">TodoMVC</a>: Website không thể bỏ qua cho những bạn cần tham khảo và so sánh kiến trúc của những framework MV* khác nhau.</li>
<li><a href="http://addyosmani.com/writing-modular-js/">Writing Modular JS</a>: Thông tin hữu ích về về các mẫu thiết kế module.</li>
<li><a href="https://leanpub.com/understandinges6">Understanding ES6</a>: Học ECMAScript 6 với Nicholas C. Zakas</li>
</ul>
<h2>Quy Trình Front End Hiện Đại</h2>
<p>Như tôi đã đề cập, kết quả làm việc nhóm có tốt hay không một phần phụ thuộc vào việc các thành viên có tuân thủ quy ước viết code (coding style convention) và quy trình làm việc (workflow) của nhóm hay không. Tuy nhiên, để nhớ hết tất cả các quy tắc đó không phải là việc đơn giản. Trong đội lập trình của Nâu, chúng tôi sử dụng các công cụ kiểm lỗi được tích hợp trong quy trình từ lúc soạn thảo cho đến biên dịch, giúp duy trì quy ước và hình thành thói quen cho các thành viên.</p>
<p>Không cần phải bàn cãi, trình duyệt là công cụ không thể thiếu của người làm Front End. Có hai kỹ năng mà tôi muốn nhấn mạnh ở đây đó là khả năng sử dụng công cụ cho người lập trình (developer tools / dev-tools) có sẵn trong trình duyệt và khả năng sử dụng phần mềm tự động nạp lại trang web (live/auto reload). Tất cả các trình duyệt hiện đại đều có dev-tools đi kèm, tuy nhiên theo tôi, dev-tools trên trình duyệt Chrome là tốt nhất hiện nay. Về phần mềm tự nạp trang, bạn có thể thử tìm hiểu <a href="http://www.browsersync.io/">Browsersync</a>.</p>
<p>Bên cạnh trình duyệt, trình soạn thảo code đóng vai trò quan trọng không kém. Bất kể bạn chọn phần mềm gì, hãy bảo đảm rằng nó có khả năng tự hoàn tất code cũng như là khả năng kiểm lỗi tức thì cho ngôn ngữ lập trình bạn viết. Với đặc tính phân tán và ít ràng buộc như HTML/CSS/JS, trình soạn thảo cho những ngôn ngữ này cũng rất cần khả năng sửa văn bản trên <a href="http://blog.generalassemb.ly/blog/wp-content/uploads/2013/11/multiplecursors.gif">nhiều con trỏ</a> và <a href="http://blog.generalassemb.ly/blog/wp-content/uploads/2013/11/gotoanything.gif">mở file nhanh bằng tìm kiếm</a>. Nếu bạn hỏi, tôi sẽ đề nghị bạn dùng thử <a href="http://www.sublimetext.com/">Sublime Text</a> hoặc <a href="https://atom.io/">Atom</a>. Ngoài ra, đừng bỏ qua <a href="http://emmet.io/">Emmet</a>, một công cụ bổ sung cho các trình soạn thảo “giúp cải thiện hiệu suất làm việc với HTML và CSS một cách đáng kể”.</p>
<p>Quy trình Front End hiện đại sẽ rất thiếu sót nếu không nhắc đến những công cụ tự động hoá chạy bằng dòng lệnh (command line) như <a href="http://gruntjs.com/">Grunt</a>, <a href="http://gulpjs.com/">Gulp</a> hoặc những công cụ tương tự có giao diện (GUI) như <a href="http://incident57.com/codekit/">Codekit</a>, <a href="http://livereload.com/">LiveReload</a>. Việc xử lý từng bước và tối ưu hoá sản phẩm Front End đã trở nên <a href="https://developers.google.com/speed/docs/insights/rules">rất phức tạp</a> để có thể làm bằng tay. Khả năng vận dụng các công cụ tự động hoá đã trở thành yêu cầu cơ bản của lập trình viên Front End.</p>
<p>Các kỹ năng và kiến thức hiển nhiên khác mà bạn cần phải có: sử dụng phần mềm quản lý phiên bản, quy trình phát triển phần mềm, mô hình phát triển phần mềm agile, công cụ hỗ trợ giao tiếp (email, nhắn tin, gọi video…), và hiểu biết tối thiểu về hệ điều hành mà bạn dùng để làm việc.</p>
<ul>
<li><a href="https://github.com/naustudio/dotfiles">Nau Front End Dotfiles</a>: Một số cài đặt và công cụ cho quy trình của Nâu.</li>
<li><a href="https://youtu.be/38D6SW26mn0">Tự động hoá với Grunt (video)</a>: Tôi sẽ hướng dẫn các bạn sử dụng một trong những công cụ tự động hoá Front End phổ biến nhất .</li>
<li><a href="https://youtu.be/sBNkiuDkILA">Khởi tạo dự án Front End với các công cụ kiểm tra lỗi tự động (video)</a>: Đây là một phần của quy trình khởi tạo dự án mới mà chúng tôi đang áp dụng.</li>
<li><a href="http://blog.chartbeat.com/2014/01/30/modern-front-end-workflow-start-finish/">Modern Front End Workflow from Start to Finish </a>: Quy trình phát triển Front End hiện đại từ đầu đến cuối.</li>
<li><a href="https://youtu.be/f7AU2Ozu8eo">JavaScript Development Workflow of 2013 (video)</a> bởi Paul Irish. Mặc dù đã được trình bày cách đây 2 năm, nhưng những công cụ được đề cập vẫn được áp dụng trong thời điểm hiện tại.</li>
</ul>
<h2>Sự Cải Tiến Tăng Dần (Progressive Enhancement)</h2>
<p><img src="https://4.bp.blogspot.com/-eR_7opxpffU/VdGP9krUTaI/AAAAAAAARis/oIe-p6ZAjAo/s640/page-120.jpg" alt="Minh hoạ Progressive Enhancement" title="Minh hoạ progressive enhancement">
Hiểu biết về <a href="http://en.wikipedia.org/wiki/Progressive_enhancement">Cải Tiến Tăng Dần</a> đã trở thành một yêu cầu bắt buộc đối với các lập trình viên Front End hiện đại. Đã qua rồi cái thời mà lập trình viên phải cố gắng hiện thực trang web cho giống y đúc trên mọi trình duyệt hoặc loại bỏ hoàn toàn những trình duyệt mà đặc tả không yêu cầu hỗ trợ. Phương pháp được khuyến khích như một chuẩn mực hiện nay là Cải Tiến Tăng Dần (Progressive Enhancement), trong đó lập trình viên Front End sẽ hiện thực website với trải nghiệm tốt nhất có thể tuỳ theo khả năng của từng loại trình duyệt khác nhau. Điều này yêu cầu bạn phải có hiểu biết về các phiên bản khác nhau của JS / CSS / HTML mà các trình duyệt hỗ trợ; biết sử dụng <a href="http://caniuse.com/">caniuse.com</a>, <a href="http://modernizr.com/">Modernizr</a>, <a href="https://html5boilerplate.com/">html5boilerplate</a>; cũng như biết khi nào cần áp dụng polyfill hoặc bỏ qua một hiệu ứng (nhưng nội dung vẫn đầy đủ) trên một trình duyệt nào đó.</p>
<p>Tham khảo thêm:</p>
<ul>
<li><a href="https://youtu.be/hdTxeR90_1E">Progressive Enhancement 2.0</a> trình bày bởi Nicholas Zakas</li>
<li><a href="http://www.smashingmagazine.com/2009/04/22/progressive-enhancement-what-it-is-and-how-to-use-it/">Progressive Enhancement: What Is It and How to Use It</a></li>
</ul>
<h2>Kỹ Năng Về Giao Diện</h2>
<p>Bạn cần có chút hiểu biết về hiệu ứng kiểu chữ (typography), các khái niệm giao diện (UI) và chuyển động (animation) và biết những thuật ngữ chuyên sâu để có thể trao đổi một cách dễ dàng với các bạn thiết kế. Ví dụ: nút hamburger, hero banner, the fold, hiệu ứng parallax…</p>
<p>Bên cạnh đó, bạn cũng cần có kỹ năng sử dụng Photoshop ở mức cơ bản để có thể trích xuất được những hình ảnh cần thiết cho việc hiện thực cũng như tham khảo các giá trị cho CSS (độ trong suốt, chuyển tiếp màu, màu sắc…). Những thao tác bằng tay này có thể sẽ được thay thế hoàn toàn bằng những công cụ hiện đại (Photoshop CC 2014, Sketch…) tuy nhiên kỹ năng về phần mềm đồ hoạ vẫn hữu ích cho bạn khi thỉnh thoảng bạn sẽ cần tự mình chỉnh sửa lên file mà không cần sự hỗ trợ của người thiết kế.</p>
<p>Bước vào năm 2015, một kỹ năng nữa mà bạn cũng cần biết, đó là sử dụng công cụ xử lý ảnh vector (Illustrator, Inkscape…) để hiệu chỉnh và trích xuất các icon và thành phần giao diện bằng vector cho thiết kế phẳng (flat design) đang là xu hướng của cả thế giới.</p>
<ul>
<li><a href="https://youtu.be/Rl5ukKqkhkc">Video hướng dẫn về CSS Text và Typography</a>.</li>
</ul>
<h2>Kỹ Năng về Tiếng Anh</h2>
<p>Mức tiếng Anh tối thiểu, theo tôi, không cần phải là trình độ A, B, C hay bao nhiêu điểm TOEIC, mà là thái độ tích cực và quyết tâm cải thiện kỹ năng giao tiếp bằng tiếng Anh của bạn.</p>
<p>Không sớm thì muộn, bạn sẽ nhận ra rằng tiếng Anh là yếu tố tối cần thiết đối với môi trường làm việc hiện đại và chuyên sâu về kỹ thuật. Công nghệ phần mềm nói chung và Web Front End nói riêng đang phát triển với tốc độ vũ bão mà nếu không có ngoại ngữ, bạn sẽ không thể nào bắt kịp. Bạn phải đọc tài liệu về các xu hướng mới, nghe các bài thuyết trình về kỹ thuật và nói chuyện với khách hàng trực tiếp hoặc qua chat/email rất thường xuyên để làm việc… Cũng có nhiều lập trình viên cho rằng chỉ cần đọc và viết tốt tiếng Anh là đủ. Tuy nhiên, bạn sẽ bỏ lỡ rất nhiều cơ hội tốt khi khả năng nghe hiểu và giao tiếp bằng tiếng Anh còn hạn chế. Vì vậy nếu tiếng Anh của bạn chưa đủ để giao tiếp, thì ngay từ bây giờ hãy không ngừng trau dồi và cải thiện.</p>
<p>Lý Quang Diệu khi đến thăm Việt Nam đã chia sẻ về <a href="http://vietnamnet.vn/vn/giao-duc/227059/ly-quang-dieu-noi-ve-giao-duc-viet-nam.html">tầm quan trọng của tiếng Anh</a>:</p>
<blockquote>
<p>Trả lời cho câu hỏi “Làm thế nào để không tụt hậu?” <strong>chỉ có một cách là phải giỏi tiếng Anh</strong>. Đây là điều ông Lý Quang Diệu nhấn mạnh. […]</p>
<p>Ông Lý Quang Diệu gợi ý: “Đại học Việt Nam nên có sách giáo khoa tiếng Anh ở các ngành quan trọng như kỹ thuật, công nghệ… bởi nếu chỉ dùng sách Việt Nam thì chắc chắn sẽ tụt hậu”. […] Ông cảnh báo, nếu tất cả sinh viên Việt Nam sau này “không thể nghe và nói tiếng Anh trôi chảy, chỉ có thể đọc thôi cũng đã là tụt hậu”.</p>
</blockquote>
<h2>Kết Luận</h2>
<p>Đến đây, nếu bạn là một lính mới về Front End hoặc là một người mới chuyển từ Back End sang, bạn sẽ cảm thấy có quá nhiều thứ để học để đạt được mức tối thiểu của Front End. Đúng là như vậy. Nhưng những người làm Front End như tôi và bạn vẫn chọn con đường không mấy dễ dàng này bởi đơn giản chúng ta yêu thích việc tạo ra những giao diện đẹp, hữu dụng và cảm thấy tự hào khi thành quả đó được đưa lên web cho cả thế giới xem và trải nghiệm.</p>
<p>Theo tôi, không phải lập trình viên nào cũng phù hợp với con đường Front End. Có những phẩm chất tạo nên sự khác biệt giữa người yêu thích Front End với người yêu thích Back End, đó là sự nhạy cảm những với thiết kế trực quan, khả năng làm việc tỉ mỉ, chi tiết đến từng pixel, và phẩm chất của một người yêu thích sự hoàn hảo.</p>
<p><img src="https://2.bp.blogspot.com/-H-9aEPUi3Kg/VdGRb22AhGI/AAAAAAAARi4/dOa4ycz34qg/s640/Strips-front-end-vs-le-back-end-650-finalenglish.jpg" alt="How back end and front end dev see each other" title="How back end and front end dev see each other"></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Baseline for Modern Front End Developers</title>
    <link href="https://int3ractive.com/blog/2015/baseline-for-modern-front-end-developers/"/>
    <updated>2015-06-08T01:47:00Z</updated>
    <id>https://int3ractive.com/blog/2015/baseline-for-modern-front-end-developers/</id>
    <content type="html"><![CDATA[
      
<div dir="ltr" style="text-align: left;" trbidi="on">
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://2.bp.blogspot.com/-mF8YcFrCO8Q/VXPniJnFrZI/AAAAAAAABDY/T7PQ5bKPoYs/s1600/front-end-baseline.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="300" src="https://2.bp.blogspot.com/-mF8YcFrCO8Q/VXPniJnFrZI/AAAAAAAABDY/T7PQ5bKPoYs/s640/front-end-baseline.png" width="610" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: right;">word cloud by wordle.net</td></tr>
</tbody></table>
From my own experiences working in small and large development teams, I learned that setting a baseline of skills and workflow know-how among the people in a technical team is as much important as the coding conventions.<span id="goog_1142196189"></span><br />

<br />
Without a doubt, raising team members' skills (esp. juniors) to a standard will not only enhance collaboration (as they should know what others are doing) but also improve their productivity.<br />
<br />
When forming up my front-end team at Nau Studio, I thought a lot about what are the most essential skills and technical knowledge which will become my team's baseline and focus of basic training.<br />
<br />
Inspired by this popular article by Rebecca Murphey, <a href="http://rmurphey.com/blog/2012/04/12/a-baseline-for-front-end-developers/" target="_blank">A Baseline for Front-End Developers</a>, I'm presenting Baseline for Modern Front End Developers (Not-Just-JavaScript edition) which is tailored to target juniors and more updated with latest trends:<br />
<br />
<a name='more'></a><br />
To begin, let's talk about the three pillars of Web Front End:<br />
<h2 style="text-align: left;">
HTML</h2>
Many developers take HTML for granted. But the more they work with it, the more they'll realize that authoring HTML that is clear and lean requires great skills and I dare to say that it is kind of an art.<br />
<br />
To become a successful developer with HTML, you must know how to combine elements semantically yet effectively. This involves good understanding of all common HTML elements in terms of not just default layout rules and styling but also their semantic and contextual usage. Part of this is gained by experience, but the principles can be taught and guided.<br />
<br />
Helper resources:<br />
<ul style="text-align: left;">
<li><a href="http://html5doctor.com/" target="_blank">HTML5 Doctor</a>: Reliable reference to HTML5 elements' usage, especially in a semantic way.</li>
<li><a href="https://docs.webplatform.org/wiki/html/tutorials" target="_blank">HTML basic tutorial</a>: Basic HTML tutorials</li>
</ul>
<h2 style="text-align: left;">
CSS</h2>
Many CSS beginners, especially IT students in Viet Nam, have very brief lessons about CSS at web dev classes and related textbooks are outdated. Most will practice trial-and-error tinkering and master CSS very inefficiently. (Or at least it was my case at the beginning)<br />
<br />
This is not the case in my team. Fundamental concepts of CSS like cascading, specificity rules, selectors, inheritance, box model and stacking context must be well understood.<br />
<br />
After the basics, you must then have some ideas of <a href="https://github.com/stubbornella/oocss/wiki" target="_blank">OOCSS</a> or start practicing some points from&nbsp;<a href="http://cssguidelin.es/" target="_blank">CSS guidelines</a>.<br />
<br />
Besides, front-end developers who do CSS well always have a few common tricks up their sleeves. For instance, they must know all the tricks to vertically align contents while Flex box is not yet mainstream. They must also know when to use <a href="https://css-tricks.com/pseudo-element-roundup/" target="_blank">pseudo-elements</a>, <a href="https://css-tricks.com/examples/ShapesOfCSS/" target="_blank">CSS shape tricks</a>, icon fonts, or sprite sheet, etc. to achieve the UI designs with best performance and compatibility results.<br />
<br />
And last but not least, a modern front-end developer should be able to use a CSS preprocessor (our favorite is <a href="http://sass-lang.com/" target="_blank">SASS</a> - SCSS flavor) to enhance maintainability and productivity of your work.<br />
<br />
You might ask about CSS3 and cutting-edge features? It will be a piece of cake once you've mastered the basics.<br />
<br />
<ul style="text-align: left;">
<li><a href="https://docs.webplatform.org/wiki/css/tutorials" target="_blank">CSS Tutorials</a>&nbsp;from webplatform.org</li>
<li><a href="https://github.com/stubbornella/oocss/wiki" target="_blank">OOCSS</a>: Object-Oriented CSS methodology by Nicole Sullivan</li>
<li><a href="http://cssguidelin.es/" target="_blank">CSS Guidelines</a>&nbsp;by CSS Wizardry - Harry Robert</li>
<li><a href="http://css-tricks.com/" target="_blank">CSS Tricks</a>: Who does CSS and hasn't visited this site before? :)</li>
</ul>
<h2 style="text-align: left;">
JavaScript</h2>
jQuery may be <a href="http://youmightnotneedjquery.com/" target="_blank">not an entrance requirement</a> to Web Front End anymore but I think it is still a very helpful lead-in for beginners to the fragmented world of web browser scripting.<br />
<br />
Like Rebecca has made it clear, learning vanilla (pure) JavaScript is essential and if you haven’t read JavaScript: The Good Parts, it’s totally fine as long as you’ll learn from Eloquent Javascript or JavaScript Enlightenment and the like.<br />
<br />
At any level, I believe, there are three key features of JavaScript that are crucial to your comprehension of the language; they are prototype chain, closures, and 'this' keyword. Other “interesting” features of the language such as dynamic typing, literals, variable and function hoisting... should be understood as well.<br />
<br />
When you get more advanced in JS, and wanting to get a more structured and maintainable approach of doing it, you’ll learn JS idioms, patterns, modules and may be an MV* framework all along.<br />
<br />
2015 is the year the next generation of JavaScript, ECMAScript 6 (AKA ES 2015), is finalized in specs and there is a huge <a href="https://www.youtube.com/watch?v=PlmsweSNhTw" target="_blank">rise of adoptions and use of es6-to-5 compilers</a>. As one of the main users of the language, you don’t want to stand out of this trend. Get ready by learning ES6 new features and adopt the compile-to-es5 workflow as soon as you have the chance.<br />
<br />
In my opinion, NodeJS is not in the baseline of Front End developers. Eventually, however, you will get to know it by using one of its many tools in the workflow or having to do some server-side coding using JS.<br />
<br />
<ul style="text-align: left;">
<li><a href="http://eloquentjavascript.net/" target="_blank">Eloquent JavaScript</a>: Very good book for JS newbie, and it’s free.</li>
<li><a href="http://www.javascriptenlightenment.com/" target="_blank">JavaScript Enlightenment</a>: Another good book for newbie.</li>
<li><a href="https://github.com/rwaldron/idiomatic.js/" target="_blank">Idiomatic JavaScript</a>: Sometimes you read others' JS code and can’t get it. Those “cypher” may be decoded here. ;)</li>
<li><a href="http://todomvc.com/" target="_blank">TodoMVC</a>: A go-to site for MVC frameworks evaluation and comparison</li>
<li><a href="http://addyosmani.com/writing-modular-js/" target="_blank">Writing Modular JS</a>: More details on modern JS modules</li>
<li><a href="https://leanpub.com/understandinges6" target="_blank">Understanding ES6</a>: Learn ECMAScript 6 with Nicholas C. Zakas</li>
</ul>
<h2 style="text-align: left;">
The Modern Workflow</h2>
As I mentioned before, good team work is also affected by how well team members comply to conventions and coding style guides. In this modern age, however, it is not necessary for new joiners to learn by heart all those rules as long as they use linters (<a href="http://jshint.com/" target="_blank">JSHint</a>, <a href="http://csslint.net/" target="_blank">CSSLint</a>, <a href="https://github.com/brigade/scss-lint" target="_blank">SCSS-lint</a>) and code styles checkers (<a href="http://jscs.info/" target="_blank">JSCS</a>), to impose and shape their coding styles.<br />
<br />
In my team, we have a <a href="https://github.com/naustudio/dotfiles" target="_blank">dotfiles repository</a> which covers editor’s defaults and plugins, code linter config, most frequently used code snippets and some command line aliases and functions.<br />
<br />
Since you develop for the Web, the browsers are undoubtedly your best sidekicks. Two know-hows I would strongly recommend are using the in-browser developer tools and so-called live reload software. All modern browsers have decent built-in devtools, but the most sophisticated and useful one, to me, is Chrome's. For live reload software, I recommend looking at <a href="http://www.browsersync.io/" target="_blank">Browsersync</a>.<br />
<br />
Next to browsers, the code editor plays as much an important role. Whatever you choose, make sure it has decent code completion with live feedback linting. The other highly recommended features of modern front end editors are multiple cursors and fuzzy file search. If you ask me, I suggest checking <a href="http://www.sublimetext.com/" target="_blank">Sublime Text</a> or <a href="https://atom.io/" target="_blank">Atom</a>. Besides, don’t miss out <a href="http://emmet.io/" target="_blank">Emmet</a>, the plugin that will “greatly improves HTML &amp; CSS workflow”.<br />
<br />
The Front End workflow can't be completed without mentioning automation tools like the command-line-based <a href="http://gruntjs.com/" target="_blank">Grunt</a> or <a href="http://gulpjs.com/" target="_blank">Gulp</a> or the GUI-based counter parts namely&nbsp;<a href="http://incident57.com/codekit/" target="_blank">CodeKit</a> or <a href="http://livereload.com/" target="_blank">LiveReload</a>. Modern web front-end process targeting performance is becoming so complicated that it is very <a href="https://developers.google.com/speed/docs/insights/rules" target="_blank">tedious to handle manually</a>. Being able to use a process automation tool is becoming the baseline standard.<br />
<br />
Other skills and knowledge that are too obvious to talk into details: version control system, software development process, agile methodologies, communication tooling and the OS platform you choose to work on.<br />
<br />
<ul style="text-align: left;">
<li><a href="https://github.com/naustudio/dotfiles" target="_blank">Nau's Front End Dotfiles</a>: A set of tools and config for our team’s workflow.</li>
<li><a href="https://youtu.be/38D6SW26mn0" target="_blank">Automation with Grunt tutorial</a>&nbsp;(screencast in Vietnamese): I’ll guide you through using one of the most popular automation tools for Front End dev.</li>
<li><a href="https://youtu.be/sBNkiuDkILA" target="_blank">Front End Project Settings &amp; Linters</a> (screencast in Vietnamese): Part of our scaffolding workflow, semi-manual for now, but will be automated with Yeoman later.</li>
<li><a href="http://blog.chartbeat.com/2014/01/30/modern-front-end-workflow-start-finish/" target="_blank">Modern Front End workflow from start to finish</a>: An insightful read or current Front End workflow.</li>
<li><a href="https://youtu.be/f7AU2Ozu8eo" target="_blank">JavaScript Development Workflow of 2013</a> by Paul Irish. Although it's 2 year old, there are a lot of demos of tools that are still applicable by now.</li>
</ul>
<h2 style="text-align: left;">
Progressive Enhancement</h2>
Knowing <a href="http://en.wikipedia.org/wiki/Progressive_enhancement" target="_blank">Progressive Enhancement</a> is now a must for modern Front End developers. It is not about the knowledge to implement websites exactly the same across browsers anymore, but ability to leverage the capability of each browser to provide the best experience on it. This requires developers to know how to use <a href="http://caniuse.com/">caniuse.com</a>, <a href="http://modernizr.com/" target="_blank">Modernizr</a>, <a href="https://html5boilerplate.com/" target="_blank">html5boilerplate</a> as well as knowing when a polyfill / fallback is required.<br />
<br />
<ul style="text-align: left;">
<li><a href="https://youtu.be/hdTxeR90_1E" target="_blank">Progressive Enhancement 2.0</a> by Nicholas Zakas, this is one of my eye-openers to PE</li>
<li><a href="http://www.smashingmagazine.com/2009/04/22/progressive-enhancement-what-it-is-and-how-to-use-it/" target="_blank">Progressive Enhancement: What Is It and How to Use It</a>&nbsp;from Smashing Magazine</li>
</ul>
<h2 style="text-align: left;">
UI Skills Set</h2>
You should have some understanding of typography, UI and animation concepts and can speak UI jargon fluently with your UX/UI designer fellows. (i.e: hamburger button, hero banner, the fold…)<br />
<br />
Besides, you should be able to open a Photoshop file to get the necessary assets for your UI development as well as extract parameters (opacity, gradient, colors…) that are applicable for CSS authoring. These manual tasks may finally be replaced by auto CSS extraction with modern design tools (Photoshop CC 2014, Sketch…), but those know-hows will still benefit you as one day you are able to make some minor adjustment to the PSD without the help of designers.<br />
<br />
In 2015, a new skill you should also get a grasp of is using a vector graphic editing tool (Illustrator, Inkscape…) to manipulate and extract vector images which are essential for scalable graphics in modern flat designs.<br />
<h2 style="text-align: left;">
Conclusion</h2>
There you go! If you are a Front End rookie or a back-end-to-front-end convert, you may feel there are a lot to learn just to meet the baseline. It is indeed. Some even compare us with kind of programming <a href="http://jjperezaguinaga.com/2014/03/19/why-cant-we-find-front-end-developers/" target="_blank">masochists</a>. But we still go for it because we enjoy making beautiful and useful UI and we feel greatly rewarded when our creations are released to the whole world to see and experience.<br />
<br />
My 2 cents, not every programmer is suitable with the web front end path. What makes a good front end dev different from back end or full stack one, I believe, is that we are more visual sensitive, we can work with pixels painstakingly and possess some characteristics of perfectionists.<br />
<h3 style="text-align: left;">
P.S:</h3>
During the time I was writing this blog, Murphey published a new blog post about <a href="http://rmurphey.com/blog/2015/03/23/a-baseline-for-front-end-developers-2015/" target="_blank">baseline for 2015 front end developers</a>. I told myself not to read it until I finish this article to see how our ideas may collide or differ from one another.<br />
<br />
I read Murphey’s post and I’m still glad I wrote this down. My target audience of this article are mostly mid-weight and below, and it aims to give you a good head start into Front End development and to collaborate better within a team. By all means, you will learn more advanced techniques through your progress with this career, but you can get away without first knowing how to write a NodeJS package or writing unit tests with Karma.<br />
<br />
Anyway, I hope both articles can give very good insights of this career path that is quite picky of its followers, and that is very new and demanding in Viet Nam too.</div>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Fixing Web Font Padding Issues on Linux/Mac/Android Browsers</title>
    <link href="https://int3ractive.com/blog/2013/fixing-web-fonts-padding-issues-on-linux-mac/"/>
    <updated>2013-07-27T19:07:00Z</updated>
    <id>https://int3ractive.com/blog/2013/fixing-web-fonts-padding-issues-on-linux-mac/</id>
    <content type="html"><![CDATA[
      
<p><a href="https://3.bp.blogspot.com/-9QmpMDEqu2o/UfP8b0piszI/AAAAAAAAIzc/dGu2we7VVO4/s1600/web-font-padding.png" imageanchor="1" style="clear: right; display: block; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="106" src="https://3.bp.blogspot.com/-9QmpMDEqu2o/UfP8b0piszI/AAAAAAAAIzc/dGu2we7VVO4/s200/web-font-padding.png" width="200" /></a>Recently I came across an annoying issue with web font (@font-face) in which the text does not appear vertically center within buttons or inputs (see image). Google around, I found that not all web fonts are affected, this defect seem to occur only on Mac/Linux and may vary in different browsers and is commonly referred to as "web font padding issue".</p>


<p>It's interesting enough that although the issue is quite common and has been <a href="http://css-tricks.com/forums/topic/padding-problem-with-web-fonts-on-linuxmac/" rel="" target="_blank">reported</a>&nbsp;<a href="http://stackoverflow.com/questions/9994437/padding-problems-in-linux-mac-browsers-comparing-to-windows-with-font-face" rel="" target="_blank">several</a>&nbsp;<a href="http://www.quora.com/Web-Fonts/Do-you-have-any-hints-how-to-fix-padding-issues-for-embedded-web-fonts" rel="" target="_blank">times</a> but there seem to be no absolute solutions. Most suggested the workaround to set uneven padding to compensate for the shift. I have struggled so much with workarounds for this especially the padding didn't help to correct the alignment across browsers and devices (I preview my app in Chrome/OSX but it runs on iOS Safari and Android browser) so I decided to look into the issue again and thought about typography metrics problems.</p>

<p>Honestly, I know very little about typography and font metrics. I used <a href="http://fontforge.org/" target="_blank">FontForge</a> (which happens to be easily installed on Ubuntu) to tinker with the troubling font file. After a few hours, I have discovered the problem when I tried to replicate the settings of another good font on the defective one. It was one of my Eureka moments!</p>

<a name='more'></a>
<p>So, here's how I fixed it:</p>

<p>
1. &nbsp;Open the troubled font file (TTF or WOFF) with FontForge<br />
2. &nbsp;Open menu Element &gt; Font Info...<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-6Ob1i7qy6ac/UfP2ivO94II/AAAAAAAAIzM/IZujal2Zprc/s1600/Screenshot+from+2013-07-21+22:38:07.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="195" src="https://2.bp.blogspot.com/-6Ob1i7qy6ac/UfP2ivO94II/AAAAAAAAIzM/IZujal2Zprc/s640/Screenshot+from+2013-07-21+22:38:07.png" width="640" /></a></div>
<br />
3. Select setting item OS/2 &gt; tab Metrics<br />
If your font is defective, the <a href="http://fontforge.org/fontinfo.html#TTF-Metrics" target="_blank">HHead (Ascent Offset, Descent Offset, Line Gap)</a>&nbsp;input boxes will be set with some values other than 0 (as in screenshot below).<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-pfrMLfQYvFs/UfQNJokCG9I/AAAAAAAAIzs/A_Og1AEkrWY/s1600/Screenshot+from+2013-07-21+22:34:05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="355" src="https://4.bp.blogspot.com/-pfrMLfQYvFs/UfQNJokCG9I/AAAAAAAAIzs/A_Og1AEkrWY/s400/Screenshot+from+2013-07-21+22:34:05.png" width="400" /></a></div>
4. Set all&nbsp;<b>HHead* values to 0</b>. &gt; OK<br />
5. Then you can generate (File &gt; Generate Fonts) the font to various web font files (TTF - TrueType, WOFF - Web Open Font, SVG). Note that just ignore any warnings during the font validation before it is generated.
</p>

<p>I have&nbsp;tried my fix on&nbsp;the defective fonts in the issue reports mentioned above and it did work!</p>

<p>For a live demo, <a href="http://dabblet.com/gist/6093760" target="_blank">visit this Dabblet</a>. (You may only see the differences if you are on Mac/Linux).<br />
Here's a screenshot of the demo:</p>

<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-jPtdvpRjth0/UfPy5DVpC3I/AAAAAAAAIy8/kbcrrTXTjFQ/s1600/web-font-padding-fix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="301" src="https://2.bp.blogspot.com/-jPtdvpRjth0/UfPy5DVpC3I/AAAAAAAAIy8/kbcrrTXTjFQ/s320/web-font-padding-fix.png" width="320" /></a></div>
<br />

<p>So, this padding issue is actually a font metrics issue. I don't fully understand why and how it happens and&nbsp;I may need some more learning to explain it thoroughly. But ultimately the fix works.</p>

<p>If you can't install FontForge, you may try with other font editors available on your platform (of course I don't know the equivalent menu location so you have to find it yourself). I hope this guide will help everybody fix the web font problem once and for all!</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project: In2Ideas HTML5 Website </title>
    <link href="https://int3ractive.com/blog/2012/portfolio-in2ideas-html5-website/"/>
    <updated>2012-11-09T11:00:00Z</updated>
    <id>https://int3ractive.com/blog/2012/portfolio-in2ideas-html5-website/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-I_w9ZnFQ2Ro/UWDtku4HgTI/AAAAAAAAIVM/6P3A9JjcuG8/s1600/in2ideas_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="267" src="https://3.bp.blogspot.com/-I_w9ZnFQ2Ro/UWDtku4HgTI/AAAAAAAAIVM/6P3A9JjcuG8/s400/in2ideas_01.png" width="400" /></a></div>
<br />
This is the complete rework of the front page of my (now ex) agency to show case our experiences and expertise. The concept was that the whole site is a mind map which is often associated with brainstorming &amp; ideas generating.<br />
<br />

The key feature of the site is the mind-map-like navigation in which you can drag to move in any direction. It works on both desktop and tablet's browsers. Looping animations are made of SVG graphics which were authoring in Flash and then converted to Google Swiffy. The dynamic dash lines were programatically drawn on HTML5 Canvas. To support older browser (IE8+), Flash will be in place of the SVG &amp; Canvas graphics.<br />
<br />
My roles: technical researcher, key front-end developer.<br />
Technical highlights: HTML5, CSS3,&nbsp;<a href="http://requirejs.org/" target="_blank">RequiredJS</a>, jQuery,&nbsp;<span style="white-space: pre-wrap;"><a href="http://www.google.com/doubleclick/studio/swiffy/" target="_blank">Google Swiffy</a>, <a href="http://flashcanvas.net/" target="_blank">FlashCanvas</a></span><br />
<br />
Live URL: <a href="http://in2ideas.com/">http://in2ideas.com</a><br />
<br />
More screen shots:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-fDBM_jqREro/UWDz_B38ZzI/AAAAAAAAIVU/OyXfSyymxss/s1600/in2ideas_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="119" src="https://1.bp.blogspot.com/-fDBM_jqREro/UWDz_B38ZzI/AAAAAAAAIVU/OyXfSyymxss/s200/in2ideas_02.png" width="200" /></a><a href="https://4.bp.blogspot.com/-RnNg6Ml5Wdc/UWD0E6gO6AI/AAAAAAAAIVc/rI7QrOkWP58/s1600/in2ideas_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="118" src="https://4.bp.blogspot.com/-RnNg6Ml5Wdc/UWD0E6gO6AI/AAAAAAAAIVc/rI7QrOkWP58/s200/in2ideas_03.png" width="200" /></a><a href="https://2.bp.blogspot.com/-IjSA7ehWgvA/UWD0OCyluEI/AAAAAAAAIVk/Fi3ctd8-FWQ/s1600/in2ideas_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="131" src="https://2.bp.blogspot.com/-IjSA7ehWgvA/UWD0OCyluEI/AAAAAAAAIVk/Fi3ctd8-FWQ/s200/in2ideas_04.png" width="200" /></a></div>
Interaction demo:<br />
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/C0W2zHLXvzo/0.jpg" height="266" width="320"><param name="movie" value="http://www.youtube.com/v/C0W2zHLXvzo?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266"  src="http://www.youtube.com/v/C0W2zHLXvzo?version=3&f=user_uploads&c=google-webdrive-0&app=youtube_gdata" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />

    ]]></content>
  </entry>
	
  
  <entry>
    <title>HTML5 Wordle Tag Cloud</title>
    <link href="https://int3ractive.com/blog/2012/html5-wordle-tag-cloud/"/>
    <updated>2012-08-28T05:27:00Z</updated>
    <id>https://int3ractive.com/blog/2012/html5-wordle-tag-cloud/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="http://labs.int3ractive.com/javascript/effects/wordle-tag-cloud" target="_blank"><img alt="Wordle JS" border="0" height="320" src="https://4.bp.blogspot.com/-1mx7fdnE-AU/UDwyOfgRS7I/AAAAAAAAE-A/62e_6ffT5Yg/s320/preview.jpg" title="" width="320" /></a></div>
<br />
This is a direct port of my <a href="http://blog.int3ractive.com/2011/02/as3-wordle-tag-cloud.html" target="_blank">AS3 Wordle Tag Cloud</a>&nbsp;to HTML5. Please read my old blog post for some background.<br />
<br />
Some technical notes:<br />
<ul>
<li>Thanks to Canvas' RenderingContext2D.measureText(), I can calculate size of the words off browser's stage.</li>
<li>Initially, I was using Canvas as rendering stage for the tag cloud. However, it demands extra work to make the words interactive. So I decided to use normal block text with CSS3's transform/rotate. The result is texts are searchable and out-of-the-box hyperlinks.</li>
<li>The position checking process may cause browser hang momentarily if run through all of the words. I have split the process of each word into each RequestAnimationFrame to avoid the script hang.</li>
</ul>
<div>
However, there is still room to improve, for example, enhancing the intersection check and using any angle rotation...</div>
<div>
<br /></div>
There you go! Check out the <a href="http://labs.int3ractive.com/javascript/effects/wordle-tag-cloud" target="_blank">live demo</a> and <a href="https://github.com/trongthanh/labs.int3ractive.com/tree/gh-pages/javascript/effects/wordle-tag-cloud" target="_blank">source code</a>.

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Google App Engine for static websites</title>
    <link href="https://int3ractive.com/blog/2012/google-app-engine-for-static-websites/"/>
    <updated>2012-08-14T09:42:00Z</updated>
    <id>https://int3ractive.com/blog/2012/google-app-engine-for-static-websites/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-PUhTvVY9vUQ/UCoi1qAEISI/AAAAAAAAE9s/wfLaZyf5cKU/s1600/google-app-engine-logo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://1.bp.blogspot.com/-PUhTvVY9vUQ/UCoi1qAEISI/AAAAAAAAE9s/wfLaZyf5cKU/s1600/google-app-engine-logo.png" /></a></div>
Nowadays, there are many options to&nbsp;host a static website (portfolios, generated <a href="http://octopress.org/" target="_blank">weblogs</a>, front-end demos, etc.) for free. One of the best ways is to push your static files to a Github's repo and publish them through <a href="http://pages.github.com/" target="_blank">Github Page</a>.<br />
<br />
A lesser known solution is to make use of <a href="https://developers.google.com/appengine/" target="_blank">Google App Engine</a>&nbsp;(GAE). Actually,&nbsp;GAE is designed for building and publishing high-performance, highly scalable web applications written in Python, Java or the newly-introduced Go language. However, by tinkering with the set up and deployment process, I figured out that it is also great for hosting static website with no server side coding at all. Like Github Page, your static website will be served through http://[your-app].appspot.com or you can customize it with a (sub)domain.<br />
<br />

The advantages of GAE over Github Page are: higher static files quota (known in GAE as blobstore, known in Github as repository size); allowed SSL; better performance (since GAE app is hosted with reserved thread and bandwidth); possible to&nbsp;supplement&nbsp;data and dynamic server-side scripting later.<br />
<a name='more'></a><h2>
How-to:</h2>
I won't explain details about setting up environment and deployment as you can easily follow the getting-started guides at:&nbsp;<a href="https://developers.google.com/appengine/">https://developers.google.com/appengine/</a><br />
<h3>
GAE for Python</h3>
As you go through the <a href="https://developers.google.com/appengine/docs/python/gettingstartedpython27/" target="_blank">getting-started tutorial for Python</a>, it becomes clear that GAE Python app won't serve your static files without specific instructions in the app.yaml file. However,&nbsp;I have successfully tweaked the app.yaml file to serve a whole static website without any Python handlers.<br />
<br />
Let's take the helloworld app from the tutorial for reference. Here are what you need to do from there:<br />
<ul>
<li>Remove all other files except app.yaml</li>
<li>Copy all static files into a subfolder. For example: <b>helloworld/www</b></li>
<li>Edit the <b>app.yaml</b> file as following:<br />
<pre style="border: 1px solid #ccc;"><code>application: my-app
version: 1
runtime: python27
api_version: 1
threadsafe: yes

handlers:
# making index.html as default page for root
- url: /
  static_files: www/index.html
  upload: www/index.html

# begin any static files request from www folder
- url: /
  static_dir: www</code></pre>
</li>
<li>However this won't make any of index.html files in the subfolder as default pages. To have default page for subfolders, you have to prepend a static_files handler for each one:<br />
<pre style="border: 1px solid #ccc;"><code>[...]
handlers:
# default page for /projects subfolder, note the order in the handler list
- url: /projects/?
  static_files: www/projects/index.html
  upload: www/projects/index.html

# making index.html as default page for root
- url: /
  static_files: www/index.html
  upload: www/index.html

# begin any static files request from www folder
- url: /
  static_dir: www</code></pre>
</li>
</ul>
Then you can deploy your static website on GAE right away.<br />
<h3>
GAE for Java</h3>
For Java App Engine, it is much easier to prepare the application to deploy. All static files deployed with the application (even in the app root folder) will be served automatically. Best of all, index.html/.htm files are automatically default pages of root and subfolder URLs.<br />
<br />
What you have to do:<br />
<ul>
<li>Copy <b>WEB-INF</b> from appengine's demos/new_project_template to your website's folder</li>
<li>Edit&nbsp;<b>appengine-web.xml</b> with your application's name and version</li>
<li>Edit <b>web.xml</b> by removing the sample servlet &amp; servlet-mapping tags.</li>
<li>Deploy your application with your website's folder in place of "war" in the command <code>appcfg.sh update war</code> from <a href="https://developers.google.com/appengine/docs/java/gettingstarted/uploading" target="_blank">the instructions</a>.</li>
</ul>
<ul>
</ul>
<h3>
Where to go from here:</h3>
After successfully deployed your application on appspot.com you may want to <a href="https://developers.google.com/appengine/docs/domain" target="_blank">customize a domain for your website</a>&nbsp;and know <a href="https://developers.google.com/appengine/docs/quotas" target="_blank">your free quota limits</a>.<br />
<br />
There's one of the topics interests me but I have no time to experiment yet is <a href="https://developers.google.com/appengine/docs/ssl" target="_blank">serving you app with SSL</a>. Please check it for yourself.<br />
<br />
If you don't have a need to host website, GAE SDK is still useful as a localhost HTTP server to test front-end projects. Follow the links for how to use development server for <a href="https://developers.google.com/appengine/docs/python/tools/devserver" target="_blank">Python</a> &amp; <a href="https://developers.google.com/appengine/docs/java/tools/devserver" target="_blank">Java</a>.

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project: ISS 2012</title>
    <link href="https://int3ractive.com/blog/2012/project-iss-2012/"/>
    <updated>2012-06-27T11:00:00Z</updated>
    <id>https://int3ractive.com/blog/2012/project-iss-2012/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-kl-fhPP97WA/T_vL8R5zawI/AAAAAAAAEyc/Z_dQMVzudm8/s1600/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-16-27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://1.bp.blogspot.com/-kl-fhPP97WA/T_vL8R5zawI/AAAAAAAAEyc/Z_dQMVzudm8/s320/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-16-27.png" width="167" /></a></div>
This is a post-event highlighting microsite for Intεl Sοlμtiοn Sμmm!t 2012. The site is to capture the activities and everything related to event in the forms of videos, photos &amp; other kind of materials. Audience of this microsite are participants of the event and other users of APɅC Intεl Channεl Pοrtal which is a member-only partners relation web site.<br />
<br />

Live URL: <i>www.%69%6E%74%65%6C.com/apac/channel/ISS2012/index.html</i> <a href="javascript:;" title="Copy the obfuscated URL string and paste on to Browser's address bar">[?]</a><br />
<br />
Technical features:<br />
<ul>
<li>jQuery</li>
<li>Galleria photo gallery (<a href="http://galleria.io/" target="_blank">library</a>)</li>
<li>OSMF's Strobe Media Playback (<a href="http://www.osmf.org/strobe_mediaplayback.html" target="_blank">component</a>)</li>
</ul>
<a href="https://4.bp.blogspot.com/-_X5LOQIHSGI/T_vMocPvn1I/AAAAAAAAEyk/4pJJalIdbcs/s1600/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-16-59.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://4.bp.blogspot.com/-_X5LOQIHSGI/T_vMocPvn1I/AAAAAAAAEyk/4pJJalIdbcs/s200/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-16-59.png" width="148" /></a>
<a href="https://4.bp.blogspot.com/-fGO6Sz2VzRA/T_vMwvWYmiI/AAAAAAAAEys/Nj8HlojH5RY/s1600/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-17-20.png" imageanchor="1" style="float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://4.bp.blogspot.com/-fGO6Sz2VzRA/T_vMwvWYmiI/AAAAAAAAEys/Nj8HlojH5RY/s200/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-17-20.png" width="121" /></a>
<a href="https://4.bp.blogspot.com/-XXH_aid6o7s/T_vM2J-85CI/AAAAAAAAEy0/ex90RBml_Gg/s1600/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-17-40.png" imageanchor="1" style="float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://4.bp.blogspot.com/-XXH_aid6o7s/T_vM2J-85CI/AAAAAAAAEy0/ex90RBml_Gg/s200/Intel%C2%AE+Solutions+Summit+2012+2012-07-10+14-17-40.png" width="135" /></a>
<br />
<div style="clear: both;">
</div>
<a href="javascript:;" style="font-size: 0.8em;" title="Some key words in this article were obfuscated with unusual symbols (but still readable) so that they are not likely to show up in search results. This is to respect the non-disclosure agreement with my employer &amp; their clients">Obfuscation Reasons</a>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Fish Boids - Three.js Demo</title>
    <link href="https://int3ractive.com/blog/2012/fish-boids-threejs-demo/"/>
    <updated>2012-05-17T08:45:00Z</updated>
    <id>https://int3ractive.com/blog/2012/fish-boids-threejs-demo/</id>
    <content type="html"><![CDATA[
      
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://labs.int3ractive.com/javascript/canvas/fish-boids/" style="margin-left: 1em; margin-right: 1em;" target="_blank" title="Open the demo"><img border="0" height="276" src="https://4.bp.blogspot.com/-4IaG0pIu5CM/T7Svn5pvOGI/AAAAAAAAEj8/TxsXKJG5Lfc/s400/school-of-fish.png" width="400" /></a></div>
<br />
This is my adaptation from the <a href="https://github.com/mrdoob/three.js" target="_blank">Three.js</a> <a href="http://mrdoob.github.com/three.js/examples/canvas_geometry_birds.html" target="_blank">Birds&nbsp;Demo</a>&nbsp;which was featured in the famous HTML5 Music Interactive Film&nbsp;<a href="http://www.thewildernessdowntown.com/">The Wilderness Downtown</a>.<br />
<br />
The original birds demo was done by Mr.Doob based on the <a href="http://www.openprocessing.org/sketch/6910" target="_blank">boids simulation</a>. You can read more about behind the scene of The Wilderness Downtown and the flocks of birds simulation <a href="http://ricardocabello.com/blog/post/705" target="_blank">from his blog here</a>. (Thank Mr. Doob for your awesome <a href="https://github.com/mrdoob/three.js" target="_blank">Three.js</a> library and the nice bird demo.)<br />
<br />
The significant adaptations that I made to this school of fishes simulation are: the fish objects are PlaneGeometry with bitmap texture; some tweaks to the boids' speed and movement to make them more fish-like; and making the fish wiggle its tail instead of bird wings' flapping.<br />
<br />
This fish and the bird demos are used in my side-project for my friend's HTML5 portfolio.<br />
<br />
Now, <a href="http://labs.int3ractive.com/javascript/canvas/fish-boids/" target="_blank">go see the demo</a>. The source code can be found on <a href="https://github.com/trongthanh/labs.int3ractive.com/tree/gh-pages/javascript/canvas/fish-boids" target="_blank">Github</a>.

    ]]></content>
  </entry>
	
  
  <entry>
    <title>A Cave, 3D Stereo Images &amp; 2-State Looping Animation</title>
    <link href="https://int3ractive.com/blog/2012/cave-3d-stereo-images-2-state-looping/"/>
    <updated>2012-05-10T07:43:00Z</updated>
    <id>https://int3ractive.com/blog/2012/cave-3d-stereo-images-2-state-looping/</id>
    <content type="html"><![CDATA[
      
When I visited <a href="http://en.wikipedia.org/wiki/Thien_Duong_Cave" target="_blank">this cave</a> during the trip to the central provinces of Viet Nam. I wanted to capture it magnificence and beauty but the cave's texture was too complex to visualize its depth and space on 2D photos. I recalled this <a href="http://www.cambridgeincolour.com/tutorials/animated-3d-stereo-photography.htm" target="_blank">3D photography technique</a> and tried to take some stereo photos of the scenes (take 2 photos of the same scene from 2 slightly different position) and made them into 3D stereo animation when I get back.<br />
<br />

Traditionally, these 3D stereo images are presented by a 2-frame animated GIF. But GIF images are not efficient for live photographs and they normally take up more bytes than JPG for large pictures so I decided to use CSS and JavaScript to reproduce the animation with JPG photos.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-mskGDxFUVco/T6tuynEL1OI/AAAAAAAAEiI/f8kZWprPZ20/s1600/DSC_0192.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://4.bp.blogspot.com/-mskGDxFUVco/T6tuynEL1OI/AAAAAAAAEiI/f8kZWprPZ20/s400/DSC_0192.jpg" width="400" /></a></div>
<br />
Basically, the JPG is set as background of a div which has dimensions of half of the image. JS will shift the background-position at intervals revealing half of the background one at a time. And <a href="http://labs.int3ractive.com/javascript/effects/stereo-images/index.html" target="_blank">here's the results</a>.<br />
<br />
During the making of the effect, I also explored its possibility with CSS3 animation and steps() function. The result is the same without any coding. But for the sake of compatibility for the audience, the said demo still use JS. I put the CSS3 solution on Dabblet for later reference of similar 2-state animation. <a href="http://dabblet.com/gist/5582401" target="_blank">Check it out</a>.

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Tutorial: Realistic Waterfall with CSS3</title>
    <link href="https://int3ractive.com/blog/2012/tutorial-realistic-waterfall-with-css3/"/>
    <updated>2012-04-18T10:02:00Z</updated>
    <id>https://int3ractive.com/blog/2012/tutorial-realistic-waterfall-with-css3/</id>
    <content type="html"><![CDATA[
      
A recent project requires me to create a realistic running waterfall. For such task, what came first to my mind was to use animated GIF or PNG sprite sheet and loop them frame by frame. Then my friend, Justin, explored more with a semi-transparent water layer overlaying a static waterfall image using Photoshop &amp; Flash. The result was really satisfying. So I decide to adopt it into our project which is pure HTML. Thanks to CSS' background repeat and the new CSS3's animation, the task was really simple to achieve and straight forward.<br />
<br />

Here's the demo &amp; source code on Dabblet:&nbsp;<a href="http://dabblet.com/gist/2403656">http://dabblet.com/gist/2403656</a><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://dabblet.com/gist/2403656" style="margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" height="200" src="https://1.bp.blogspot.com/-QkKrcdYj0Ss/T46PEw6JquI/AAAAAAAAEV8/4OJaY0bZSFI/s400/realistic-css3-waterfall.jpg" width="400" /></a></div>
<br />
It is worth noting that CSS3's animation is still an experiment feature. You can still achieve same result using JS to shift the background at intervals.<br />
<br />
Let me explain step by step to re-create the effect:<br />
<a name='more'></a><br />
<h3>
The images</h3>
1. Find a nice <a href="http://www.deviantart.com/download/54948872/Waterfall_n_Mossy_Rocks_Stock_by_Enchantedgal_Stock.jpg" rel="nofollow" target="_blank">waterfall photo</a>, open it in Photoshop<br />
<br />
2. Use magic wand / color range selection / lasso tool... to select waterfall area<br />
<br />
3. Use feather / quick mask to soften the edges<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-9MOaRWrwtS8/T46GCyDfKlI/AAAAAAAAEVE/Tdr-Q7dkZVw/s1600/01-masking.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://4.bp.blogspot.com/-9MOaRWrwtS8/T46GCyDfKlI/AAAAAAAAEVE/Tdr-Q7dkZVw/s400/01-masking.png" width="400" /></a></div>
<br />
4. Invert selection &gt; copy selection to new layer &gt; receive draft "mask" for waterfall (the waterfall area is see-through)<br />
<br />
5.&nbsp;On the draft mask layer, make a rectangle selection around the "hole" we just "punched", make sure it fully cover the semi-transparent soft edges &gt; invert selection &gt; delete. This leaves a smaller rectangle mask around the white water area. Remember the rectangle's offset from the original waterfall image. You'll need it later. Duplicate the layer to new document &gt; crop it &gt; save it as waterfall-mask.png<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-VlCvoRKuJfw/T46G7LeBAbI/AAAAAAAAEVM/mZrN5aj4UV0/s1600/waterfall-mask.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://1.bp.blogspot.com/-VlCvoRKuJfw/T46G7LeBAbI/AAAAAAAAEVM/mZrN5aj4UV0/s320/waterfall-mask.png" width="114" /></a></div>
<br />
6. Copy the water running part of the waterfall to new document.<br />
<br />
7. Resize its canvas to fit the mask above.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-TN5lG9BslHU/T46HPd6mMhI/AAAAAAAAEVU/lGMGutCLrA0/s1600/02-waterfall-canvas.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://2.bp.blogspot.com/-TN5lG9BslHU/T46HPd6mMhI/AAAAAAAAEVU/lGMGutCLrA0/s400/02-waterfall-canvas.png" width="400" /></a></div>
<br />
8. If using Photoshop CS5+: select part of the water fall &gt; select invert &gt; fill &gt; content aware<br />
If older Photoshop / other software: use clone tool&nbsp;manually fill the other area with waterfall pattern.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-CQnuNEivK6Q/T46HalxHmEI/AAAAAAAAEVc/6iHF2kfkae4/s1600/02-waterfall-pattern.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://2.bp.blogspot.com/-CQnuNEivK6Q/T46HalxHmEI/AAAAAAAAEVc/6iHF2kfkae4/s400/02-waterfall-pattern.png" width="400" /></a></div>
<br />
9. To make seamless loop, double canvas' height &gt; duplicate the waterfall layer &gt; flip it vertically and move it to the bottom half of the larger canvas.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/--PUAoasr0Uw/T46HslNG7KI/AAAAAAAAEVk/fZzP6YTrdxw/s1600/03-waterfall-loop.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://3.bp.blogspot.com/--PUAoasr0Uw/T46HslNG7KI/AAAAAAAAEVk/fZzP6YTrdxw/s400/03-waterfall-loop.png" width="400" /></a></div>
<br />
10. Reduce opacity to 50% and save it as waterfall-loop.png<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-IMt09pdOi6I/T46H7fQGHJI/AAAAAAAAEVs/PoWMHoTsgDk/s1600/waterfall-loop.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://2.bp.blogspot.com/-IMt09pdOi6I/T46H7fQGHJI/AAAAAAAAEVs/PoWMHoTsgDk/s320/waterfall-loop.png" width="56" /></a></div>
<br />
<br />
11. On the original waterfall, make selection of the waterfall area from the mask &gt; use motion blur to make the water blurry vertically. &gt; save this as waterfall.jpg<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-43tyWT3Fbng/T46IF2iQCqI/AAAAAAAAEV0/hltyMywCS40/s1600/waterfall.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="267" src="https://4.bp.blogspot.com/-43tyWT3Fbng/T46IF2iQCqI/AAAAAAAAEV0/hltyMywCS40/s320/waterfall.jpg" width="320" /></a></div>
<br />
<h3>
The code</h3>
<h4>
HTML:</h4>
Make 1 waterfall container which contains 2 layer: waterfall-loop &amp; waterfall-mask<br />
<div>
<script src="https://gist.github.com/2403656.js?file=dabblet.html">
</script></div>
<h4>
CSS:</h4>
More explanation in the code comments:<br />
<div>
<script src="https://gist.github.com/2403656.js?file=dabblet.css">
</script></div>
<h3>
Final thoughts</h3>
Thanks to CSS' background repeat, the loop is ridiculously simple to create, no need for complicate background looping technique.<br />
<br />
This technique only work for waterfall photo which was captured from direct angle and the water flow running vertically. For other angles, it may be tricky. It can also be applied&nbsp;for river with water moving horizontally.

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Geany: open-source SublimeText for front-end developer</title>
    <link href="https://int3ractive.com/blog/2012/geany-open-source-sublimetext-for-front/"/>
    <updated>2012-04-13T03:21:00Z</updated>
    <id>https://int3ractive.com/blog/2012/geany-open-source-sublimetext-for-front/</id>
    <content type="html"><![CDATA[
      
When I started doing JavaScript, I kept searching for an ideal JS code editor that is free, lightweight and fast just like FlashDevelop, my favorite ActionScript counter part. (In case you're wondering, I have made a <a href="http://bit.ly/jD0qUD" target="_blank">Wine mod of FD4</a> and been able to run it on Linux). Most JS editors I tried were Java-based, heavy and code assistance is as not good as I expected.<br />
<br />
Then I discovered <a href="http://www.sublimetext.com/2" target="_blank">SublimeText 2</a> and <a href="http://geany.org/" target="_blank">Geany</a>. The former is commercial and the latter is opensource. Both of them are cross platform, lightweight, fast and has syntax highlighting for quite a number languages. For JavaScript and front-end stuff in particular, they both have some support for code hinting and auto completion but fairly limited.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td colspan="1" rowspan="1" style="text-align: center;"><a href="https://2.bp.blogspot.com/-dmqGJXrnnzQ/T4aLdfsvJ0I/AAAAAAAAESY/mHhvI7HBLZ8/s1600/geany-interface.png" style="margin-left: auto; margin-right: auto;"><img height="301" src="https://2.bp.blogspot.com/-dmqGJXrnnzQ/T4aLdfsvJ0I/AAAAAAAAESY/mHhvI7HBLZ8/s400/geany-interface.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" colspan="1" rowspan="1" style="text-align: center;">Geany interface</td></tr>
</tbody></table>
<br />
<a name='more'></a><br />
I tried them both for coding JavaScript. I have to admit that SublimeText is more elegant, stylish, and has better syntax highlighting in some cases. But it is not free (as in free speech and free beer). I'm not bashing SublimeText but as someone who advocates open source, I'm determined to embrace Geany, and you should give Geany some favors too.<br />
<br />
The more I use Geany, the more potential I think it has. Thanks to its current support of extra configuration files, I found it is relatively easy to fix some issues of its current syntax highlighting and add some automatic code completion for a specific language.<br />
<br />
So I created some supplement files to enhance Geany in coding of HTML/CSS/JS (required some manual works with Copy-n-Paste and some regular-expression search-replace). I have <a href="https://github.com/trongthanh/geany-for-front-end-dev" target="_blank">posted them on GitHub</a> for version control and for anyone interested to contribute to it. I also have a more detailed instruction at the GitHub project on how to install these files and what have been enhanced.<br />
<br />
Here are some screen shots featuring my Geany's enhancement for front-end dev:<br />
<br />
- Better source code highlighting<br />
<br />
<div style="clear: both; text-align: center;">
<a href="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/css-highlighting.png" style="margin-left: 1em; margin-right: 1em;"><img height="112" src="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/css-highlighting.png" width="400" /></a></div>
<br />
- Code completion for JavaScript (currently: core classes, some DOM &amp; Mootools)<br />
<br />
<div style="clear: both; text-align: center;">
<a href="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/js-code-hinting.png" style="margin-left: 1em; margin-right: 1em;"><img src="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/js-code-hinting.png" /></a></div>
<br />
- Function parameters hinting for JavaScript:<br />
<br />
<div style="clear: both; text-align: center;">
<a href="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/js-function-hinting.png" style="margin-left: 1em; margin-right: 1em;"><img src="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/js-function-hinting.png" /></a></div>
<br />
- Property completion for CSS (with latest CSS3):<br />
<br />
<div style="clear: both; text-align: center;">
<a href="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/css-hinting.png" style="margin-left: 1em; margin-right: 1em;"><img height="383" src="https://github.com/trongthanh/geany-for-front-end-dev/raw/master/ref/images/css-hinting.png" width="400" /></a></div>
<br />
I'm looking into enhance it further. But for now<a href="https://github.com/trongthanh/geany-for-front-end-dev" target="_blank"> Geany-for-front-end-dev</a> is quite nice for me to work with.<br />
<br />

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project: Justin Portfolio</title>
    <link href="https://int3ractive.com/blog/2012/project-justin-portfolio/"/>
    <updated>2012-03-15T04:30:00Z</updated>
    <id>https://int3ractive.com/blog/2012/project-justin-portfolio/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-l9eTjMMAj2Y/T-KgFT11LkI/AAAAAAAAEu0/x1n--iwB3O0/s1600/Justin+Portfolio+2012-06-16+13-08-52.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="211" src="https://1.bp.blogspot.com/-l9eTjMMAj2Y/T-KgFT11LkI/AAAAAAAAEu0/x1n--iwB3O0/s400/Justin+Portfolio+2012-06-16+13-08-52.jpeg" width="400" /></a></div><br />
<span style="background-color: white;">One of the projects to challenge my skill in JavaScript and HTML5. The original parallax scrolling experience is coded from scratch with the help of MooTools framework.&nbsp;</span><span style="background-color: white;">I learned a lot from this project and &nbsp;got everything I need </span><span style="background-color: white;">to handle larger front-end interactive websites.</span><br />
<br />
<span style="background-color: white;">Visit <a href="http://justin.buitran.me/" target="_blank">the site</a>.</span><br />
<br />
<span style="background-color: white;">Technical features:</span><br />
<ul><li><a href="http://html5boilerplate.com/" target="_blank">HTML5 Boilerplate</a></li>
<li><a href="http://mootools.net/" target="_blank">MooTools 1.4</a></li>
<li><a href="https://github.com/mrdoob/three.js/" target="_blank">ThreeJS 3D</a> library &amp; its <a href="http://mrdoob.github.com/three.js/examples/canvas_geometry_birds.html" target="_blank">Birds Demo</a></li>
<li>CSS3's transition &amp; animation</li>
</ul>Related posts:<br />
<ul><li><a href="http://blog.int3ractive.com/2012/04/tutorial-realistic-waterfall-with-css3.html" target="_blank">Realistic waterfall effect with CSS</a></li>
<li><a href="http://blog.int3ractive.com/2012/05/fish-boids-threejs-demo.html" target="_blank">Fish boids</a></li>
</ul><br />
<a href="https://4.bp.blogspot.com/-ueIAQ91D_WI/T-KgNTOPSFI/AAAAAAAAEu8/1pjqJvUqNLg/s1600/Justin+Portfolio+2012-06-16+13-09-57.jpeg" imageanchor="1" style="background-color: white; clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img style="display: inline !important;" border="0" height="106" src="https://4.bp.blogspot.com/-ueIAQ91D_WI/T-KgNTOPSFI/AAAAAAAAEu8/1pjqJvUqNLg/s200/Justin+Portfolio+2012-06-16+13-09-57.jpeg" width="200" /></a><a href="https://2.bp.blogspot.com/-ChTmMhXJYBg/T-KgTPZxGDI/AAAAAAAAEvE/fL5oimWwJy4/s1600/Justin+Portfolio+2012-06-16+13-11-37.jpeg" imageanchor="1" style="background-color: white; clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img style="display: inline !important;" border="0" height="106" src="https://2.bp.blogspot.com/-ChTmMhXJYBg/T-KgTPZxGDI/AAAAAAAAEvE/fL5oimWwJy4/s200/Justin+Portfolio+2012-06-16+13-11-37.jpeg" width="200" /></a><br><a href="https://3.bp.blogspot.com/-pWBGDQIbElw/T-Kgc1wxI4I/AAAAAAAAEvM/Qrs2G_LIrQk/s1600/Justin+Portfolio+2012-06-16+13-12-14.jpeg" imageanchor="1" style="background-color: white; clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img style="display: inline !important;" border="0" height="106" src="https://3.bp.blogspot.com/-pWBGDQIbElw/T-Kgc1wxI4I/AAAAAAAAEvM/Qrs2G_LIrQk/s200/Justin+Portfolio+2012-06-16+13-12-14.jpeg" width="200" /></a><a href="https://3.bp.blogspot.com/-Cq1vN9emV4A/T-Khylndj5I/AAAAAAAAEvU/GTbxYcSbcOo/s1600/Justin+Portfolio+-+Chromium_063.jpeg" imageanchor="1" style="background-color: white; clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img style="display: inline !important;" border="0" height="106" src="https://3.bp.blogspot.com/-Cq1vN9emV4A/T-Khylndj5I/AAAAAAAAEvU/GTbxYcSbcOo/s200/Justin+Portfolio+-+Chromium_063.jpeg" width="200" /></a><br />
<br />

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project: J&amp;J HTML Template</title>
    <link href="https://int3ractive.com/blog/2012/project-j-html-template/"/>
    <updated>2012-03-06T06:06:00Z</updated>
    <id>https://int3ractive.com/blog/2012/project-j-html-template/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-5tP_n79fbok/T_cLf4j09-I/AAAAAAAAExs/wd5A6eriOjE/s1600/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+15-57-08.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://2.bp.blogspot.com/-5tP_n79fbok/T_cLf4j09-I/AAAAAAAAExs/wd5A6eriOjE/s200/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+15-57-08.jpeg" width="170" /></a></div>
This is an HTML template for a privately developed CMS website. The job involved converting Photoshop .PSD files into HTML/CSS template, Javascripting validation for contact form and Google maps interaction. At the same time, I custom made the Flash banner carousel with the text &amp; images customizable via XML feed. Due to CMS restrictions and corporate's guidelines, the template is rather traditional.<br />
<br />
The live site can be visited here:&nbsp;<i>www.comms.%6A%6A%73%65%61.com</i> <a href="javascript:;" title="Copy and paste the URL string to browser's address bar">[?]</a><br />
Note: the CMS developers have altered some layout and client-size logic. Here's the link to my&nbsp;<a href="http://in2ideas.com.php5-23.dfw1-2.websitetestlink.com/clients/jjsea/comms_site/homepage.html" rel="nofollow" target="_blank">demo site</a>&nbsp;before integration.<br />
<br />
Technical notes:<br />
<ul>
<li>jQuery</li>
<li>Google Maps API</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-yUoBTzgGdcw/T_cL-4ETMyI/AAAAAAAAEx0/Y1dZjl4d0HQ/s1600/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+15-57-54.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://2.bp.blogspot.com/-yUoBTzgGdcw/T_cL-4ETMyI/AAAAAAAAEx0/Y1dZjl4d0HQ/s200/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+15-57-54.jpeg" width="144" /></a><a href="https://4.bp.blogspot.com/-pXwc2mFw2Gc/T_cPdwLSBvI/AAAAAAAAEyM/cpHOEatSN_g/s1600/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+16-01-27.jpeg" imageanchor="1" style="background-color: white; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://4.bp.blogspot.com/-pXwc2mFw2Gc/T_cPdwLSBvI/AAAAAAAAEyM/cpHOEatSN_g/s200/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+16-01-27.jpeg" width="168" /></a><a href="https://3.bp.blogspot.com/-4ScWdG7oYao/T_cPS-ja3NI/AAAAAAAAEyE/Hqp1MMbS9Vc/s1600/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+16-00-24.jpeg" imageanchor="1" style="background-color: white; clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://3.bp.blogspot.com/-4ScWdG7oYao/T_cPS-ja3NI/AAAAAAAAEyE/Hqp1MMbS9Vc/s200/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+16-00-24.jpeg" width="180" /></a>&nbsp;<a href="https://4.bp.blogspot.com/-KHYnZuMbUcQ/T_cNgwLv3dI/AAAAAAAAEx8/i0r70RhGa_k/s1600/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+15-58-40.jpeg" imageanchor="1" style="background-color: white; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://4.bp.blogspot.com/-KHYnZuMbUcQ/T_cNgwLv3dI/AAAAAAAAEx8/i0r70RhGa_k/s200/Jebsen+&amp;+Jessen+Communications:+Total+solutions+for+your+communication+needs+2012-06-16+15-58-40.jpeg" width="132" /></a></div>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Demo: Stage3D Fireworks with Flare3D</title>
    <link href="https://int3ractive.com/blog/2012/demo-stage3d-fireworks-with-flare3d/"/>
    <updated>2012-01-20T13:22:00Z</updated>
    <id>https://int3ractive.com/blog/2012/demo-stage3d-fireworks-with-flare3d/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-Ph3PemeMT6Y/T91X3lDvWyI/AAAAAAAAErM/FvWkjEniIv8/s1600/Selection_001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="293" src="https://2.bp.blogspot.com/-Ph3PemeMT6Y/T91X3lDvWyI/AAAAAAAAErM/FvWkjEniIv8/s400/Selection_001.png" width="400" /></a></div>
<br />
My going back to Flash to experiment on Stage3D. The animation make use of<span style="background-color: white;">&nbsp;Flare3D engine. Thanks to its built-in shaders and particles components, I was able to create the fireworks and the lightning effects without much trouble. However there's still room to improve the fireworks effect with more particles.</span><br />
<br />
<a href="http://labs.int3ractive.com/flash/stage3d/lunar-new-year-fireworks/" target="_blank">View the demo</a>.

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Case Study: WebGL 360° Panorama</title>
    <link href="https://int3ractive.com/blog/2011/case-study-webgl-360-panorama/"/>
    <updated>2011-12-20T11:00:00Z</updated>
    <id>https://int3ractive.com/blog/2011/case-study-webgl-360-panorama/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-olOavrKzSfo/T-KUyOMgsnI/AAAAAAAAEuk/0TOWubVgnig/s1600/Labs+-+In2+Office+in+360+-+A+WebGL+experiment.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-olOavrKzSfo/T-KUyOMgsnI/AAAAAAAAEuk/0TOWubVgnig/s1600/Labs+-+In2+Office+in+360+-+A+WebGL+experiment.png" /></a></div>
<span style="background-color: white;"><br /></span><br />
<span style="background-color: white;">A 360° walk-through of my office. This is a&nbsp;<a href="http://labs.int3ractive.com/javascript/webgl/panorama/in2sg_office_panorama.html" target="_blank">case study</a> with the <a href="https://github.com/mrdoob/three.js/" target="_blank">ThreeJS</a> 3D engine for HTML5 Canvas and WebGL. I have adapted the ThreeJS WebGL&nbsp;</span><a href="http://mrdoob.github.com/three.js/examples/webgl_panorama_equirectangular.html" target="_blank">equirectangular panorama demo</a>, making it fall back to Canvas renderer when browser doesn't support WebGL. The overlaying markers are DOM objects. There's some coordinates conversion between ThreeJS 3D world and 2D DOM. In this adaptation, there are 2 spherical panoramas so users can navigate and see more corners of the office. Just for fun and experimental purpose, some snowing effect added on the occasion of Christmas 2011.<br />
<br />
Components used:<br />
<span style="background-color: white;">- ThreeJS WebGL&nbsp;</span><span style="background-color: white;"><a href="http://mrdoob.github.com/three.js/examples/webgl_panorama_equirectangular.html" target="_blank">equirectangular panorama demo</a></span><br />
-&nbsp;<a href="https://github.com/sebleedelisle/JavaScript-PixelPounding-demos" target="_blank">Snowing effect</a> by&nbsp;Seb Lee-Delisle<br />
<br />
Finally, check out <a href="http://labs.int3ractive.com/javascript/webgl/panorama/in2sg_office_panorama.html" target="_blank">the demo</a>&nbsp;and&nbsp;grab the <a href="https://github.com/trongthanh/labs.int3ractive.com/tree/gh-pages/javascript/webgl/panorama" target="_blank">source code</a>.<br />
<br />

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Case Study: In2 Profile</title>
    <link href="https://int3ractive.com/blog/2011/case-study-in2-profile/"/>
    <updated>2011-11-23T09:54:00Z</updated>
    <id>https://int3ractive.com/blog/2011/case-study-in2-profile/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-EH8PgVMuNEo/T5Ppf_yE6rI/AAAAAAAAEbU/nzNPP2UUhLM/s1600/Selection_045.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="226" src="https://1.bp.blogspot.com/-EH8PgVMuNEo/T5Ppf_yE6rI/AAAAAAAAEbU/nzNPP2UUhLM/s400/Selection_045.png" width="400" /></a></div>
<br />
This is a case study that my team set out to explore HTML5 / CSS3 but it is also served as pitch deck for my company's profile presentation. This one-page parallax scrolling website is inspired by the one of the 2010 buzzing HTML5 experiences, <a href="http://nikebetterworld.com/about" target="_blank">nikebetterworld.com</a>. Everything was coded from scratch.<br />
<br />
We developed 2 versions. The <a href="http://int3ractive.com/casestudies/in2profile/v1" rel="nofollow" target="_blank">first version</a> features usual parallax scrolling with arrow drawing effect using canvas. The <a href="http://int3ractive.com/casestudies/in2profile/v2" rel="nofollow" target="_blank">second version</a> is a revamped one with additional animation on the illustrating graphics. I also experimented CSS3 transitions effect on the menu and some buttons.<br />
<br />
My role: JavaScript + HTML Developer, Technical Researcher<br />
<br />
Technical features:<br />
<ul>
<li>jQuery (<a href="http://jquery.com/" target="_blank">library</a>)</li>
<li>HTML5 Boilerplate (<a href="http://html5boilerplate.com/" target="_blank">library</a>)</li>
<li>HTML5 Canvas</li>
<li>CSS3 transitions</li>
</ul>
<br />
<a href="https://2.bp.blogspot.com/-sBu7hlac4Gg/T5P-3pPVVFI/AAAAAAAAEbg/IEbIUDmHHp8/s1600/Selection_046.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="108" src="https://2.bp.blogspot.com/-sBu7hlac4Gg/T5P-3pPVVFI/AAAAAAAAEbg/IEbIUDmHHp8/s200/Selection_046.png" width="200" /></a><a href="https://2.bp.blogspot.com/-HPaoL_Cr0w4/T5P_AU9DkYI/AAAAAAAAEbo/Lz8SZHvNAmM/s1600/Selection_048.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="108" src="https://2.bp.blogspot.com/-HPaoL_Cr0w4/T5P_AU9DkYI/AAAAAAAAEbo/Lz8SZHvNAmM/s200/Selection_048.png" width="200" /></a><a href="https://3.bp.blogspot.com/-LWls_tqMWzc/T5P_HntAqUI/AAAAAAAAEbw/PyGfizLLoQE/s1600/Selection_049.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="108" src="https://3.bp.blogspot.com/-LWls_tqMWzc/T5P_HntAqUI/AAAAAAAAEbw/PyGfizLLoQE/s200/Selection_049.png" width="200" /></a>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project: Turbo Race Track</title>
    <link href="https://int3ractive.com/blog/2011/project-turbo-race-track/"/>
    <updated>2011-09-15T15:00:00Z</updated>
    <id>https://int3ractive.com/blog/2011/project-turbo-race-track/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-ed8kMUoZ2jk/T-B34N24N6I/AAAAAAAAEsU/ESzT5uJAZ_4/s1600/turbo_race_01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://1.bp.blogspot.com/-ed8kMUoZ2jk/T-B34N24N6I/AAAAAAAAEsU/ESzT5uJAZ_4/s400/turbo_race_01.jpg" width="400" /></a></div>
<br />
This full flash minisite is part of a campaign to interactively inform users about Intel's partner membership program&nbsp;<span style="background-color: white;">(APAC only)</span><span style="background-color: white;">&nbsp;and guide them to earn more credits to enhance their membership level. There is a web service-driven section where weekly leading credit earners are listed to make the "race" more excited. The mechanism is relatively simple and straightforward. There's no demo link since this is a membership-only website.</span><br />
<br />
My role: Flash developer<br />
<span style="background-color: white;">Technical highlights:</span><br />
<ul>
<li>MVC approach with Robotlegs framework</li>
<li>AS3-Signals</li>
<li>Greensock's TweenLite</li>
</ul>
<br />
<a href="https://1.bp.blogspot.com/-LEti6AKc5sU/T-B4P5Zs63I/AAAAAAAAEsk/Fwzhip4OITw/s1600/turbo_race_03.jpg" imageanchor="1" style="background-color: white; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="118" src="https://1.bp.blogspot.com/-LEti6AKc5sU/T-B4P5Zs63I/AAAAAAAAEsk/Fwzhip4OITw/s200/turbo_race_03.jpg" width="200" /></a><a href="https://2.bp.blogspot.com/-67Nq_ahTDAc/T-B4HRF2_MI/AAAAAAAAEsc/K7bJytB9fL8/s1600/turbo_race_02.jpg" imageanchor="1" style="background-color: white; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="118" src="https://2.bp.blogspot.com/-67Nq_ahTDAc/T-B4HRF2_MI/AAAAAAAAEsc/K7bJytB9fL8/s200/turbo_race_02.jpg" width="200" /></a><a href="https://1.bp.blogspot.com/-FdKomXDvb1U/T-B4bFH-uFI/AAAAAAAAEss/VvsyJk-gSzc/s1600/turbo_race_04.jpg" imageanchor="1" style="background-color: white; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="118" src="https://1.bp.blogspot.com/-FdKomXDvb1U/T-B4bFH-uFI/AAAAAAAAEss/VvsyJk-gSzc/s200/turbo_race_04.jpg" width="200" /></a>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project: Training Credits Estimator</title>
    <link href="https://int3ractive.com/blog/2011/project-training-credits-estimator/"/>
    <updated>2011-06-24T14:48:00Z</updated>
    <id>https://int3ractive.com/blog/2011/project-training-credits-estimator/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-X_KbUNjWGiw/T-CNffeocbI/AAAAAAAAEtA/_k_3Ia882ro/s1600/estimator_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="258" src="https://2.bp.blogspot.com/-X_KbUNjWGiw/T-CNffeocbI/AAAAAAAAEtA/_k_3Ia882ro/s400/estimator_1.png" width="400" /></a></div>
<br />
The aim of this site is to support Intel's&nbsp;<span style="background-color: white;">partners and&nbsp;</span><span style="background-color: white;">distributors&nbsp;in estimating their attendance in training courses offered by the company in order to maintain their&nbsp;privileged&nbsp;membership. For each type of membership, users have to select the courses with number of attendees, various training types and courses. The system will automatically calculate the credits</span><span style="background-color: white;">&nbsp;members would be able to gain from said inputs. Disclaimer and a notice box will appear&nbsp;</span><span style="background-color: white;">at the beginning</span><span style="background-color: white;">&nbsp;and</span><span style="background-color: white;">&nbsp;</span><span style="background-color: white;">at the end</span><span style="background-color: white;">&nbsp;respectively congratulating users having fulfilled the required credits. The most tricky part making text components flexible so that the site is&nbsp;</span><span style="background-color: white;">interchangeable</span><span style="background-color: white;">&nbsp;within 6 different languages.</span><br />
<br />
My role: Flash Developer<br />
Technical features:<br />
<ul>
<li>MVC approach&nbsp;</li>
<li>Multilingual with external fonts &amp; texts loading</li>
<li><a href="http://www.robotlegs.org/" target="_blank">Robotlegs</a> framework</li>
<li><a href="https://github.com/robertpenner/as3-signals" target="_blank">AS3-Signals</a> (AS3 Events replacement)</li>
</ul>
<br />
<a href="https://2.bp.blogspot.com/-6PZnIxWtdXA/T-CN5i6WmeI/AAAAAAAAEtI/rfBhHxZCvgg/s1600/estimator_2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="129" src="https://2.bp.blogspot.com/-6PZnIxWtdXA/T-CN5i6WmeI/AAAAAAAAEtI/rfBhHxZCvgg/s200/estimator_2.png" width="200" /></a><a href="https://2.bp.blogspot.com/-AV0tN8D1dFw/T-CN_m3YuHI/AAAAAAAAEtQ/jhOA1oU5xj8/s1600/estimator_3.png" imageanchor="1" style="background-color: white; clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="130" src="https://2.bp.blogspot.com/-AV0tN8D1dFw/T-CN_m3YuHI/AAAAAAAAEtQ/jhOA1oU5xj8/s200/estimator_3.png" width="200" /></a><br />
<br />
<a href="https://1.bp.blogspot.com/-0FJoubAYmlc/T-COHt6sYXI/AAAAAAAAEtY/scWQZ1nBadE/s1600/estimator_4.png" imageanchor="1" style="background-color: white; clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="130" src="https://1.bp.blogspot.com/-0FJoubAYmlc/T-COHt6sYXI/AAAAAAAAEtY/scWQZ1nBadE/s200/estimator_4.png" width="200" /></a><a href="https://4.bp.blogspot.com/-Gu6Te929e4M/T-COM8ik34I/AAAAAAAAEtg/HB2RXF1lujE/s1600/estimator_5.png" imageanchor="1" style="background-color: white; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="129" src="https://4.bp.blogspot.com/-Gu6Te929e4M/T-COM8ik34I/AAAAAAAAEtg/HB2RXF1lujE/s200/estimator_5.png" width="200" /></a><br />
<br />
<br />

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Bắt đầu với Molehill (Stage3D) - Phần 2</title>
    <link href="https://int3ractive.com/blog/2011/bat-dau-voi-molehill-stage3d-phan-2/"/>
    <updated>2011-05-15T13:15:00Z</updated>
    <id>https://int3ractive.com/blog/2011/bat-dau-voi-molehill-stage3d-phan-2/</id>
    <content type="html"><![CDATA[
      <p>[This is a translation and edit of the article “<a href="http://labs.jam3.ca/2011/03/molehill-getting-started/">Molehill Getting Started</a>” from <a href="http://labs.jam3.ca">labs.jam3.ca</a>]</p>
<h2>PHẦN 2. TÌM HIỂU MOLEHILL (STAGE3D) API</h2>
<table>
<thead>
<tr>
<th>Trình độ: Cao Cấp</th>
<th>Phần mềm</th>
<th>File mẫu</th>
</tr>
</thead>
<tbody>
<tr>
<td>- Vững ActionScript 3<br>- Biết FlashDevelop<br>- Biết Flash 3D hoặc 3D Engine</td>
<td>- Flash Develop 4 (<a href="http://www.flashdevelop.org/community/viewtopic.php?f=9&amp;t=3529">tải về</a>)<br>- Flex SDK 4.5 r.19786 (<a href="http://opensource.adobe.com/wiki/display%20/flexsdk/Download+Flex+Hero">tải về</a>)</td>
<td><a href="http://code.google.com/p/thanhtran-sources/downloads/detail?name=molehill_getting_start_p2.zip&amp;can=2&amp;q=">molehill_getting_start_p2.zip</a></td>
</tr>
</tbody>
</table>
<blockquote>
<p>(TTT) Đây là bài viết giới thiệu về Molehill (Stage3D) API ở khía cạnh cơ bản của nó. Molehill API là một tập lệnh cấp thấp nên đòi hỏi bạn phải vững về ActionScript 3 và có chút kinh nghiệm về 3D (Flash) để có thể dễ dàng tiếp cận hơn.</p>
</blockquote>
<p>(Dịch) Trước khi chúng ta bắt đầu, có một số thuật ngữ các bạn nên biết:</p>
<h3>Các thuật ngữ:</h3>
<ul>
<li>Vertex: Một điểm trong không gian 3D. Một vertex sẽ xác định đỉnh của một tam giác. Tuy nhiên trong MoleHill, vertex định nghĩa cả vị trí và màu của đỉnh.</li>
<li>Matrix: Bạn dùng Matrix (ma trận) để biến đổi các Vertex. Hãy hình dung Matrix giống như là các “phương trình” để xoay, thay đổi tỉ lệ hoặc thay đổi vị trí của Vertex.</li>
<li>Shader: Shader là một chương trình nhỏ dùng để xử lý Vertex. Shader có thể dùng Matrix để làm các phép biến đổi lên Vertex. (Hay nói cách khác, chương trình thực thi một phương trình lên tất cả các điểm trong 3D). Không như tôi nghĩ, Shader trong MoleHill không chỉ xử lý hoa văn và giao diện mà nó còn dùng để xử lý vị trí của các đối tượng.</li>
</ul>
<p>Bây giờ chúng ta có thể bắt đầu xem xét các thành phần tạo nên MoleHill</p>
<h3>Các thành phần tạo nên MoleHill:</h3>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display/Stage3D.html">Stage3D</a></h4>
<p>Stage3D là phần đứng giữa Flash và bộ máy xử lý đồ họa (GPU). Stage3D không nằm trong display list (bạn không thể làm thao tác addChild với Stage3D). Stage3D tồn tại song song với đối tượng Stage chúng ta đã biết. Stage3D nằm đằng sau tất cả các đối tượng hiển thị của Flash nhưng nằm đằng trước StageVideo.</p>
<p><img src="https://lh6.googleusercontent.com/w_7lTWqtB7I26bDvcJT1Mc32UgZWDtLkdB3IkYwhjfbNdNfEwa_11njE9cJSr2CtlugalajRkl5oUqUaYShLOgPqq9K0EQuKXzEcuutsueG5NLkU2Ig" alt=""></p>
<p>Minh họa Stage3D (nguồn: <a href="http://www.bytearray.org/?p=2555">ByteArray</a>)</p>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display3D/Context3D.html">Context3D</a></h4>
<p>Stage3D sẽ chứa Context3D. Để dễ hình dung, bạn hãy liên tưởng tới việc Bitmap chứa BitmapData. Bạn không vẽ trực tiếp lên Bitmap cũng như bạn sẽ không render đối tượng trực tiếp lên Stage3D. Việc bạn làm với Context3D sẽ tương tự như với BitmapData.</p>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display3D/VertexBuffer3D.html">VertextBuffer3D</a></h4>
<p>Context3D sẽ chứa các đối tượng VertextBuffer3D. Hãy hình dung VertextBuffer3D như là các “chỉ dẫn” cần phải vẽ những gì và chúng trông như thế nào. VertextBuffer3D gồm một Vector. (mảng các giá trị kiểu Number) mà nó sẽ định nghĩa vị trí và màu sắc của vertex. (xem thêm bên dưới)</p>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display3D/IndexBuffer3D.html">IndexBuffer3D</a></h4>
<p>IndexBuffer3D chứa một Vector giống VertexBuffer3D. Nhưng thay vì là một Vector., IndexBuffer3D là một Vector. (các phần tử của Vector có kiểu uint). Hãy hình dung như vầy: VertexBuffer3D sẽ chứa một tập các tọa độ còn IndexBuffer3D sẽ quyết định thứ tự được vẽ của các tọa độ đó. Nếu so sánh chúng với thế giới thực, VertexBuffer3D xác định các thành phố trên bản đồ còn IndexBuffer3D sẽ xác định thứ tự để đến các thành phố đó.</p>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display3D/Program3D.html">Program3D</a></h4>
<p>Program3D là một “chương trình” mà nó sẽ duyệt qua dữ liệu của VertextBuffer3D và “biến đổi” chúng. Program3D chứa 2 Shader mà một sẽ biến đổi vị trí của từng vertex và một sẽ định nghĩa các pixel trong một tam giác sẽ trông như thế nào. 2 chương trình nhỏ đó được gọi là VertexShader và FragmentShader</p>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display3D/Program3D.html#upload%28%29">VertexShader</a></h4>
<p>VertexShader là một chương trình nhỏ viết bằng ngôn ngữ AGAL mà nó sẽ biến đổi vị trí các Vertex (đỉnh) của tam giác. Chẳng hạn, nếu bạn muốn co giãn, xoay, hoặc di chuyển một tam giác, bạn sẽ dùng VertexShader để làm việc này.</p>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display3D/Program3D.html#upload%28%29">FragmentShader</a></h4>
<p>FragmentShader là một chương trình khác viết bằng AGAL mà nó sẽ xử lý các pixel bên trong tác giác. Chẳng hạn, nếu bạn muốn đổi màu tam giác thành màu đỏ thì bạn cần viết một chương trình FragmentShader để làm việc đó.</p>
<p><img src="https://lh6.googleusercontent.com/t0Sc8RdDGijRU4Pk3mI76bvOjRxM0YIvzU2Zm-g_HRjlwFrrOFL3s-rtmltVUtFl4HsU9pExFCOaSZCRNAGjxqFEcpIwJHQnDtNPRVKDM5XRFuj8sIM" alt=""></p>
<p>Hình minh họa về Vertex &amp; Fragment program (nguồn <a href="http://www.bytearray.org/?p=2555">ByteArray</a>)</p>
<h4><a href="http://labs.jam3.ca/asdocs/incubatorAsDoc/flash/display3D/Program3D.html#upload%28%29">AGAL</a></h4>
<p>AGAL (Adobe Graphics Assembly Language) là một ngôn ngữ lập trình cấp thấp. Nó được dùng để viết các chương trình VertexShader và FragmentShader. Nó là trái tim của MoleHill.</p>
<p>Sơ đồ bên dưới mô tả sự liên hệ giữa các thành phần<img src="https://lh3.googleusercontent.com/bPlU0WN5OmVZGMkg4XOMAcmucUWghcDIXOBf9S4sf2qOOVOry4yNWa0_VuoToriw1kyIsTPShsA8gbye6KQsNIWL9unxC3LZiTHP5tkU7i443n5GQg" alt=""></p>
<h3>Ứng dụng MoleHill thường có 2 phần:</h3>
<ol>
<li>Cài đặt</li>
<li>Render (tạm dịch: xử lý hiển thị)</li>
</ol>
<h4>1. Những việc chúng ta cần làm trong giai đoạn Cài đặt</h4>
<ol>
<li>Truy xuất đối tượng Context3D từ Stage3D.</li>
<li>Cài đặt Context3D</li>
<li>Tạo một VertextBuffer</li>
<li>Tạo một IndexBuffer</li>
<li>Gửi dữ liệu Vertex cho VertexBuffer</li>
<li>Gửi dữ liệu Index cho IndexBuffer</li>
<li>Biên dịch VertexShader</li>
<li>Biên dịch FragmentShader</li>
<li>Tạo một Program3D để sử dụng 2 shader vừa tạo</li>
<li>Lắng nghe sự kiện ENTER_FRAME để liên lục gửi dữ liệu đến GPU.</li>
</ol>
<p>Bạn có thể thấy có khá nhiều việc phải làm trong bước cài đặt. Việc cài đặt, theo tôi, phức tạp hơn nhiều so với việc render.</p>
<h4>2. Những việc cần làm trong quá trình Render (ENTER_FRAME):</h4>
<ol>
<li>Dọn sạch Context3D</li>
<li>Cài đặt chương trình Program3D sẽ dùng</li>
<li>Gửi VertextBuffer đến Context3D</li>
<li>Cài đặt dữ liệu cho các shader (khai báo các biến AGAL)</li>
<li>Vẽ các tam giác</li>
<li>Hiển thị ra màn hình các tam giác được vẽ</li>
</ol>
<h3>Mã nguồn ví dụ</h3>
<p>Bây giờ chúng ta sẽ xem qua mã nguồn ví dụ
Phần cài đặt mô tả ở trên được hiện thực trong hàm onGotContext. Bởi vì để lấy được Context3D, chúng ta phải gửi yêu cầu cho Flash và chờ cho đến khi nó được trả về.
Phần render xảy ra trong hàm onRenderLoop xử lý sự kiện ENTER_FRAME.
Tôi đã cố gắng viết thật nhiều dòng ghi chú trong code để bạn có thể dễ nắm bắt. Cũng cần nói thêm là mã nguồn ví dụ này được dựa trên <a href="http://www.bytearray.org/?p=2555">bài blog</a> của Thibault Imbert và <a href="http://2010.max.adobe.com/online/2010/MAX175_1288221804987EOHN">video này</a>.</p>
<pre class="language-actionscript"><code class="language-actionscript"><span class="token keyword">package</span> <span class="token punctuation">{</span>
	<span class="token keyword">import</span> com<span class="token punctuation">.</span>adobe<span class="token punctuation">.</span>utils<span class="token punctuation">.</span>AGALMiniAssembler<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display<span class="token punctuation">.</span>Sprite<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display<span class="token punctuation">.</span>Stage3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display<span class="token punctuation">.</span>StageAlign<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display<span class="token punctuation">.</span>StageScaleMode<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display3D<span class="token punctuation">.</span>Context3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display3D<span class="token punctuation">.</span>Context3DProgramType<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display3D<span class="token punctuation">.</span>Context3DTriangleFace<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display3D<span class="token punctuation">.</span>Context3DVertexBufferFormat<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display3D<span class="token punctuation">.</span>IndexBuffer3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display3D<span class="token punctuation">.</span>Program3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display3D<span class="token punctuation">.</span>VertexBuffer3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>events<span class="token punctuation">.</span>Event<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>geom<span class="token punctuation">.</span>Matrix3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>geom<span class="token punctuation">.</span>Rectangle<span class="token punctuation">;</span>
	<span class="token comment">/**
	 *
	 */</span>
	<span class="token punctuation">[</span><span class="token constant">SWF</span><span class="token punctuation">(</span>width<span class="token operator">=</span><span class="token string">"980"</span><span class="token punctuation">,</span>height<span class="token operator">=</span><span class="token string">"570"</span><span class="token punctuation">,</span>frameRate<span class="token operator">=</span><span class="token string">"60"</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
	<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MolehillDemo</span> <span class="token keyword">extends</span> <span class="token class-name">Sprite</span> <span class="token punctuation">{</span>
		<span class="token comment">//Context3D là nơi xử lý hiển thị xảy ra</span>
		<span class="token comment">//Nó giống như BitmapData đối với Bitmap (Stage3D)</span>
		<span class="token keyword">private</span> <span class="token keyword">var</span> context3d<span class="token punctuation">:</span>Context3D<span class="token punctuation">;</span>
		<span class="token comment">//Đây là đối tượng sẽ lưu dữ liệu của vertex</span>
		<span class="token keyword">private</span> <span class="token keyword">var</span> vertexBuffer<span class="token punctuation">:</span>VertexBuffer3D<span class="token punctuation">;</span>
		<span class="token comment">//Đối tượng này sẽ xác định thứ tự vẽ của các đỉnh vertex</span>
		<span class="token keyword">private</span> <span class="token keyword">var</span> indexBuffer<span class="token punctuation">:</span>IndexBuffer3D<span class="token punctuation">;</span>
		<span class="token comment">//Chương trình này sẽ chứa 2 shader dùng để xử lý các vertex</span>
		<span class="token keyword">private</span> <span class="token keyword">var</span> program<span class="token punctuation">:</span>Program3D<span class="token punctuation">;</span>
		<span class="token comment">//Đây là Ma Trận sẽ được sử dụng bởi VertexShader để xử lý vị trí của các vertex</span>
		<span class="token comment">//(đừng lo, bạn sẽ hiểu nó khi đọc xong bên dưới)</span>
		<span class="token keyword">private</span> <span class="token keyword">var</span> model<span class="token punctuation">:</span>Matrix3D <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Matrix3D</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


		<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">MolehillDemo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token function">trace</span><span class="token punctuation">(</span><span class="token string">"start app"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token comment">//Các lệnh thông thường của Flash để điều chỉnh nội dung Flash không thay đổi tỉ lệ</span>
			<span class="token comment">//và luôn canh lề ở góc trên bên trái</span>
			stage<span class="token punctuation">.</span>scaleMode <span class="token operator">=</span> StageScaleMode<span class="token punctuation">.</span><span class="token constant">NO_SCALE</span><span class="token punctuation">;</span>
			stage<span class="token punctuation">.</span>align <span class="token operator">=</span> StageAlign<span class="token punctuation">.</span><span class="token constant">TOP_LEFT</span><span class="token punctuation">;</span>

			<span class="token comment">//Lắng nghe sự kiện khi Flash sẵn sàng trả vể đối tượng Context3D.</span>
			<span class="token comment">//Đối tượng Context3D có thể không truy xuất được ngay tức thời nên chúng ta</span>
			<span class="token comment">//cần phải lắng nghe sự kiện này.</span>
			stage<span class="token punctuation">.</span>stage3Ds<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span>Event<span class="token punctuation">.</span><span class="token constant">CONTEXT3D_CREATE</span><span class="token punctuation">,</span> onGotContext<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Yêu cầu Flash trả về tham chiếu đến Context3D, Flash sẽ đáp trả trong hàm onGotContext</span>
			stage<span class="token punctuation">.</span>stage3Ds<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">requestContext3D</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Tại đây chúng ta đề nghị Flash hiển thị các hình ảnh 3D trong một khung hình</span>
			<span class="token comment">//chữ nhật rộng 980px, cao 570px bắt đầu từ tọa độ 0,0</span>
			stage<span class="token punctuation">.</span>stage3Ds<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>viewPort <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Rectangle</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">980</span><span class="token punctuation">,</span> <span class="token number">570</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>

		<span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function">onGotContext</span><span class="token punctuation">(</span>e<span class="token punctuation">:</span>Event<span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token keyword">void</span> <span class="token punctuation">{</span>
			<span class="token function">trace</span><span class="token punctuation">(</span><span class="token string">"got context"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token comment">//Nhận được đối tượng Stage3D mà qua đó sẽ lấy được Context3D</span>
			<span class="token keyword">var</span> stage3d<span class="token punctuation">:</span>Stage3D <span class="token operator">=</span> <span class="token function">Stage3D</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>currentTarget<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//cuối cùng cũng lấy được Context3D – Yeah!</span>
			context3d <span class="token operator">=</span> stage3d<span class="token punctuation">.</span>context3D<span class="token punctuation">;</span>
			<span class="token function">trace</span><span class="token punctuation">(</span><span class="token string">"context 3D: "</span> <span class="token operator">+</span> context3d<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token comment">//Khoan đã! Đến đây cũng chưa chắc bạn đã thật sự lấy được Context3D. Câu lệnh</span>
			<span class="token comment">//bên dưới là cách chuẩn để kiểm tra lần cuối bạn có thật sự nhận được Context3D.</span>
			<span class="token comment">//Trong ví dụ này, nếu điều kiện là true, chúng ta sẽ thoát khỏi hàm và không</span>
			<span class="token comment">//làm gì cả.</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>context3d <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
				<span class="token keyword">return</span><span class="token punctuation">;</span>
			<span class="token comment">//Dòng dưới giúp chúng ta nhận được các thông báo lỗi nếu chương trình chạy có vấn đề.</span>
			<span class="token comment">//Khi xuất bản ứng dụng, chúng ta nên cài về false. (Việc này cũng sẽ giúp cải thiện tốc độ).</span>
			context3d<span class="token punctuation">.</span>enableErrorChecking <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>

			<span class="token comment">//Thao tác này tương tự việc khởi tạo BitmapData(980, 570). Chúng ta đang khai báo</span>
			<span class="token comment">//vùng dữ liệu mà chúng ta cần để xử lý. Số 4 là mức độ khử răng cưa.</span>
			<span class="token comment">//Theo tài liệu, các giá trị cho phép của tham số này là:</span>
			<span class="token comment">//0 không khử răng cưa</span>
			<span class="token comment">//2 khử răng cưa ít</span>
			<span class="token comment">//4 khử răng cưa chất lượng cao</span>
			<span class="token comment">//16 khử răng cưa chất lượng rất cao</span>
			<span class="token comment">//nhưng khi tôi thử đặt 16, chương trình bị lỗi nên có thể 16 hiện tại chưa hoạt động.</span>
			context3d<span class="token punctuation">.</span><span class="token function">configureBackBuffer</span><span class="token punctuation">(</span><span class="token number">980</span><span class="token punctuation">,</span> <span class="token number">570</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Ở đây đơn giản chúng ta đang cài đặt nếu một tam giác không quay về phía người</span>
			<span class="token comment">//xem thì không vẽ nó ra (culling: lược bớt)</span>
			<span class="token comment">//context3d.setCulling(Context3DTriangleFace.BACK);</span>
			context3d<span class="token punctuation">.</span><span class="token function">setCulling</span><span class="token punctuation">(</span>Context3DTriangleFace<span class="token punctuation">.</span><span class="token constant">BACK</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Tạo một vertex buffer</span>
			<span class="token comment">//Chúng ta sẽ có 3 vertex và sẽ có 6 giá trị cho mỗi vertex: x, y, z, r, g, b</span>
			vertexBuffer <span class="token operator">=</span> context3d<span class="token punctuation">.</span><span class="token function">createVertexBuffer</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Tạo một buffer chỉ mục (index) cho các vertex</span>
			<span class="token comment">//Chúng ta sẽ vẽ một tam giác, vì vậy sẽ có 3 đỉnh (vertex) và 3 chỉ mục (index)</span>
			indexBuffer <span class="token operator">=</span> context3d<span class="token punctuation">.</span><span class="token function">createIndexBuffer</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Tiếp theo chúng ta sẽ tạo ra mảng dữ liệu cho các vertex. Mảng dữ liệu vertex này</span>
			<span class="token comment">//sẽ chứa thông tin tọa độ và màu sắc của từng vertex.</span>
			<span class="token comment">//Sau đây là giải thích cho mảng dữ liệu bên dưới:</span>
			<span class="token comment">//Vùng thông tin cho mỗi vertex bao gồm tọa độ sau đó là màu sắc.</span>
			<span class="token comment">//x==-1 là vị trí trái cùng của màn hình</span>
			<span class="token comment">//x==1 là vị trí phải cùng của màn hình</span>
			<span class="token comment">//x==0 là vị trí giữa màn hình (theo chiều ngang)</span>
			<span class="token comment">//Tương tự theo chiều dọc cho Y</span>
			<span class="token comment">//Màu sắc cũng được biểu diễn bằng số phân số cho nên:</span>
			<span class="token comment">//1, 0, 0 &lt;- màu đỏ 255 (r, g, b)</span>
			<span class="token comment">//0.5, 0, 0 &lt;- nửa màu đỏ 128</span>

			<span class="token comment">//Mảng sau đây sẽ định nghĩa một tam giác có góc trái dưới màu đỏ, góc giữa trên</span>
			<span class="token comment">//màu xanh lá và góc phải dưới màu xanh dương</span>
			<span class="token keyword">var</span> vertexData<span class="token punctuation">:</span>Vector<span class="token punctuation">.</span> <span class="token operator">=</span> Vector<span class="token punctuation">.</span><span class="token punctuation">(</span>
				<span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token comment">//&lt;- 1st vertex x,y,z,r,g,b</span>
				<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token comment">//&lt;- 2nd vertex x,y,z,r,g,b</span>
				<span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span> <span class="token operator">/</span> <span class="token number">255</span> <span class="token comment">//&lt;- 3rd vertex x,y,z,r,g,b</span>
				<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Sau đây là thứ tự các chỉ mục mà các đỉnh sẽ được vẽ</span>
			<span class="token comment">//0==đỉnh thứ nhất</span>
			<span class="token comment">//1==đỉnh thứ hai</span>
			<span class="token comment">//2==đỉnh thứ ba</span>
			<span class="token keyword">var</span> indexData<span class="token punctuation">:</span>Vector<span class="token punctuation">.</span> <span class="token operator">=</span> Vector<span class="token punctuation">.</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Gửi thông tin của các vertex cho vertex buffer</span>
			vertexBuffer<span class="token punctuation">.</span><span class="token function">uploadFromVector</span><span class="token punctuation">(</span>vertexData<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Gửi dữ liệu chỉ mục cho index buffer</span>
			indexBuffer<span class="token punctuation">.</span><span class="token function">uploadFromVector</span><span class="token punctuation">(</span>indexData<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Chúng ta sẽ cần 1 “bộ biên dịch” AGAL cho vertex shader và 1 cho fragment shader</span>
			<span class="token keyword">var</span> agalVertex<span class="token punctuation">:</span>AGALMiniAssembler <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AGALMiniAssembler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token keyword">var</span> agalFragment<span class="token punctuation">:</span>AGALMiniAssembler <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AGALMiniAssembler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Bây giờ hãy cùng viết vài dòng AGAL</span>
			<span class="token comment">//AGAL là ngôn ngữ rất cơ bản</span>
			<span class="token comment">//Nó bao gồm các câu lệnh (statements)</span>
			<span class="token comment">//Mỗi câu lệnh có ít nhất các thành phần sau</span>
			<span class="token comment">//Operation OutPut, Input1 (Hành-động Dữ-liệu-ra, Dữ-liệu-vào-1)</span>
			<span class="token comment">//Đôi khi nó có thể có 2 tham số truyền vào</span>
			<span class="token comment">//Operation OutPut, Input1, Input2</span>

			<span class="token comment">//Để xem AGAL hoạt động như thế nào, hãy giả sử chúng ta cần làm một phép tính:</span>
			<span class="token comment">//I*J=K</span>
			<span class="token comment">//câu lệnh AGAL sẽ như sau:</span>
			<span class="token comment">//mul K, I, J</span>

			<span class="token comment">//mul==Operation</span>
			<span class="token comment">//K==Output</span>
			<span class="token comment">//I==Input1</span>
			<span class="token comment">//J==Input2</span>

			<span class="token comment">//Sau đây là định nghĩa của một số biến và lệnh được thấy ở dưới</span>
			<span class="token comment">//m44: lệnh để thực thi một ma trận (Matrix) lên dữ liệu</span>
			<span class="token comment">//op: dữ liệu ra là vị trí của vertex trên màn hình</span>
			<span class="token comment">//va0: x, y, z của một vertex trogn tam giác của chúng ta</span>
			<span class="token comment">//vc0: một hằng sẽ được định nghĩa sau (trong trường hợp của chúng ta chính là</span>
			<span class="token comment">//ma trận để chuyển đổi các vertx)</span>
			<span class="token comment">//v0: một “biến” ở giữa vertex shader và fragment shader</span>
			<span class="token comment">//va1: r, g, b của một vertex</span>

			<span class="token comment">//Mô tả của các dòng lệnh tiếp theo như sau:</span>
			<span class="token comment">//m44 op, va0, vc0 -> thực thi một ma trận 4x4 lên vertex và trả về giá trị của nó trên màn hình</span>
			<span class="token comment">//mov v0, va1 → lấy giá tri màu của vertex này và gửi nó cho fragment shader</span>
			<span class="token keyword">var</span> agalVertexSource<span class="token punctuation">:</span>String <span class="token operator">=</span> <span class="token string">"m44 op, va0, vc0\n"</span> <span class="token operator">+</span> <span class="token string">"mov v0, va1\n"</span><span class="token punctuation">;</span>

			<span class="token comment">//oc: dữ liệu ra là màu hiển thị trên màn hình</span>
			<span class="token comment">//v0: biến trung gian giữa vertex shader và fragment shader</span>
			<span class="token comment">//mov oc, v0 -> lấy giá trị màu (biến trung gian đã được lưu từ vertex shader) và xuất ra màn hình</span>
			<span class="token keyword">var</span> agalFragmentSource<span class="token punctuation">:</span>String <span class="token operator">=</span> <span class="token string">"mov oc, v0\n"</span><span class="token punctuation">;</span>

			<span class="token comment">//Biên dịch source AGAL vừa viết thành một mảng ByteArray mà các shader có thể dùng.</span>
			agalVertex<span class="token punctuation">.</span><span class="token function">assemble</span><span class="token punctuation">(</span>Context3DProgramType<span class="token punctuation">.</span><span class="token constant">VERTEX</span><span class="token punctuation">,</span> agalVertexSource<span class="token punctuation">)</span><span class="token punctuation">;</span>
			agalFragment<span class="token punctuation">.</span><span class="token function">assemble</span><span class="token punctuation">(</span>Context3DProgramType<span class="token punctuation">.</span><span class="token constant">FRAGMENT</span><span class="token punctuation">,</span> agalFragmentSource<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Tạo một chương trình (program) để thực thi các shader</span>
			<span class="token comment">//Nên nhớ là chương trình này sẽ chứa một Vertex Shader và một Fragment Shader</span>
			program <span class="token operator">=</span> context3d<span class="token punctuation">.</span><span class="token function">createProgram</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Gửi các shader đã được biên dịch đến program để thực thi</span>
			<span class="token comment">//agalCode==bytearray</span>
			program<span class="token punctuation">.</span><span class="token function">upload</span><span class="token punctuation">(</span>agalVertex<span class="token punctuation">.</span>agalcode<span class="token punctuation">,</span> agalFragment<span class="token punctuation">.</span>agalcode<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Thêm hàm xử lý render liên tục</span>
			<span class="token function">addEventListener</span><span class="token punctuation">(</span>Event<span class="token punctuation">.</span><span class="token constant">ENTER_FRAME</span><span class="token punctuation">,</span> onRenderLoop<span class="token punctuation">)</span><span class="token punctuation">;</span>

		<span class="token punctuation">}</span>

		<span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function">onRenderLoop</span><span class="token punctuation">(</span>event<span class="token punctuation">:</span>Event<span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token keyword">void</span> <span class="token punctuation">{</span>

			<span class="token comment">//Xóa khung hình và màn hình</span>
			context3d<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//cài đặt chương trình dùng để render</span>
			context3d<span class="token punctuation">.</span><span class="token function">setProgram</span><span class="token punctuation">(</span>program<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Có thể bạn sẽ thấy lạ vì 2 dòng bên dưới gần giống như nhau.</span>
			<span class="token comment">//Về cơ bản, đoạn code bên dưới sẽ cho AGAL biết va0 sẽ là x, y, z và va1 sẽ là r, g, b</span>
			<span class="token comment">//Dòng thứ 1</span>
			<span class="token comment">//0: chỉ mục của biến đầu tiên, va0</span>
			<span class="token comment">//vertexBuffer: vertex buffer mà chúng ta sẽ dùng</span>
			<span class="token comment">//0: chỉ mục nơi bắt đầu lấy giá trị cho va0 (0 bởi vì x, y, z bắt đầu tại 0)</span>
			<span class="token comment">//Context3DVertexBufferFormat.FLOAT_3: sẽ có 3 giá trị liên tiếp để lấy: x, y, z</span>
			<span class="token comment">//Dòng thứ 2</span>
			<span class="token comment">//1: chỉ mục của biến va1</span>
			<span class="token comment">//vertexBuffer: vertex buffer mà chúng ta sẽ dùng</span>
			<span class="token comment">//3: chỉ mục nơi bắt đầu lấy giá trị cho va1 (r, g, b bắt đầu tại chỉ mục 3)</span>
			<span class="token comment">//Context3DVertexBufferFormat.FLOAT_3: 3 giá trị liên tiếp để lấy: r, g, b</span>
			<span class="token comment">//Theo tôi bạn có thể dùng Context3DVertexBufferFormat.FLOAT_4 nếu bạn cần sử dụng r, g, b, a</span>
			context3d<span class="token punctuation">.</span><span class="token function">setVertexBufferAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> vertexBuffer<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> Context3DVertexBufferFormat<span class="token punctuation">.</span><span class="token constant">FLOAT_3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			context3d<span class="token punctuation">.</span><span class="token function">setVertexBufferAt</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> vertexBuffer<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> Context3DVertexBufferFormat<span class="token punctuation">.</span><span class="token constant">FLOAT_3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Lấy giá trị mặc định của ma trận</span>
			model<span class="token punctuation">.</span><span class="token function">identity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Co tỉ lệ của tam giác xuống 0.5 theo x, y, z</span>
			model<span class="token punctuation">.</span><span class="token function">appendScale</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Gán ma trận vừa khai báo vào biến vc0 và nó sẽ được dùng để xử lý dữ liệu vertex của chúng ta</span>
			context3d<span class="token punctuation">.</span><span class="token function">setProgramConstantsFromMatrix</span><span class="token punctuation">(</span>Context3DProgramType<span class="token punctuation">.</span><span class="token constant">VERTEX</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> model<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Vẽ hình tam giác của chúng ta ra màn hình</span>
			<span class="token comment">//0 là chỉ mục của vị trí (trong vertex buffer) bắt đầu vẽ</span>
			<span class="token comment">//1 là số tam giác sẽ vẽ</span>
			context3d<span class="token punctuation">.</span><span class="token function">drawTriangles</span><span class="token punctuation">(</span>indexBuffer<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token comment">//Hiển thị tam giác tra màn hình</span>
			context3d<span class="token punctuation">.</span><span class="token function">present</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Để biên dịch được đoạn code trên, bạn cũng làm các bước chuẩn bị như ở Phần 1-II-1.
Các bước để biên dịch đoạn code trên như sau:</p>
<ol>
<li>Vào project settings, thêm thư mục lib vào danh sách Classpaths.</li>
<li>Tải về thư viện AGALMiniAssembler <a href="http://www.bytearray.org/wp-content/projects/agalassembler/com.zip">tại đây</a> (đây là lớp tiện ích bên ngoài, không có sẵn trong Flash Player Incubator), giải nén vào thư mục lib của dự án. (thư mục ‘com’ ở trong ‘lib’).
(Nếu bạn dùng lại dự án đã tạo cho phần 1 thì không cần phải làm bước này, AGALMiniAssembler đã được đóng gói sẵn với Away3D)</li>
<li>Tạo một lớp mới tên <a href="http://MolehillDemo.as">MolehillDemo.as</a> và nhập nội dung của lớp như ở trên.</li>
<li>Click chuột phải lên <a href="http://MolehillDemo.as">MolehillDemo.as</a> trên cửa sổ Project Manager, chọn Document Class</li>
<li>Nhấn F8 hoặc Project &gt; Build Project để biên dịch ứng dụng.</li>
<li>Mở file index.html bằng browser đã cài Flash Player Incubator.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/JB8RjYicIi3dk27lFpofdyOeat4xQ0JrrPit2GRw3Cl1uLArxo18WsG-EnDO8DhDmthM24ue2fSdYIsLfrhuBwCeCSJdd4dmehtt9_XhzXk7ap4ISx0" alt=""></p>
<h3>Xem thêm:</h3>
<ul>
<li>Bài viết gốc: <a href="http://labs.jam3.ca/2011/03/molehill-getting-started">http://labs.jam3.ca/2011/03/molehill-getting-started</a></li>
<li>Giới thiệu về Flash Player Incubator và cách biên dịch: <a href="http://labs.adobe.com/wiki/index.php/Flash_Player_Incubator#Authoring_for_Flash_Player_11.2C0.2C0.2C58_Incubator">http://labs.adobe.com/wiki/index.php/Flash_Player_Incubator#Authoring_for_Flash_Player_11.2C0.2C0.2C58_Incubator</a></li>
<li>Đào sâu hơn về Molehill API: <a href="http://www.bytearray.org/?p=2555">http://www.bytearray.org/?p=2555</a></li>
</ul>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Bắt đầu với Molehill - Phần 1</title>
    <link href="https://int3ractive.com/blog/2011/bat-dau-voi-molehill-phan-1/"/>
    <updated>2011-05-06T04:02:00Z</updated>
    <id>https://int3ractive.com/blog/2011/bat-dau-voi-molehill-phan-1/</id>
    <content type="html"><![CDATA[
      <p>[This tutorial discusses How to get started with Molehill API via Away3D. You can find English equivalents from other sources easily]</p>
<h2>PHẦN 1. TIẾP CẬN MOLEHILL THÔNG QUA FLASH ENGINE AWAY3D</h2>
<table>
<thead>
<tr>
<th>Trình độ: Trung Cấp</th>
<th>Phần mềm</th>
<th>File mẫu</th>
</tr>
</thead>
<tbody>
<tr>
<td>- ActionScript 3<br>- Biết FlashDevelop<br>- Từng sử dụng Flash 3D engine</td>
<td>- Flash Develop 4 (<a href="http://www.flashdevelop.org/community/viewtopic.php?f=9&amp;t=3529">tải về</a>)<br>- Flex SDK 4.5 r.19786 (<a href="http://opensource.adobe.com/wiki/display%20/flexsdk/Download+Flex+Hero">tải về</a>)</td>
<td><a href="http://code.google.com/p/thanhtran-sources/downloads/detail?name=molehill_getting_start_p1.zip&amp;can=2&amp;q=">molehill_getting_start_p1.zip</a></td>
</tr>
</tbody>
</table>
<h3>I. Molehill và những câu hỏi thường gặp.</h3>
<h4>1. Molehill là gì?</h4>
<p>Molehill là tên mã của một tập lệnh (API) cấp thấp trong Flash Player cho phép tận dụng sức mạnh của chip đồ họa (GPU) để hiển thị hình ảnh 3D phức tạp và các hiệu ứng đồ họa đòi hỏi tốc độ xử lý cực nhanh, từ đó mang lại cho người dụng trải nghiệm 3D ấn tượng trên hầu hết các máy tính và thiết bị kết nối internet.</p>
<p>Dự kiến Molehill sẽ được phát hành chính thức trong Flash Player 11 và Adobe AIR phiên bản tiếp theo.</p>
<p><img src="https://lh3.googleusercontent.com/LQnSKUDCgdFvxt3iV7l2EzThIBd-KaPfahkZL_8SxcZzCc7D0cAeXDBf1DY-zOVnglT7uIce-UlHgEDsgFEzPrRCGuUQhAUk0rE7jVdJTF2cGiYt1J4" alt=""><em>Ảnh: Ứng dụng demo Max Racer viết bằng engine Alternativa 3D hỗ trợ Molehill.</em></p>
<p><a href="http://alternativaplatform.com/en/demos/maxracer/">Xem demo</a>.</p>
<h4>2. Những yêu cầu để Flash Player hoạt động với 3D:</h4>
<p>3D APIs của Flash Player đòi hỏi DirectX 9 trên Windows và OpenGL 1.3 trên MAC và Linux. Trên nền tảng di động, 3D API dựa trên OpenGL ES 2.0. Với những card đồ họa không được hỗ trợ, Flash Player sẽ thay thế bằng nền tảng software (cũng khá nhanh) tên là SwiftShader, một công nghệ của TransGaming.</p>
<h4>3. Điều này có nghĩa 3D API được giới thiệu trong Flash Player 10 sẽ ngưng hỗ trợ?</h4>
<p>Không, 3D APIs giới thiệu trong Flash Player 10 tiếp tục được cung cấp cho người thiết kế và lập trình viên như là một phương thức hiển thị hiệu ứng 3D đơn giản trên nội dung 2D. Còn tập lệnh 3D cấp thấp mới hướng đến những lập trình viên chuyên sâu giúp xây dựng những trải nghiệm đồ họa 3D phức tạp tăng tốc bằng phần cứng. Việc lựa chọn API nào sẽ phụ thuộc vào từng trường hợp cụ thể và loại nội dung được tạo.</p>
<h4>4. 3D Molehill có được hỗ trợ bởi phiên bản Flash Player cho di động? Nếu có thì khi nào?</h4>
<p>Có, 3D APIs sẽ có mặt trên các nền tảng di động chẳng hạn như Android hoặc điện thoại sử dụng Linux. Adobe đang làm việc với các đối tác trong dự án Open Screen Project để triển khai 3D trên các thiết bị chạy Flash Player và AIR.</p>
<h4>5. Lập trình viên sẽ viết ứng dụng 3D với Molehill như thế nào?</h4>
<p>3D API của Molehill là một tập lệnh cấp thấp nên rất khó sử dụng. Tuy nhiên đã có các ActionScript 3D framework giúp lập trình viên tiếp cận Molehill ở cấp cao và dễ dàng hơn. Sử dụng 3D framework là cách dễ nhất để lập trình viên hiện thực dự án sử dụng Molehill. Các 3D framework hứa hẹn sẽ hỗ trợ Molehill bao gồm: Alternativa3D, Away3d, CopperCube, Flare3D, Minko, Sophie3D or Yogurt3D…</p>
<p>Xem thêm các câu hỏi thường gặp và phần giới thiệu về Molehill tại đây: <a href="http://labs.adobe.com/technologies/flashplatformruntimes/incubator/features/molehill.html">http://labs.adobe.com/technologies/flashplatformruntimes/incubator/features/molehill.html</a></p>
<h3>II. Ứng dụng 3D Molehill đầu tiên với Away3D</h3>
<h4>1. Chuẩn bị môi trường làm việc với 3D Molehill:</h4>
<p>Vì 3D Molehill mới trong gian đoạn beta và còn rất mới, để biên dịch được ứng dụng sử dụng 3D API bạn cần làm một số bước chuẩn bị.</p>
<p>Sau đây là hướng dẫn chuẩn bị môi trường phát triển Molehill bằng FlashDevelop và FlexSDK đơn giản nhất theo ý kiến của tôi:</p>
<ol>
<li>
<p>Tải về và cài đặt FlashDevelop 4 (tại thời điểm viết bài chỉ mới có bản beta) <a href="http://www.flashdevelop.org/community/viewtopic.php?f=9&amp;t=3529">tại đây</a>. Với bản FlashDevelop beta, bạn nên cài dạng stand-alone. Trong lúc cài nhớ bỏ chọn tải về Flex SDK và AIR SDK. Chúng ta sẽ tải về bản Flex SDK beta mới nhất.</p>
</li>
<li>
<p>Tải về và giản nén bản FlexSDK 4.5 revision 19786 trở lên <a href="http://opensource.adobe.com/wiki/display%20/flexsdk/Download+Flex+Hero">tại đây</a>. (Giả sử bạn giải nén tại C:\flex_sdk_4.5.0.19786)</p>
</li>
<li>
<p>Tải về thư viện flashplayer_inc_playerglobal_022711.swc hỗ trợ Molehill API <a href="http://download.macromedia.com/pub/labs/flashplatformruntimes/incubator/flashplayer_inc_playerglobal_022711.swc">tại đây</a>.</p>
</li>
<li>
<p>Tạo thư mục 11.0 bên trong Flex SDK theo đường dẫn: “flex_sdk_4.5.0.19786\frameworks\libs\player\11.0”.
Sau đó chép file SWC vừa tải ở trên vào và đổi tên thành playerglobal.swc</p>
</li>
<li>
<p>Chạy FD4, vào Tools &gt; Program Settings… &gt; chọn AS3 Context &gt; nhấn nút […] tại mục Installed Flex SDKs &gt; Add &gt; Nhấn vào nút […] tại mục Path của Flex SDK vừa thêm &gt; tìm đến thư mục Flex SDK vừa tải về (C:\flex_sdk_4.5.0.19786) &gt; OK &gt; Close<img src="https://lh5.googleusercontent.com/kn6GuGF5VOTl7-z8HLTposfuhb91vsY1vUkeehs9gs5hk_OG_jHFoADWCptxiP4w0s5bhRfK75FPD7s5ns0jup0NiCg0LmLxmiSdApGZTHKC6xrrhHI" alt=""></p>
</li>
<li>
<p>Tạo một dự án mới với template Actionscript 3 - AS3 Project.</p>
</li>
<li>
<p>Vào project settings:</p>
</li>
<li>
<p>Tại Output &gt; Platform &gt; chọn Flash Player - 11.0.</p>
</li>
<li>
<p>Tại Compiler Options &gt; Additional Compiler Options &gt; thêm dòng: -swf-version=13</p>
</li>
<li>
<p>Chúng ta chỉ build mà không chạy ứng dụng trực tiếp trong FlashDevelop do chưa có Flash Player standalone hỗ trợ Molehill. Để chạy được flash Molehill, bạn cần tải về Flash Player 11 incubator chạy trên browser <a href="http://labs.adobe.com/downloads/flashplatformruntimes_incubator.html">tại đây</a>.</p>
</li>
</ol>
<p>Xem thêm bài viết sau để biết cách build Molehill bằng Flex SDK thuần túy hoặc Flash CS5:
<a href="http://labs.adobe.com/wiki/index.php/Flash_Player_Incubator#Authoring_for_Flash_Player_11.2C0.2C0.2C58_Incubator">http://labs.adobe.com/wiki/index.php/Flash_Player_Incubator#Authoring_for_Flash_Player_11.2C0.2C0.2C58_Incubator</a></p>
<h4>2. Viết ứng dụng Molehill đầu tiên với Away3D:</h4>
<ol>
<li>Tải về Away3D phiên bản hỗ trợ Molehill (4.0) <a href="http://away3d.com/downloads">tại đây</a>.</li>
<li>Giải nén và chép nội dung của thư mục src (thư mục away3d và com) vào thư mục lib của dự án FlashDevelop vừa tạo ở trên.</li>
<li>Vào project settings, thêm thư mục lib vào danh sách Classpaths.</li>
<li>Tạo một lớp mới tên <a href="http://AwayMolehillDemo.as">AwayMolehillDemo.as</a> và nhập nội dung của lớp như sau:</li>
</ol>
<pre class="language-actionscript"><code class="language-actionscript"><span class="token keyword">package</span>  <span class="token punctuation">{</span>
	<span class="token keyword">import</span> away3d<span class="token punctuation">.</span>containers<span class="token punctuation">.</span>Scene3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> away3d<span class="token punctuation">.</span>containers<span class="token punctuation">.</span>View3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> away3d<span class="token punctuation">.</span>entities<span class="token punctuation">.</span>Sprite3D<span class="token punctuation">;</span>
	<span class="token keyword">import</span> away3d<span class="token punctuation">.</span>lights<span class="token punctuation">.</span>PointLight<span class="token punctuation">;</span>
	<span class="token keyword">import</span> away3d<span class="token punctuation">.</span>materials<span class="token punctuation">.</span>ColorMaterial<span class="token punctuation">;</span>
	<span class="token keyword">import</span> away3d<span class="token punctuation">.</span>primitives<span class="token punctuation">.</span>Cube<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>display<span class="token punctuation">.</span>Sprite<span class="token punctuation">;</span>
	<span class="token keyword">import</span> flash<span class="token punctuation">.</span>events<span class="token punctuation">.</span>Event<span class="token punctuation">;</span>

	<span class="token comment">/**
			 - ...
			 - @author Thanh Tran
	 */</span>
	<span class="token punctuation">[</span><span class="token constant">SWF</span><span class="token punctuation">(</span>width<span class="token operator">=</span><span class="token string">"800"</span><span class="token punctuation">,</span>height<span class="token operator">=</span><span class="token string">"600"</span><span class="token punctuation">,</span>frameRate<span class="token operator">=</span><span class="token string">"60"</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
	<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AwayMolehillDemo</span> <span class="token keyword">extends</span> <span class="token class-name">Sprite</span> <span class="token punctuation">{</span>
		<span class="token keyword">public</span> <span class="token keyword">var</span> light1<span class="token punctuation">:</span> PointLight<span class="token punctuation">;</span>
		<span class="token keyword">public</span> <span class="token keyword">var</span> light2<span class="token punctuation">:</span> PointLight<span class="token punctuation">;</span>
		<span class="token keyword">public</span> <span class="token keyword">var</span> view3D<span class="token punctuation">:</span> View3D<span class="token punctuation">;</span>
		<span class="token keyword">public</span> <span class="token keyword">var</span> cube<span class="token punctuation">:</span> Cube<span class="token punctuation">;</span>

		<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">AwayMolehillDemo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>

		<span class="token keyword">private</span> <span class="token keyword">function</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token keyword">void</span> <span class="token punctuation">{</span>
			view3D <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">View3D</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token comment">//IMPORTANT</span>
			view3D<span class="token punctuation">.</span>width <span class="token operator">=</span> <span class="token number">800</span><span class="token punctuation">;</span>
			view3D<span class="token punctuation">.</span>height <span class="token operator">=</span> <span class="token number">600</span><span class="token punctuation">;</span>
			<span class="token function">addChild</span><span class="token punctuation">(</span>view3D<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token keyword">var</span> mat<span class="token punctuation">:</span> ColorMaterial <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ColorMaterial</span><span class="token punctuation">(</span><span class="token number">0x0000FF</span><span class="token punctuation">,</span> <span class="token number">0.7</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			cube <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Cube</span><span class="token punctuation">(</span>mat<span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

			light1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PointLight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			light1<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1000</span><span class="token punctuation">;</span>
			light1<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token number">1000</span><span class="token punctuation">;</span>
			light1<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1000</span><span class="token punctuation">;</span>
			light1<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token number">0xffFFFF</span><span class="token punctuation">;</span>

			light2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PointLight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			light2<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token number">1000</span><span class="token punctuation">;</span>
			light2<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1000</span><span class="token punctuation">;</span>
			light2<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token number">1000</span><span class="token punctuation">;</span>
			light2<span class="token punctuation">.</span>color <span class="token operator">=</span> <span class="token number">0xffFFFF</span><span class="token punctuation">;</span>

			mat<span class="token punctuation">.</span>lights <span class="token operator">=</span> <span class="token punctuation">[</span>light1<span class="token punctuation">,</span> light2<span class="token punctuation">]</span><span class="token punctuation">;</span>

			view3D<span class="token punctuation">.</span>scene<span class="token punctuation">.</span><span class="token function">addChild</span><span class="token punctuation">(</span>light1<span class="token punctuation">)</span><span class="token punctuation">;</span>
			view3D<span class="token punctuation">.</span>scene<span class="token punctuation">.</span><span class="token function">addChild</span><span class="token punctuation">(</span>light2<span class="token punctuation">)</span><span class="token punctuation">;</span>
			view3D<span class="token punctuation">.</span>scene<span class="token punctuation">.</span><span class="token function">addChild</span><span class="token punctuation">(</span>cube<span class="token punctuation">)</span><span class="token punctuation">;</span>

			<span class="token function">addEventListener</span><span class="token punctuation">(</span>Event<span class="token punctuation">.</span><span class="token constant">ENTER_FRAME</span><span class="token punctuation">,</span> enterFrameHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>

		<span class="token keyword">private</span> <span class="token keyword">function</span> <span class="token function">enterFrameHandler</span><span class="token punctuation">(</span>e<span class="token punctuation">:</span>Event<span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token keyword">void</span> <span class="token punctuation">{</span>
			cube<span class="token punctuation">.</span>rotationY <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>
			cube<span class="token punctuation">.</span>rotationX <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>
			view3D<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<ol start="5">
<li>Click chuột phải lên <a href="http://AwayMolehillDemo.as">AwayMolehillDemo.as</a> trên cửa sổ Project Manager, chọn Document Class</li>
<li>Nhấn F8 hoặc Project &gt; Build Project để biên dịch ứng dụng.</li>
<li>Mở file index.html bằng browser đã cài Flash Player Incubator.<img src="https://lh4.googleusercontent.com/k3WsIDA-bQtpJ18gqgTe-9ZHDKV9K_tUqk9EBmEntpzS_uMTiqSZxsQTCjJ6M3_i1RMTIQMm3Mb_9nTU4MN71aOLumFovBFhrOdvU0x1ahtuCJMmAUU" alt=""></li>
</ol>
<p>Bài viết này chúng ta dùng Flash engine để tạo hiệu ứng 3D Molehill nhanh chóng. Đây cũng là cách mà hầu hết lập trình viên sẽ tiếp cận khi làm việc trong dự án. Trong bài viết tiếp theo chúng ta sẽ xem xét Molehill 3D API ở cấp thấp để hiểu hơn bản chất và cách thức hoạt động của nó.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Playing with Wallaby</title>
    <link href="https://int3ractive.com/blog/2011/playing-with-wallaby/"/>
    <updated>2011-03-28T10:13:00Z</updated>
    <id>https://int3ractive.com/blog/2011/playing-with-wallaby/</id>
    <content type="html"><![CDATA[
      
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-0y5JE-36S_s/TZBNWB_Q9rI/AAAAAAAADL8/JdEx672-jX0/s1600/Wallaby_demo2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://1.bp.blogspot.com/-0y5JE-36S_s/TZBNWB_Q9rI/AAAAAAAADL8/JdEx672-jX0/s320/Wallaby_demo2.png" target="_blank" width="308" /></a></div>
This is my attempt to convert an old Flash animation (my old animated signature when I was young ;) ) &nbsp;to HTML5 using&nbsp;<a href="http://labs.adobe.com/technologies/wallaby/">Adobe's Wallaby tool</a>.<br />
<br />
Because of the nature of this animation, a lot of SVG files were generated. The total size of the HTML5 animation is 1.1MB compared to 21.6KB of the Flash counterpart. (OMG, way to much less efficient).&nbsp;I had to edit some JavaScript to add a preloader for it. Another side note is that Wallaby only works with Flash CS5's fla. (The tool failed to open my old animation in CS3 format).<br />
<a name='more'></a><br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">
-&nbsp;<a href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/WallabyDemos/DrawingLogo/logo.html" target="_blank">The converted HTML5 animation</a>&nbsp;(only work with Webkit browser for now)</div>
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">
-&nbsp;<a href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/WallabyDemos/DrawingLogo/logo_flash.html" target="_blank">The original Flash animation</a><br />
- (<a href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/WallabyDemos/DrawingLogo.zip" target="_blank">Fla &amp; html source</a>)<br />
<br /></div>
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">
As you may notice, the 2 animations are not 100% identical as there are still some limitations with the tool. You should read the&nbsp;<a href="http://labs.adobe.com/wiki/index.php/Wallaby#Release_Notes" target="_blank">release note</a>&nbsp;to be aware of them and may adjust your animation for best conversion.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/--tLGshRq7gU/TZBMjWc1kKI/AAAAAAAADL4/gCXlJZZDzmM/s1600/Wallaby_demo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" height="290" src="https://3.bp.blogspot.com/--tLGshRq7gU/TZBMjWc1kKI/AAAAAAAADL4/gCXlJZZDzmM/s400/Wallaby_demo.png" width="400" /></a></div>
My thought about Wallaby:<br />
<ul>
<li>Flash designer can use existing skills and tools to create animations for HTML5.</li>
<li>If we just look from HTML5 aspect, Wallaby + Flash CS5 is similar to <a href="http://www.sencha.com/products/animator/">Sencha Animator</a> which allow us to create HTML5/CSS3 animation on timeline visually.</li>
<li>As it doesn't&nbsp;currently&nbsp;support ActionScript 1/2/3, it is quite useless for developers to get any quick porting of Flash applications to HTML5.</li>
<li>Wallaby's current use cases: ad banners, intro animations, animated assets for HTML/Javascript apps</li>
</ul>
Update 2011-04-01: Wallaby can be installed and used in Linux via Wine (Windows version). You need to install winetricks&nbsp;vcrun2008.<br />
<ul>
</ul>
<span class="Apple-style-span" style="font-size: xx-small;">[Vietnamese tag: Thử nghiệm với Wallaby]</span>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>AS3 Wordle Tag Cloud</title>
    <link href="https://int3ractive.com/blog/2011/as3-wordle-tag-cloud/"/>
    <updated>2011-02-22T12:15:00Z</updated>
    <id>https://int3ractive.com/blog/2011/as3-wordle-tag-cloud/</id>
    <content type="html"><![CDATA[
      
<p style="text-align: center"><a title="AS3 Wordle Tag Cloud" href="https://raw.github.com/trongthanh/ttt-sources/master/demos/flash/wordle-tag-cloud/bin/WordleTagCloud.swf" target="_blank" rel="noopener shadowbox[WordleTagCloudClosedSource1];width=1024;height=768"><img title="Wordle Tag Cloud" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TWOo44tDQoI/AAAAAAAADKs/lrMlP-mhZ38/demo%5B20%5D.png?imgmax=800" alt="Wordle Tag Cloud" width="420" height="423" border="0" /></a></p>
<p>You should have seen the aesthetic tag cloud above somewhere on the web. It originates from the famous <a href="http://www.wordle.net/" target="_blank" rel="noopener">Wordle words cloud</a> (closed source). For the past few days, I have ported an open source Java class to ActionScript and able to render the tag cloud in Flash as seen above. Please refer to <a href="http://plindenbaum.blogspot.com/2010/10/playing-with-worldle-algorithm-tag.html" target="_blank" rel="noopener">this article</a> to have the Java author explain the basic of the algorithm. (Thank Pierre Lindenbaum for the nice implementation)</p>

<p>For my AS3 port, I&rsquo;ll leave the source code explain itself (mentioned below); but I can commend that Flash is very suitable for such visual tasks as it has built-in classes for drawing and object positioning. Some notable works for the Flash adaptation are:</p>
<ul>
<li>Checking for closely-fit bounds of the text on TextField (simple getBounds() will leave you some unwanted padding around the TextField object).<img title="Perfect bounds are drawn to see how they fit closely" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TWRu-qzN3vI/AAAAAAAADKw/gT3mu11okj8/perfect_bounds%5B6%5D.png?imgmax=800" alt="Perfect bounds are drawn to see how they fit closely" width="185" height="127" border="0" /><br />I would like to thank Thu Hoang, my dear colleague, who helped fixing this perfect bounds implementation.</li>
<li>Deploy some <a href="http://troygilbert.com/2007/06/pixel-perfect-collision-detection-in-actionscript3/" target="_blank" rel="noopener">pixel perfect collision detection approaches</a> and try them. However the result is extremely slow and somehow inaccurate. I leave this for later improvement.</li>
<li>As the process of collision testing and word placing cost a lot of CPU power, the Flash application usually hang for several seconds when rendering the tag cloud. To prevent this, I have split the process into multiple ENTER_FRAME events in order to eliminate the hang and resulted in a word-appearing animation.</li>
<li>The class doesn&rsquo;t care about scaling to fit the viewport yet. I intend to take care of that later.</li>
</ul>
<p><a title="AS3 Wordle Tag Cloud" href="https://raw.github.com/trongthanh/ttt-sources/master/demos/flash/wordle-tag-cloud/bin/WordleTagCloud.swf" target="_blank" rel="noopener shadowbox[WordleTagCloudClosedSource2];width=1024;height=768">Check out the demo here</a>.<br /> I would like to open source the whole project but that is not possible because I have spent some of my company time doing the porting (It also come from a request of a commercial project). But I&rsquo;m pleased to share the basic porting of the Java class which you can <a title="Source on Google Code" href="http://code.google.com/p/thanhtran-sources/source/browse/#svn%2Ftrunk%2Fdemos%2FWordleTagCloud" target="_blank" rel="noopener">view it here</a> (or <a href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/WordleTagCloud" target="_blank" rel="noopener">check out the SVN here</a>)<br /> The open source <a href="http://code.google.com/p/thanhtran-sources/source/browse/trunk/demos/WordleTagCloud/src/com/pyco/tagcloud/Wordle.as" target="_blank" rel="noopener">Wordle</a> tag cloud is the basic porting of the Java class which still run on single loop (no animation and still hang). But to split the process into multiple frames is simple OR you can deploy a pseudo-threading library. There are plenty of rooms for you to improve. (See the <a href="https://raw.github.com/trongthanh/ttt-sources/master/demos/flash/wordle-tag-cloud/bin/WordleTagCloud_OpenSource.swf" target="_blank" rel="noopener">open source demo here</a>.)<br /> There is a native AS3 implementation as you can <a href="http://www.leichtgewicht.at/436/road-to-tag-cloud-2/" target="_blank" rel="noopener">find here</a>. I found the vertical/horizontal case of this implementation doesn&rsquo;t look very good (and my request doesn&rsquo;t care about free angle) so I decided to go with this Java class.<br /> On a side note, when testing the single loop demo, I realized that the Flash Player on Linux (~2000ms) runs approximately 4 times slower than the Windows&rsquo; counter part (~500ms). Holy cow!<br /><br /><strong>Updated 2013-04-04:</strong> I have uploaded this demo on Github sometimes ago. Please visit the&nbsp;<a href="https://github.com/trongthanh/ttt-sources/tree/master/demos/flash/wordle-tag-cloud" target="_blank" rel="noopener">Github repo</a>. In this repo, I have also committed the part that was closed: multi-frame calculation (to avoid blocking script). However, this part remains closed source. You can read it for inspiration only. If you want to use the closed part (Main.as, WordleAS3.as), please seek permission from my ex-employer (noted as copyright holder in the source).<br />[Vietnamese tag: Đ&aacute;m m&acirc;y tag Wordle viết bằng ActionScript 3]</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Flash on multiple screen demo</title>
    <link href="https://int3ractive.com/blog/2011/flash-on-multiple-screen-demo/"/>
    <updated>2011-02-15T06:18:00Z</updated>
    <id>https://int3ractive.com/blog/2011/flash-on-multiple-screen-demo/</id>
    <content type="html"><![CDATA[
      
<p>2011 undoubtedly expects the multiple screen applications trend. Flash platform is one of the best solutions to deliver same experience across multiple devices and platforms. Here is a demo of Flash-based games on multiple (device) screens: PC, iPhone, iPad, Android phone (Motorola Milestone 2), Android tablet (Samsung Galaxy Tab).</p>  <p>All the coding effort is credited to my Flash team. The iOS applications were created by using Flash CS5’s iPhone Packager. I repackaged the Flash builds to AIR for Android using Flex SDK Hero. Some of the applications are not complete and/or Android-optimized yet.</p>  <p><iframe title="YouTube video player" height="390" src="http://www.youtube.com/embed/AN5BgrDOY58" frameborder="0" width="640" allowfullscreen="allowfullscreen"></iframe></p>  <p>FYI, the video was created with <a href="http://cinelerra.org/" target="_blank">Cinelerra</a>, the most advanced non-linear video editor and compositor for Linux. (Quite close to Adobe Premiere, and require some learning curve)</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Tips on encoding videos for Android using Adobe Media Encoder</title>
    <link href="https://int3ractive.com/blog/2011/tips-on-encoding-videos-for-android/"/>
    <updated>2011-01-12T04:45:00Z</updated>
    <id>https://int3ractive.com/blog/2011/tips-on-encoding-videos-for-android/</id>
    <content type="html"><![CDATA[
      
<p>As a Flash Professional user, you probably have Adobe Media Encoder installed on your computer. This is a great tool to encode videos not only for Flash video player but also for other H.264-enabled devices like iPhone and Android. However, when I tried to encode a video using a random H.264 preset, my phone (a Milestone 2) could not play the video. This means that not every export settings is compatible with the phone’s internal video encoder.</p> <p>So which preset should we choose for the export settings?</p><a name='more'></a> <p>I suggest you start with a preset for mobile such as <em>“Apple iPod, iPhone (Widescreen) Video”</em> (assuming Adobe Media Encoder CS5). For a Motorola phone like mine which has higher screen resolution than said preset I have successfully encoded my video with <em>“YouTube Widescreen SD”</em> for a better quality video. From these presets, you can tweak the settings a little bit to perfectly match your phone’s screen. Typically, you can set size and bitrate of the video and leave other settings alone.</p> <p>I found these settings are perfect for my Motorola Android phone (854x480):</p> <ul> <li>Format: H.264  <li>Preset: YouTube Widescreen SD  <li>Frame Width: 854 (or leave it as 640)  <li>Frame Height: 480 (or leave it as 360)  <li>Target Bitrate: 1  <li>Maximum Bitrate: 2</li></ul> <p>Of course my source video has aspect ratio of 16x9. Otherwise, I would select a similar preset for 4x3 videos. You can try other presets at your own risk.</p> <p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="media encoder" border="0" alt="media encoder" src="https://lh3.ggpht.com/_47w2iQ8-NcE/TS0x5LahEsI/AAAAAAAACs8/KVy_i362AS8/media%20encoder%5B7%5D.png?imgmax=800" width="644" height="471"> </p> <p></p> <p><font size="1">[Vietnamese tag: Vài lưu ý khi tạo video cho điện thoại Android với chương trình Adobe Media Encoder]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project Snow Fight</title>
    <link href="https://int3ractive.com/blog/2010/project-snow-fight/"/>
    <updated>2010-12-25T08:32:00Z</updated>
    <id>https://int3ractive.com/blog/2010/project-snow-fight/</id>
    <content type="html"><![CDATA[
      
<a href="https://lh3.ggpht.com/_47w2iQ8-NcE/TVjptqr0KTI/AAAAAAAADJk/aaU1rrFd6Vk/s1600-h/snowfight_3%5B1%5D.jpg" target="_blank"><img alt="Snow Fight Game" border="0" height="304" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TVjpuQ66qWI/AAAAAAAADJs/b2M6eIaUTYY/snowfight_3_thumb.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="Snow Fight Game" width="404" /></a> <br />
Another internal case-study project of Pyco Flash team to research multiplayer game with Red5. This is a 2D top-view real-time shooting game whose gameplay is similar to <a href="http://www.cs2d.com/" target="_blank">CS2D</a> – you control your character moving round with WASD keys and aim and shoot with your mouse. The game showcases real-time synchronization among clients in a precision and fast-pace environment. The team have learnt a lot from the book <a href="http://www.amazon.com/ActionScript-Multiplayer-Games-Virtual-Worlds/dp/0321643364" target="_blank">ActionScript for Multiplayer Games and Virtual Worlds</a> and apply what we learnt successfully to this game.<br />
I designed and proposed the game concept and detailed requirements. I also joint to develop the character control and foundation of client-server synchronization.<br />
My roles: system designer, technical supporter<br />
Tech notes:<br />
<ul>
<li><a href="http://blog.int3ractive.com/2009/12/pyco-flash-framework-beta.html">Pyco Flash Framework</a> – based on PureMVC </li>
<li><a href="http://red5.org/">Red5 </a></li>
<li>TweenMax </li>
<li>Realtime multiplayer synchronization </li>
</ul>
<a href="http://int3ractive.com/casestudies/snowfight/">Click here</a> to try the game. (Because this is a multi-player game, make sure you invite your friends to join).<br />
<a href="https://lh4.ggpht.com/_47w2iQ8-NcE/TVjpvA6HrVI/AAAAAAAADJ0/_r2_6VQYw_c/s1600-h/snowfight_1%5B2%5D.jpg" target="_blank"><img alt="Login screen" border="0" height="184" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TVjpvggr-1I/AAAAAAAADJ8/Y5vUd8ylJD0/snowfight_1_thumb%5B2%5D.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="Login screen" width="244" /></a>&nbsp;<a href="https://lh5.ggpht.com/_47w2iQ8-NcE/TVjpxRPTY1I/AAAAAAAADKE/PJv9A9sQ_kg/s1600-h/snowfight_2%5B2%5D.jpg" target="_blank"><img alt="Battle room screen" border="0" height="184" src="https://lh3.ggpht.com/_47w2iQ8-NcE/TVjp0QCF3YI/AAAAAAAADKI/1oOWmr-7I6w/snowfight_2_thumb%5B2%5D.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="Battle room screen" width="244" /></a> <a href="https://lh5.ggpht.com/_47w2iQ8-NcE/TVjp0xYhePI/AAAAAAAADKU/gHDT0sas3VE/s1600-h/snowfight_4%5B1%5D.jpg" target="_blank"><img alt="Game over screen" border="0" height="184" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TVjp1u-DMMI/AAAAAAAADKY/bQhGCanq_6c/snowfight_4_thumb%5B1%5D.jpg?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="Game over screen" width="244" /></a>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Flash Camp Hanoi 2010</title>
    <link href="https://int3ractive.com/blog/2010/flash-camp-hanoi-2010/"/>
    <updated>2010-12-05T02:30:00Z</updated>
    <id>https://int3ractive.com/blog/2010/flash-camp-hanoi-2010/</id>
    <content type="html"><![CDATA[
      
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://3.bp.blogspot.com/-F2GGLRVdMYA/T-ppllZtaaI/AAAAAAAAExc/7jNxTVB8Exk/s1600/people.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="232" src="https://3.bp.blogspot.com/-F2GGLRVdMYA/T-ppllZtaaI/AAAAAAAAExc/7jNxTVB8Exk/s400/people.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The young and energetic people</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: left;">
<span style="background-color: white;">It was great honor for me to be invited to the first Flash conference in Viet Nam, Flash Camp Hanoi 2010. The event is a proving fact that Flash/Flex users community in Viet Nam has grown up and stronger than ever. All details and stories can be found at the official website: </span><span style="background-color: white;"><a href="http://flashcamphanoi.com.vn/">flashcamphanoi.com.vn</a>&nbsp;</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="background-color: white;">(Update: the server is temporarily down, please access the overview article on <a href="http://groups.adobe.com/index.cfm?event=post.display&amp;postid=38121" target="_blank">groups.adobe.com</a>&nbsp;or view the event photos on <a href="https://www.facebook.com/flashcamphanoi/photos" target="_blank">FCH Facebook page</a>)</span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://3.bp.blogspot.com/-jEzsKJ0qq-A/T-ppaC9rtYI/AAAAAAAAExU/qu3gbbWFz0g/s1600/presentation.jpg" imageanchor="1" style="background-color: white; margin-left: auto; margin-right: auto;"><img border="0" height="300" src="https://3.bp.blogspot.com/-jEzsKJ0qq-A/T-ppaC9rtYI/AAAAAAAAExU/qu3gbbWFz0g/s400/presentation.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Me on stage</td></tr>
</tbody></table>
<span style="text-align: left;">I brought to the event the presentation about&nbsp;</span><a href="http://www.libspark.org/wiki/saqoosha/FLARToolKit/en" style="text-align: left;" target="_blank">FLARToolKit</a><span style="text-align: left;">&nbsp;and augmented reality in Flash. The slide deck (with links to online demos) has been uploaded by the organizer on&nbsp;</span><a href="http://www.slideshare.net/danghuongtra/augmented-reality-inflashtrantrongthanh" style="text-align: left;" target="_blank">slideshare.net</a><span style="text-align: left;">.</span>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Presentation: Introduction to TDD &amp; FlexUnit</title>
    <link href="https://int3ractive.com/blog/2010/presentation-introduction-to-tdd/"/>
    <updated>2010-10-08T10:42:00Z</updated>
    <id>https://int3ractive.com/blog/2010/presentation-introduction-to-tdd/</id>
    <content type="html"><![CDATA[
      
<p>This is a summary of what I studied and practiced with TDD &amp; FlexUnit. This presentation is not for persuading developers applying unit testing but it will highlight benefits &amp; vulnerabilities of TDD objectively.</p> <p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" width="425" height="370" id="onlinePlayer"><param name="movie" value="http://www.slideboom.com/player/player.swf?id_resource=218588" /><param name="allowScriptAccess" value="always" /><param name="quality" value="high" /><param name="bgcolor" value="#ffffff" /><param name="allowFullScreen" value="true" /><param name="flashVars" value="" /><embed src="http://www.slideboom.com/player/player.swf?id_resource=218588" width="425" height="370" name="onlinePlayer" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" allowScriptAccess="always" quality="high" bgcolor="#ffffff" allowFullScreen="true" flashVars=""></embed></object></p> <p><font size="1">[Vietnamese tag: Bài thuyết trình về FlexUnit và mô hình phát triển phần mềm dựa trên kiểm thử / kiểm tra]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Using Flash Builder 4 on Ubuntu</title>
    <link href="https://int3ractive.com/blog/2010/using-flash-builder-4-on-ubuntu/"/>
    <updated>2010-10-02T13:27:00Z</updated>
    <id>https://int3ractive.com/blog/2010/using-flash-builder-4-on-ubuntu/</id>
    <content type="html"><![CDATA[
      
<p align="center"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Flash Builder 4 splash screen on my Ubuntu" border="0" alt="Flash Builder 4 splash screen on my Ubuntu" src="https://lh3.ggpht.com/_47w2iQ8-NcE/TKcy-OSjfCI/AAAAAAAACqI/gwpPT2nLcpY/fb_001_splash%5B8%5D.png?imgmax=800" width="554" height="329" /></p>  <p>So, Adobe has <a href="http://blogs.adobe.com/flex/2010/09/flex-builder-for-linux-project-ending.html" target="_blank">discontinued its Linux version</a> of Flex Builder. That’s sad news for us. Anyway, it doesn’t change much since Linux users already have alternatives long before, e.g. <a href="http://fdt.powerflasher.com/" target="_blank">FDT</a>, <a href="http://www.jetbrains.com/idea/" target="_blank">IDEA</a>. Besides, I have been able to run Flash Builder 4 on my Ubuntu (via Wine) for a while to take advantage of its mxml coding hinting and the unique design view. Let me share some of my experiences of using Flash Builer on Ubuntu so far.</p>

<a name='more'></a>  <h3>Installation</h3>  <p>Some users (<a href="http://appdb.winehq.org/objectManager.php?sClass=version&amp;iId=16795&amp;iTestingId=41068" target="_blank">here</a> and <a href="http://diariolinux.com/2009/06/22/how-to-install-flash-builder-on-linux/" target="_blank">here</a>) said that they could install Flash Builder 4 (FB4) with Wine. However, that is dated back to the beta version of FB4. I have tried many times with different winetricks to install the released version of FB4 but didn’t succeed. So I have no choice but install it on my Windows virtual machine and copy the installed files to Ubuntu’s wineprefix.</p>  <p>This process is similar to what was described in my previous blog post about <a href="http://int3ractive.blogspot.com/2010/08/how-to-run-flash-cs5-on-ubuntu-with.html" target="_blank">making Flash CS5 (and Photoshop CS5) running on Ubuntu</a>, except the winetricks part should be as following:</p>  <p><font face="Courier New">~$ winetricks msxml3 vcrun2008 usp10 comctl32 ie6</font></p>  <p>FYI, to my findings, <em>usp10</em> is for the source editor to work correctly (especially with unicode texts); <em>comctl32</em> will corrects some win controls and the code hinting popup;and <em>ie6</em> lets the tooltip display ASdoc help correctly.</p>  <p><a href="https://lh4.ggpht.com/_47w2iQ8-NcE/TKczAX7PqlI/AAAAAAAACqw/q4ocpEogfs8/s1600-h/fb_003_design_view%5B8%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="design view" border="0" alt="design view" src="https://lh3.ggpht.com/_47w2iQ8-NcE/TKczBWPqLbI/AAAAAAAACq4/UVcbQhLuXuo/fb_003_design_view_thumb%5B4%5D.png?imgmax=800" width="404" height="325" /></a>     <br /><font size="2">(Proof of concept: Flash Builder running on default Ubuntu 10.4 desktop)</font>     <br /></p>  <h3>Start up</h3>  <p>Very often, you will face this error box when starting FB.    <br /><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="memory error" border="0" alt="memory error" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TKczCQYlksI/AAAAAAAACqU/MqeNPzc8cqM/fb_005_memory_error%5B7%5D.png?imgmax=800" width="254" height="230" />     <br />Starting it from command line you will find this message:     <br /><font face="Courier New">Error occurred during initialization of VM      <br />Could not reserve enough space for object heap</font></p>  <p>Don’t worry, try running the application again. You’ll finally have it started (usually after 2 - 3 attempts). </p>  <p>Passing above blocking error, another error message box will appear (all the time, just like with Flash CS5) but just close it and the initialization carry on. You will also notice a long delay before the Splash screen appear.</p>  <h3>Code hinting popup issue</h3>  <p>When you type, the code hinting popup may appear but doesn’t respond and you cannot input until the popup is closed. It is because Ubuntu’s windows manager is interfering. To resolve, for now, run the wine config (Application &gt; Wine &gt; Configure Wine OR enter this command in terminal: <font face="Courier New">winecfg</font>) &gt; open tab Graphics &gt; uncheck ‘Allow the window manager to control the windows’.</p>  <p><a href="https://lh4.ggpht.com/_47w2iQ8-NcE/TKczEl1qlTI/AAAAAAAACrA/eJZ31_ZDQhY/s1600-h/fb_002_source_view%5B5%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="source view" border="0" alt="source view" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TKczHJ_yDUI/AAAAAAAACrM/a3TpgbpzzAE/fb_002_source_view_thumb%5B3%5D.png?imgmax=800" width="404" height="340" /></a> </p>  <p>Now the source editor will work as expected. However, there is some downside: the option Allow the window manager to decorate the windows will not be effective anymore. Besides you will not be able to minimize Flash Builder to GNOME panel. It only minimizes to a small icon floating on the desktop. And there appear to be some glitches with text input focus.</p>  <h3>Compile and debug</h3>  <p>No extra Java Runtime is needed to compile with FB4. The FB4 has a bundled JRE &amp; Flex SDK that will help you check compile-time errors and compile the project as you type.</p>  <p>For the test run, you can install Flash Player activeX debugger for IE6 in Wine to test the application. However, I have discovered a better way: running it directly on your Linux-native browser and still able to debug. How cool is that? Here’s how:</p>  <ol>   <li>Open gedit and enter the following text:      <br /><font face="Courier New">&#160;&#160; #!/bin/sh        <br />&#160;&#160; firefox -url &quot;`wine winepath -u &quot;$1&quot;`&quot;</font>       <br />What this shell script does is to: open the native Firefox browser with the URL which has been converted from Windows path to Linux path by using ‘wine winepath’ command.       <br />If you prefer Chromium browser, use this command instead:       <br /><font face="Courier New">&#160;&#160; chromium-browser &quot;`wine winepath -u &quot;$1&quot;`&quot;</font> </li>    <li>Name the file as “<font face="Courier New">lnx_browser</font>” and save it to an easy access folder. (Here I choose <font face="Courier New">/home/username/lnx_browser</font>). Remember to allow it execute as program. </li>    <li>In FB, navigate to Window &gt; Preferences &gt; General &gt; Web Browser. </li>    <li>Select “Use external web browser” </li>    <li>Click New, input new browser settings as following:      <br />Name: <strong>Linux Browser</strong>       <br />Location: <strong>/home/username/lnx_browser</strong> (Must be Linux path, do not use Z:\home…)       <br />Parameters: <strong>%URL% </strong></li>    <li>OK and then select Linux Browser as your chosen external browser. </li> </ol>  <p><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/TKczJOoNTZI/AAAAAAAACrQ/sBSPyQSqUZQ/s1600-h/fb_006_linux_browser%5B4%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="new linux browser" border="0" alt="new linux browser" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TKczKXxJIiI/AAAAAAAACrY/12RR-vguuRU/fb_006_linux_browser_thumb%5B2%5D.png?imgmax=800" width="404" height="289" /></a></p>  <p>After setting up external browser, go ahead and run/debug your application. FB4 will show a warning message about not finding Flash Player. Just ignore and click yes. Your application will run on Firefox Linux!</p>  <p><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/TKczNTY8o1I/AAAAAAAACrs/T9dj5DN87MI/s1600-h/fb_004_debugging%5B4%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="debugging" border="0" alt="debugging" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TKczP07rLpI/AAAAAAAACr4/Q67HAwj6YUM/fb_004_debugging_thumb%5B2%5D.png?imgmax=800" width="404" height="340" /></a></p>  <p>For testing AIR applications, I just let FB4 use the Windows adl.exe debug loader (no native solution yet). It is fine to test functionality of simple windows. When it uses system tray or something complicated, you can write ANT task of shell script to run the app with native adl.</p>  <h3>Isolate FB4 wineprefix</h3>  <p>With said configurations and winetricks tweaking, it is very likely that they may affect other installed applications in Wine. I have come across one noticeable case: after setting up for FB4, Photoshop CS5 fails to start due to a conflict with the additional <em>comctl32</em> library. So, my advice is to isolate FB in a separate wineprefix (default is .wine).</p>  <p>To create a&#160; separate wineprefix use this command (assume you want it to be .winefb):</p>  <p><font face="Courier New">~$ env WINEPREFIX=&quot;/home/username/.winefb&quot; winecfg</font></p>  <p>That command is actually to open wine config window, since wineprefix doesn’t exist, Wine will create a new one in that folder.</p>  <p>After that, prepend <font face="Courier New">env WINEPREFIX=&quot;/home/username/.winefb&quot;</font> before every wine command, for example:</p>  <ul>   <li>Winetricks:      <br /><font face="Courier New">~$ env WINEPREFIX=&quot;/home/username/.winefb&quot; winetricks msxml3 vcrun2008 usp10 comctl32 ie6</font> </li>    <li>Start wine config:      <br /><font face="Courier New">~$ env WINEPREFIX=&quot;/home/username/.winefb&quot; winecfg</font> </li>    <li>Start up FB:      <br /><font face="Courier New">~$ env WINEPREFIX=&quot;/home/username/.winefb&quot; wine &quot;C:\Program Files\Adobe\Adobe Flash Builder 4\FlashBuilder.exe&quot;</font> </li> </ul>  <h3>Summary</h3>  <p>Here’s my summary in the style of Wine’s AppDB report for your reference:</p>  <h4>What works:</h4>  <p>Almost all functions</p>  <ul>   <li>Source view </li>    <li>Design view </li>    <li>Launching / debugging (with above tweaking) </li>    <li>Export release builds </li>    <li>New project/class wizard </li>    <li>All panels: Package Explorer, Outline, Components, Problems, Console, ASDoc, Network monitor, Properties, Styles… </li> </ul>  <h4>What does not work:</h4>  <ul>   <li>Create new folder in New / Import Project wizard </li> </ul>  <h4>What was not tested:</h4>  <ul>   <li>Profiler </li>    <li>Unit testing (but I guess it will work) </li>    <li>Data/Services </li> </ul>  <p><font size="1">[Vietnamese tag: sử dụng Flash Builder 4 trên Ubuntu, hướng dẫn cài đặt, khắc phục lỗi code hint, biên dịch và debug]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Quick AS3 Language Reference Search with Google Chrome’s custom search engine</title>
    <link href="https://int3ractive.com/blog/2010/quick-as3-language-reference-search/"/>
    <updated>2010-09-13T07:19:00Z</updated>
    <id>https://int3ractive.com/blog/2010/quick-as3-language-reference-search/</id>
    <content type="html"><![CDATA[
      
<p><a title="Online AS3 language reference" href="http://www.adobe.com/livedocs/flash/9.0/actionscriptlangrefv3/" target="_blank">ActionScript 3 language reference</a> document is any Flash developer’s bible. Whenever you implement something with Flash, you’ll find yourself checking this document regularly. There are plenty of ways to access this document:</p>

<ol> <li>Open Flash CS* and press F1 to open it’s internal help panel. (Some of my friends do this even when they don’t have any fla to edit).  <li>In FlashDevelop, place the caret on a Flash built-in class name and press F1. FD will open the default browser with Google search results within AS3 language reference’s site. (This requires you to open FlashDevelop anyway).  <li>Bookmark this site: <a href="http://www.adobe.com/livedocs/flash/9.0/actionscriptlangrefv3/">http://www.adobe.com/livedocs/flash/9.0/actionscriptlangrefv3/</a> (Flash Player 9 AS3 &amp; Flash CS3 components) or this: <a title="http://help.adobe.com/en_US/AS3LCR/Flash_10.0/" href="http://help.adobe.com/en_US/AS3LCR/Flash_10.0/">http://help.adobe.com/en_US/AS3LCR/Flash_10.0/</a> (Flash Player 10 AS3 &amp; Flash CS4 components) and open it with your favorite browser. Then you’ll need to browse through the classes list.  <li>Download this <a href="http://help.adobe.com/support/documentation/en/flash/10/ActionScript3LangRef.zip" target="_blank">offline FlashCS4 help document</a> and open the index.html file locally with your favorite browser. You’ll also need to browse through the classes list.<br>You can also bookmark this local document for quick access.</li></ol> <p>Now, if you’re using <a href="www.google.com/chrome" target="_blank">Google Chrome</a>, let me propose another way not only help access the online document quickly but also allow to search for a specific term or class with lightning speed!</p><a name='more'></a> <h4>Setting up:</h4> <ul> <li>Right-click on Google Chrome’s address bar and select Edit Search Engines…<br><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Search Engines_001" border="0" alt="Search Engines_001" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TI3QcvNNhyI/AAAAAAAACp0/hS5lgXq_fw0/Search%20Engines_001%5B6%5D.png?imgmax=800" width="601" height="411">  <li>Click Add… to open custom search engine editor  <li>Input:<br>- Name: <strong>ActionScript 3 Reference</strong> (or a name of your choice)<br>- Keywork: <strong>as3</strong> (or keyword of your choice; the shorter, the better)<br>- URL: <strong>http://www.google.com/search?q=%s+site:http://www.adobe.com/livedocs/flash/9.0/actionscriptlangrefv3/<br></strong>OR: <strong>http://www.google.com/search?q=%s+site:http://help.adobe.com/en_US/AS3LCR/Flash_10.0/<br></strong>(I think you get the idea. This is custom search for specified site after “site:”)<br><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Edit Search Engine_002" border="0" alt="Edit Search Engine_002" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TI3QdSdZ8iI/AAAAAAAACp4/6umaaBTFWAY/Edit%20Search%20Engine_002%5B7%5D.png?imgmax=800" width="394" height="225">  <li>And then Save this new custom search engine.</li></ul> <h4>To use:</h4> <ul> <li>Press F6 or Ctrl-L to focus on the address bar  <li>Type ‘as3’ (or the short keyword you chose)<br><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Selection_003" border="0" alt="Selection_003" src="https://lh3.ggpht.com/_47w2iQ8-NcE/TI3QebGUuLI/AAAAAAAACp8/OR-5_xooXBA/Selection_003%5B4%5D.png?imgmax=800" width="578" height="36">  <li>Press Tab  <li>Type the term or class you want to look up<br><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Selection_005" border="0" alt="Selection_005" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TI3QfLSGnNI/AAAAAAAACqA/JJ8qTsUlQE4/Selection_005%5B4%5D.png?imgmax=800" width="578" height="37">  <li>Enter  <li>Your searched results appear instantly.<br><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Selection_006" border="0" alt="Selection_006" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TI3QiOJyhVI/AAAAAAAACqE/fCLXdRJ41es/Selection_006%5B8%5D.png?imgmax=800" width="504" height="344"> </li></ul> <p>You may argue that this method is similar to FlashDevelop’s F1. Yes, it is. But consider these advantages:</p> <ul> <li>You don’t need to open FD (especially if you’re working on Linux)  <li>You search the term, not just slowly browsing for it.  <li>And you are searching with Google engine with lightning speed.  <li>Bookmarking the site only let you open it quickly and still browse through long list of classes. Besides, the provided search form in the site is way slower than Google’s.</li></ul> <p>The disadvantage is Google must index the whole site in order for you to search for the term/class effectively. I intended to propose Adobe’s latest Flash Platform documentation site at: <a title="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/" href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/">http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/</a> but the site is so new and not all the pages are indexed by Google yet. (You may switch to this site later when the indexing completes to access latest documentation.)</p> <p><strong>Updated 2010-09-20</strong>: You can just type the keyword, then space, then search term to search with specified custom engine. Your keyword should be unique.</p> <p><font size="1">[Vietnamese tag: Truy cập nhanh tài liệu tham khảo ActionScript với Google Chrome; tùy biến tìm chức năng tìm kiếm trong Google Chrome]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Announcing as3-karaoke-player, my first open library</title>
    <link href="https://int3ractive.com/blog/2010/announcing-as3-karaoke-player-my-first/"/>
    <updated>2010-08-28T06:44:00Z</updated>
    <id>https://int3ractive.com/blog/2010/announcing-as3-karaoke-player-my-first/</id>
    <content type="html"><![CDATA[
      
<p>Today I’m very excited to announce my first open source library: <strong><a href="http://code.google.com/p/as3-karaoke-player/" target="_blank">as3-karaoke-player</a></strong>. It comes from a request to make a small karaoke website. The idea is that <a href="http://en.wikipedia.org/wiki/Karaoke" target="_blank">karaoke</a> is a popular kind of entertainment in Vietnam so I thought I would make the core rendering engine open source so that everyone especially my fellow developers can make and/or enjoy karaoke online. (About the said karaoke site, of course I only charged the GUI customization and the Red5 recorder)</p>

<p>You can check out or download the source at Google Code site: <a title="http://code.google.com/p/as3-karaoke-player/" href="http://code.google.com/p/as3-karaoke-player/">http://code.google.com/p/as3-karaoke-player/</a>. This library is licensed under <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache License 2.0</a>.</p>  <p>Here's the sample player:</p>  <p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="600" height="400" id="Player" align="middle">  <param name="allowScriptAccess" value="always">  <param name="allowFullScreen" value="true">  <param name="movie" value="http://www.fileden.com/files/2009/8/2/2530043/flash/karplayer_0.8.71.swf">  <param name="quality" value="high">  <param name="bgcolor" value="#FFFFFF"> <param name="flashvars" value="songList=Hạnh Ph&uacute;c Bất Tận,http://www.fileden.com/files/2009/8/2/2530043/data/hanhphucbattan.xml;Hạnh Ph&uacute;c Bất Tận (with vocal),http://www.fileden.com/files/2009/8/2/2530043/data/hanhphucbattan_vocal.xml;C&ocirc; B&eacute; M&ugrave;a Đ&ocirc;ng,http://www.fileden.com/files/2009/8/2/2530043/data/cobemuadong.xml;C&ocirc; B&eacute; M&ugrave;a Đ&ocirc;ng (with vocal),http://www.fileden.com/files/2009/8/2/2530043/data/cobemuadong_vocal.xml;Con Đường T&igrave;nh Y&ecirc;u,http://www.fileden.com/files/2009/8/2/2530043/data/conduongtinhyeu.xml;Con Đường T&igrave;nh Y&ecirc;u (with vocal),http://www.fileden.com/files/2009/8/2/2530043/data/conduongtinhyeu_vocal.xml;Love Story,http://www.fileden.com/files/2009/8/2/2530043/data/lovestory.xml;Love To Be Loved By You,http://www.fileden.com/files/2009/8/2/2530043/data/lovetobelovedbyyou.xml;I'm yours,http://www.fileden.com/files/2009/8/2/2530043/data/imyours.xml">   <embed src="http://www.fileden.com/files/2009/8/2/2530043/flash/karplayer_0.8.71.swf" quality="high" bgcolor="#FFFFFF" width="600" height="400" name="Player" align="middle" allowscriptaccess="always" allowfullscreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="songList=Hạnh Phúc Bất Tận,http://www.fileden.com/files/2009/8/2/2530043/data/hanhphucbattan.xml;Hạnh Phúc Bất Tận (with vocal),http://www.fileden.com/files/2009/8/2/2530043/data/hanhphucbattan_vocal.xml;Cô Bé Mùa Đông,http://www.fileden.com/files/2009/8/2/2530043/data/cobemuadong.xml;Cô Bé Mùa Đông (with vocal),http://www.fileden.com/files/2009/8/2/2530043/data/cobemuadong_vocal.xml;Con Đường Tình Yêu,http://www.fileden.com/files/2009/8/2/2530043/data/conduongtinhyeu.xml;Con Đường Tình Yêu (with vocal),http://www.fileden.com/files/2009/8/2/2530043/data/conduongtinhyeu_vocal.xml;Love Story,http://www.fileden.com/files/2009/8/2/2530043/data/lovestory.xml;Love To Be Loved By You,http://www.fileden.com/files/2009/8/2/2530043/data/lovetobelovedbyyou.xml;I'm yours,http://www.fileden.com/files/2009/8/2/2530043/data/imyours.xml"></embed>  </object>    <br /><em><font size="2">(The background photo is taken by me :P )</font></em></p> <a name='more'></a>  <p>This library will render lyrics and music in synchronization so that viewer can sing a long. The core player was designed as simple as a screen to render karaoke only. Developers can implement their own graphical interface to control the engine and add other features.</p>  <p>The library was implemented with performance concerns and open standards kept in mind. The lyrics data file is adopted from W3C standard <a href="http://www.w3.org/TR/ttaf1-dfxp/" target="_blank">Timed Text</a>. The player uses <a href="http://int3ractive.blogspot.com/2010/03/as3signals-new-approach-for-as3-events.html" target="_blank">AS3Signals</a> as communication mechanism among components.</p>  <p>Current features: </p>  <ul>   <li>Load and parse a Timed Text-based lyrics XML file (see <a href="http://code.google.com/p/as3-karaoke-player/source/browse/trunk/flash/bin/xml/song_full_specs.xml" target="_blank">specifications</a>) </li>    <li>Load and play progressive beat audio (MP3) </li>    <li>Lyric texts are synchronized with audio </li>    <li>Play, pause, stop, seek allowed </li>    <li>Set global lyric styles (font, color, size) and few options </li> </ul>  <p>I have also created a sample player (demo above) based on the Lunar skin from <a href="http://code.google.com/p/reops/" target="_blank">RealEyes OSMF Media Player</a> with these additional features:</p>  <ul>   <li>Set volume </li>    <li>Turn lyrics (A.K.A captions) on/off </li>    <li>Go to full screen </li> </ul>  <p>These are features that I plan to add (random order and no promises):</p>  <ul>   <li>AIR application for editing the lyric data file </li>    <li>Song-specific lyric color styling </li>    <li>Multiple text lines (more than 2, not decided how to show/animate them) </li>    <li>Custom transition for text line instances </li>    <li>Photo slide show for background </li>    <li>Red5 application for recording from user's microphone </li>    <li>Play video as background </li>    <li>Play karaoke video (videos with music and running lyrics) </li>    <li>Flex Component&#160; </li>    <li>AIR application for local recording </li>    <li>... (please suggest) </li> </ul>  <p>If you find any bugs or have any suggestion, feel free to post a new ticket to the issue tracker. I welcome anyone wants to join this project.</p>  <p><font size="1">[Vietnamese tag: công bố thư viện nguồn mở đầu tiên của tôi as3-karaoke-player]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>How to run Flash CS5 on Ubuntu (with Wine)</title>
    <link href="https://int3ractive.com/blog/2010/how-to-run-flash-cs5-on-ubuntu-with/"/>
    <updated>2010-08-14T07:40:00Z</updated>
    <id>https://int3ractive.com/blog/2010/how-to-run-flash-cs5-on-ubuntu-with/</id>
    <content type="html"><![CDATA[
      
<p>Updated on 2011-05-24</p> <p><a href="https://lh4.ggpht.com/_47w2iQ8-NcE/TGZIOWS0tyI/AAAAAAAACo8/Ro862AAEMVg/s1600-h/Desk%201_004%5B8%5D.png" target="_blank"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Flash CS5 on Ubuntu 10.04" border="0" alt="Flash CS5 on Ubuntu 10.04" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TGZIRfBlBjI/AAAAAAAACpA/VCwtDuLZMXc/Desk%201_004_thumb%5B6%5D.png?imgmax=800" width="604" height="484"></a> </p> <p>After a couple of days testing and examining, finally, I have managed to run Adobe Flash CS5 on my Ubuntu machine. As I say "run", I mean that I did not succeed installing the application but I had to copy the installed files from Windows. However, it is worth noting that this is the first Adobe Flash version that runs with workable quality since Macromedia Flash 8. The last 2 versions (CS3 &amp; CS4) is known to be useless when trying to run with Wine.</p>

<p>No more wandering, let's me show you the how to first and then comments later. </p> <a name='more'></a> <h3>1. Install Adobe Flash CS5 on Windows</h3> <p>I installed Adobe Flash CS5 on my Windows XP virtual machine (32-bit). You can get the trial version of Flash CS5 <a href="http://www.adobe.com/products/flash/" target="_blank">here</a>. I suggest you install everything in the package in the default installation path.</p> <h3>2. Export Adobe registry branch</h3> <p>- Go to Start &gt; Run… &gt; input regedit &gt; OK <br>- In Regitry Editor, navigate to HKEY_LOCAL_MACHINE/SOFTWARE <br>- Select Adobe&nbsp; branch &gt; File &gt; Export… &gt; save the file as adobe.reg &gt; store it some where so you can access from Ubuntu later.</p> <p>Now, let’s get back to Ubuntu. I’m using Ubuntu 10.04 Lucid.</p> <h3>3. Installing Wine 1.3</h3> <p>By the time of this post, the official repository of Ubuntu only update Wine to version 1.1.34. So you need to add the ppa repository from WineHQ to get the latest version. Open the terminal and enter these commands:</p> <p><font face="Courier New">~$ sudo add-apt-repository ppa:ubuntu-wine/ppa <br>~$ sudo apt-get update <br>~$ sudo apt-get install wine1.3</font></p> <p>By installing this version, you will also get <a href="http://wiki.winehq.org/winetricks" target="_blank">winetricks</a> installed. If you’re using other distro, go to <a href="http://www.winehq.org/download" target="_blank">this link</a> to get your version of Wine.</p> <h3>4. Install subordinate Windows native libraries</h3> <p>It is recommended that you reset your wineprefix by deleting ~/.wine folder if you have testing something else before with wine. Then, use winetricks to install these libaries:</p> <p><font face="Courier New">~$ winetricks vcrun2008 msxml3 atmlib gdiplus</font></p> <p>The atmlib is kept in a large cab file so it is normal that you will experience a long progress downloading the 120MB cab file.</p> <h3>5. Replicate the installation in Ubuntu</h3> <p>Copy from Windows to Ubuntu :</p> <ul> <li>“C:\Program Files\Adobe\" to "$HOME/.wine/drive_c/Program Files/Adobe"  <li>“C:\Program Files\Common Files\Adobe" to “$HOME/.wine/drive_c/Program Files/Common Files/Adobe"  <li>“C:\Documents and Settings\All Users\Application Data\Adobe\CS5” to “$HOME/.wine/drive_c/users/Public/Application Data/Adobe/CS5” <br><strong>(this is required for Java Runtime Environment)</strong> </li></ul> <p>Import the registry branch for Adobe:</p> <p><font face="Courier New">~$ wine regedit adobe.reg</font> <br>(assuming the file adobe.reg has been placed at your home folder)</p> <p>Then you’re done. Here you can run the application from command line:</p> <p><font face="Courier New">~$ cd "$HOME/.wine/drive_c/Program Files/Adobe/Adobe Flash CS5" <br>~/.wine/drive_c/Program Files/Adobe/Adobe Flash CS5$ wine Flash.exe </font></p> <p>During the initialization, you may come across this error message:</p> <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Program Error_008" border="0" alt="Program Error_008" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TGZISZ2dZrI/AAAAAAAACpE/ycA5YAxW6T8/Program%20Error_008%5B4%5D.png?imgmax=800" width="416" height="318"> </p> <p>Just click Close and Flash CS5 will continue to start up.</p> <p>For convenience, you can create a launcher to run Flash CS5 from your desktop:</p> <h3>6. Create desktop launcher</h3> <p>Right click on desktop and select Create Launcher <br>Enter the command as in the image: <br><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Adobe Flash CS5 Properties_007" border="0" alt="Adobe Flash CS5 Properties_007" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TGZITzQjA-I/AAAAAAAACpI/aNSCIpGWPc8/Adobe%20Flash%20CS5%20Properties_007%5B4%5D.png?imgmax=800" width="538" height="442"> <br>You can find the logo of Flash CS5 in: …Adobe Flash CS5/Common/First Run/StartPage/resources/images/appicon_xl.png</p> <h3>7. How to: resolve “Error initializing Java Runtime Environment”</h3> <p>When starting Flash CS5, you may experience this error message:</p> <p><strong><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Selection_002" border="0" alt="Selection_002" src="https://lh3.ggpht.com/_47w2iQ8-NcE/TGZIUpAuCCI/AAAAAAAACpM/wW4_NRKvFiY/Selection_002%5B4%5D.png?imgmax=800" width="504" height="163"></strong></p> <p>There are a few reasons that I can identify up to now:</p> <h4>- The bundled JRE of CS5 is missing:</h4> <p>Make sure you copy the <strong>jre</strong> folder from: <br>C:\Documents and Settings\All Users\Application Data\Adobe\CS5 <br>to: <br>$HOME/.wine/drive_c/users/Public/Application Data/Adobe/CS5</p> <h4>- Error reserving the memory for the Java Virtual Machine:</h4> <p>When you run Flash CS5 with command line, you may notice these error messages together with above message box: <br><font face="Courier New">Error occurred during initialization of VM <br>Could not reserve enough space for object heap</font></p> <p>This is related to the <strong>–Xmx###m</strong> parameter in the JVM initial config.</p> <p>To fix, open the jvm.ini file located at: <br>$HOME/.wine/drive_c/users/$USER/Local Settings/Application Data/Adobe/Flash CS5/en_US/Configuration/ActionScript 3.0/jvm.ini <br>(Assuming $USER is current user name)</p> <p>Try editing the default line <strong>–Xmx128m</strong> NOT to a higher value BUT to a LOWER value.</p> <p>When I set it to <strong>–Xmx64m</strong>, the problem is gone (my RAM is 2GB on a 32-bit Ubuntu)!</p> <h3>8. How to: Built applications cannot access online resources</h3> <p><em>(This solution is still in progress and can only resolve the issue partially)</em></p> <p>When you build your application, the application will not be able to access online resources. This is because of the security sandbox which prevent local file access internet location. To solve, you can add trusted location to the Flash Player’s global settings.</p> <p>There are 2 ways to do this:</p> <ol> <li>Using the <a title="Global Security Settings panel" href="http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html" target="_blank">Global Security Settings panel</a> to add your working folder. However, this requires you install IE6 and Flash Player to your wineprefix. (How to do this is long and out of this post’s scope)  <li>Create new .cfg file at this location: <br>$HOME/.wine/drive_c/users/$USER/Application Data/Macromedia/Flash Player/#Security/FlashPlayerTrust/ <br>If the folders are not there, create them manually. <br>Each .cfg is a plain text document containing the path to your trusted folder. For e.g.: C:\ </li></ol> <p>However, this just allow the application to access internet when testing in debug mode! There is still something wrong with the normal run.</p> <h3>Other comments:</h3> <p>Thanks to <a href="http://appdb.winehq.org/objectManager.php?sClass=version&amp;iId=20158" target="_blank">this how to</a> for <a href="http://www.adobe.com/products/photoshop/compare/" target="_blank">Photoshop CS5</a> in <a href="http://appdb.winehq.org" target="_blank">AppDB</a>, I have come up with this procedure. However, <strong>you can use this procedure to run Photoshop CS5 as well</strong>. (I have tried)</p> <p>Here’s my test report so far (deeper test update to come):</p> <p><strong>What works:</strong> most of the normal functionalities </p> <ul> <li>All the drawing tools including 3D transform  <li>All Panels: library, color, align, transform, AS editor…  <li>Time line, layers, tweens  <li>TLF text, Classic text  <li>Open, Save, Build, Test run </li></ul> <p><strong>What does not work:</strong></p> <ul> <li>If Java Runtime Environment fails to initialize, some components will not work <br>- New TLF TextField <br>- New AS editor (fall back to old one) <br>- ActionScript will be ignored in the output application <br>(See How to resolve “Error initializing Java Runtime Environment” above)  <li>In the workspace, the contents are sometime clipped or hidden. But when I try scrolling or zooming, the contents appear fully again. This looks like being caused by the rendering library. (UPDATE FIX: View &gt; Preview Mode &gt; select Fast)&nbsp; <li>The application can only start debug session once. If you attempt debug your application again, the application will notice that the debug socket is being used! </li></ul> <p><strong>What was not tested:</strong></p> <ul> <li>Build a AIR  <li>iPhone Packager  <li>Some other unpopular functions </li></ul> <p>I will post my report to AppDB when getting some more test results.</p>    <h3>Adobe Media Encoder CS5</h3> <p>I also tried Adobe Media Encoder CS5. It ran but I could only open videos in some kind of format (3GP, MP4). Others (MPG, AVI…) failed to open. It seems like this program requires some default encoders available in Windows (which are not in Wine).</p> <p><a href="https://lh4.ggpht.com/_47w2iQ8-NcE/TGZIarT399I/AAAAAAAACpQ/PsIbrJbHvYM/s1600-h/Desk%201_008%5B7%5D.png" target="_blank"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Adobe Media Encoder CS5 on Ubuntu" border="0" alt="Adobe Media Encoder CS5 on Ubuntu" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TGZId4aop7I/AAAAAAAACpU/l-leTzqy4nY/Desk%201_008_thumb%5B5%5D.png?imgmax=800" width="604" height="484"></a> </p> <p>I will investigate further to improve the usability but this progress is very satisfactory to me. Now I can work with most projects without starting the virtual machine.</p> <p><strong>Update 2010-08-16</strong>: Added …/CS5/ to the folders need to copy, added 7. How to: resolve “Error initializing Java Runtime Environment” and 8. How to: Built applications cannot access online resources.</p> <p><strong>Update 2010-11-22:</strong> Flash CS5 stops at "building workspace" while initializing if Wine version is 1.3.7. I have no work around yet so if you want to run Flash CS5, please stay at Wine 1.3.6. (Photoshop CS5 may start normally)</p> <p><strong>Update 2010-12-02:</strong> The startup issue discussed above was fixed since Wine 1.3.8. Wine 1.3.8 was released at the end of Nov ‘10. You can now upgrade Wine to latest version to enjoy Flash CS5 on Linux. It is not likely that this issue will occur again in future version of Wine.</p> <p><strong>Update 2011-05-24:</strong><br>- I have just found out that if you <strong>switch Preview Mode to Fast</strong> (menu View &gt; Preview Mode &gt; Fast or Ctrl-Shift-Alt-F), the authoring stage will render much faster and virtually no more clipping issue.<br>- I have tried to run<strong> Flash CS 5.5</strong> and <strong>Photshop CS 5.1 trial</strong> on Ubuntu 11.04 using the same procedure. They both started as expected with the trial reminder window as well. However, during working session, an error popup keep appearing after a while. To tackle this, use the winetrick suggested by a commenter below (thanks Endur)<br><font face="Courier New">$ winetricks nocrashdialog</font></p> <p><font size="1">[Vietnamese tags: Hướng dẫn chạy Adobe Flash CS5 trên Ubuntu (với Wine) | Làm sao để chạy Flash CS5 trên Ubuntu]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Dark color scheme for FDT &amp; FlashDevelop</title>
    <link href="https://int3ractive.com/blog/2010/dark-color-scheme-for-fdt-flashdevelop/"/>
    <updated>2010-08-12T07:23:00Z</updated>
    <id>https://int3ractive.com/blog/2010/dark-color-scheme-for-fdt-flashdevelop/</id>
    <content type="html"><![CDATA[
      
<p>Here’s my (dark) color scheme for FDT 3.5:</p> <p><a href="https://lh6.ggpht.com/_47w2iQ8-NcE/TGOhFRiZyRI/AAAAAAAACnw/rPNb9bLB95I/s1600-h/eclipse_pref_001%5B5%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="eclipse_pref_fdt" border="0" alt="eclipse_pref_fdt" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TGOhH3fRUnI/AAAAAAAACn4/YJOn6ltEY6c/eclipse_pref_001_thumb%5B3%5D.png?imgmax=800" width="644" height="470"></a> </p> <p>To install, follow these steps:</p> <ol> <li>Save my <a title="download color scheme for FDT" href="http://thanhtran-sources.googlecode.com/svn/trunk/misc/fdt_config/eclipse_fdt_dark_ttt.epf" target="_blank">eclipse preference file (.epf)</a> to your computer. (Don’t worry, this preference file only contains color settings for FDT, your own settings will not be affected)  <li>In FDT/Eclipse go to File &gt; Import… &gt; expand General &gt; select Preferences &gt; click Next  <li>At “From preference file” box, browse to the preference file &gt; Check “Import all” &gt; click Finished and there you go.</li></ol> <p>If you want to know how to make these preference files, <a href="http://blog.ansuz.nl/index.php/2009/01/26/howto-create-a-color-scheme-for-fdt/" target="_blank">read this tutorial</a>.</p> <p>Besides, the black background of the editor is set at global setting. Therefore, other editors (.txt, .xml, .java…) must also be changed to dark theme or they are very difficult to read.</p><a name='more'></a> <p>Here are my additional preference file for:</p> <p><strong>ANT XML:</strong> <a href="http://thanhtran-sources.googlecode.com/svn/trunk/misc/fdt_config/eclipse_ant_dark_ttt.epf" target="_blank">download here</a></p> <p><a href="https://lh3.ggpht.com/_47w2iQ8-NcE/TGOhKfhGk_I/AAAAAAAACoA/k9yLF-_WgEg/s1600-h/eclipse_pref_002%5B9%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="eclipse_pref_ant" border="0" alt="eclipse_pref_ant" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TGOhMhy29yI/AAAAAAAACoI/hHkiKw2x53k/eclipse_pref_002_thumb%5B7%5D.png?imgmax=800" width="644" height="465"></a> </p> <p><strong>Java &amp; WTP:</strong> <a href="http://thanhtran-sources.googlecode.com/svn/trunk/misc/fdt_config/eclipse_jdt_wst_dark_ttt.epf" target="_blank">download</a> (this one is my quick adoption of <a href="http://blog.prabir.me/post/Dark-Eclipse-Theme.aspx" target="_blank">this guy’s theme</a> after removing redundant settings)</p> <p><a href="https://lh3.ggpht.com/_47w2iQ8-NcE/TGOhPLvzRKI/AAAAAAAACoM/sCn-RDzbqOk/s1600-h/eclipse_pref_003%5B7%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="eclipse_pref_003" border="0" alt="eclipse_pref_003" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TGOhRcov-iI/AAAAAAAACoQ/e6PcQ-l-1DI/eclipse_pref_003_thumb%5B4%5D.png?imgmax=800" width="644" height="468"></a> </p> <p><strong>Bonus: </strong>SVN coloring scheme (<a href="http://thanhtran-sources.googlecode.com/svn/trunk/misc/fdt_config/eclipse_svn_ttt.epf" target="_blank">download</a>)</p> <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="eclipse_svn" border="0" alt="eclipse_svn" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TGOhSV8cQWI/AAAAAAAACnk/pj3v25kIjJE/eclipse_svn%5B5%5D.png?imgmax=800" width="322" height="471"> </p> <p>&nbsp;</p> <p>And last but not least, my<strong> dark color scheme for FlashDevelop 3.1+</strong> (actually, my FDT scheme is based on this): <a title="Open read_me.txt for instruction" href="http://thanhtran-sources.googlecode.com/svn/trunk/misc/flashdevelop_config/" target="_blank">instruction &amp; download</a></p> <p><a href="https://lh4.ggpht.com/_47w2iQ8-NcE/TGOhTUUreKI/AAAAAAAACoU/sXnAghXyw_Y/s1600-h/fd_color_scheme%5B5%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="fd_color_scheme" border="0" alt="fd_color_scheme" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TGOhVjBkzjI/AAAAAAAACoc/3fVN1pacLo4/fd_color_scheme_thumb%5B3%5D.png?imgmax=800" width="644" height="419"></a> </p> <p>Next time, I’ll compose some preference file to make FDT behave more like FlashDevelop and more convenient to use. (So that you and I don’t have to wade through all the settings again when installing a new copy of FDT)</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Myth Buster: EnterFrame Event Performance</title>
    <link href="https://int3ractive.com/blog/2010/myth-buster-enterframe-event/"/>
    <updated>2010-07-01T05:30:00Z</updated>
    <id>https://int3ractive.com/blog/2010/myth-buster-enterframe-event/</id>
    <content type="html"><![CDATA[
      
<p>When dealing with animation and tweening in ActionScript, EnterFrame event is the most important factor. However, it is also one of the frequent factors to cause performance issue for your application. Using it efficiently is critical for every application.</p>

<h3>The myths</h3>
<p>The EnterFrame events reportedly generate 1500 &ndash; 1800 event objects per minutes. Imagine, in every instance of your component (for e.g. a text marquee), you add an EnterFrame handler to its own, that number of objects generated per minute will multiply. Keep in mind that, creating an object is one of the <a href="http://www.richardlord.net/blog/object-pool-class" target="_blank" rel="noopener">slow actions in ActionScript</a>. So avoid creating too many event objects will theoretically improve application performance.</p>
<p>When <a href="http://int3ractive.blogspot.com/2010/03/as3signals-new-approach-for-as3-events.html" target="_blank" rel="noopener">discussing AS3Signals</a>, I have mentioned an approach (raised by <a title="Rober Penner's 2-frame symbol solution" href="http://gist.github.com/243630" target="_blank" rel="noopener">Robert Penner</a> and <a title="Alec's [frame] tag solution" href="http://alecmce.com/as3/replacing-enter_frame" target="_blank" rel="noopener">AlecMcE</a>) which uses a two-frame MovieClip which has some script attached to its frames. The MovieClip loops continuously between 2 frames. When the play head reach a frame, the script attached to it will call the handling function, imitating EnterFrame&rsquo;s events. Some claims that: &ldquo;The idea behind the approach is that a frame-loop is an internal Flash player structure. It sits underneath the AS3 functionality, and so it doesn&rsquo;t produce ENTER_FRAME events&rdquo;.</p>
<h3>The experiments</h3>
<p><a href="https://lh6.ggpht.com/_47w2iQ8-NcE/TCwoz29C_WI/AAAAAAAACmU/sxCMk_E94lc/s1600-h/demo%5B3%5D.jpg"><img title="demo" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TCwo1dvj-UI/AAAAAAAACmY/kqfzIHIsCyo/demo_thumb%5B1%5D.jpg?imgmax=800" alt="demo" width="554" height="404" border="0" /></a></p>
<p>To clear the myths about EnterFrame event performance and the 2-frame-loop approach, I have constructed an experiment of moving 5000 objects simultaneously using 4 different approaches:</p>
<p>&nbsp;</p>
<h4>1. A singleton frame-loop Manager. <a title="Singleton frame-loop manager" href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/EnterFrameTest/bin/enter_frame_test.swf?singleton=true&amp;event=false" target="_blank" rel="noopener shadowbox[EnterFrameTest];width=550;height=400">(View demo)</a></h4>
<p>This singleton manager will extends a 2-frame movieclip. This movie clip is created before-hand in Flash CS. Attach the same enterFrameHandler to its 2 frames. The moving balls will attach their enterFrameHandler to this manager via Signals:</p>
<div>
<ol>
<li>
<div>publicclass TwoFrameManager extends TwoFrameMovie {</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; static privatevar _instance: TwoFrameManager = new TwoFrameManager();</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicvarenterFrame: Signal;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicfunction TwoFrameManager(){</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enterFrame = new Signal();</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addFrameScript(0, enterFrameHandler,1, enterFrameHandler);</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; privatefunction enterFrameHandler():void{</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enterFrame.dispatch();</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; static publicfunctionget instance(): TwoFrameManager {return _instance;}</div>
</li>
<li>
<div>}</div>
</li>
</ol>
</div>
<h4>2. A singleton EnterFrame Manager. <a title="Singleton enterFrame manager" href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/EnterFrameTest/bin/enter_frame_test.swf?singleton=true&amp;event=true" target="_blank" rel="noopener shadowbox[EnterFrameTest];width=550;height=400">(View demo)</a></h4>
<p>This manager will work the same as previous one except it extends a Shape (the most simple display object that can be created with &lsquo;new&lsquo; statement) and add an event listener to its own EnterFrame event.</p>
<div>
<ol>
<li>
<div>publicclass EnterFrameManager extends<a href="http://www.google.com/search?q=shape%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:shape.html">Shape</a>{</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; static privatevar _instance: EnterFrameManager = new EnterFrameManager();</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicvarenterFrame: Signal;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicfunction EnterFrameManager(){</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enterFrame = new Signal();</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addEventListener(<a href="http://www.google.com/search?q=event%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:event.html">Event</a>.ENTER_FRAME, enterFrameHandler);</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; privatefunction enterFrameHandler(event:<a href="http://www.google.com/search?q=event%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:event.html">Event</a> = null):void{</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enterFrame.dispatch();</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; static publicfunctionget instance(): EnterFrameManager {return _instance;}</div>
</li>
<li>
<div>}</div>
</li>
</ol>
</div>
<h4>3. Multiple frame-loop instances <a title="Multiple frame-loop instances" href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/EnterFrameTest/bin/enter_frame_test.swf?singleton=false&amp;event=false" target="_blank" rel="noopener shadowbox[EnterFrameTest];width=550;height=400">(View demo)</a></h4>
<p>Every moving ball instance will attach its enterFrameHandler to the frames of a new TwoFrameMovie. i.e. there is one TwoFrameMovie for each moving ball.</p>
<div>
<ol>
<li>
<div>publicclass MovingBall extends<a href="http://www.google.com/search?q=sprite%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:sprite.html">Sprite</a>{</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicvarenterFrame: TwoFrameMovie;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicfunction MovingBall(){</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enterFrame = new TwoFrameMovie();</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enterFrame.addFrameScript(0, enterFrameHandler,1, enterFrameHandler)</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; /*...*/</div>
</li>
<li>
<div>}</div>
</li>
</ol>
</div>
<h4>4. Multiple EnterFrame instances <a title="Multiple enter-frame instances" href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/EnterFrameTest/bin/enter_frame_test.swf?singleton=false&amp;event=true" target="_blank" rel="noopener shadowbox[EnterFrameTest];width=550;height=400">(View demo)</a></h4>
<p>Every moving ball will add an EnterFrame event listener to its own instance:</p>
<div>
<ol>
<li>
<div>publicclass MovingBall extends<a href="http://www.google.com/search?q=sprite%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:sprite.html">Sprite</a>{</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicvarenterFrame: TwoFrameMovie;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicfunction MovingBall(){</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addEventListener(<a href="http://www.google.com/search?q=event%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:event.html">Event</a>.ENTER_FRAME, enterFrameHandler);</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; /*...*/</div>
</li>
<li>
<div>}</div>
</li>
</ol>
</div>
<h3>Results:</h3>
<p>Running the demos a few time, I have come up with these average statistics (reported through the same <a href="http://github.com/mrdoob/stats.as" target="_blank" rel="noopener">Stats</a> panel):</p>
<p>My computer: Intel Core 2 Duo 2.53Ghz, 2GB RAM, Win XP, Firefox 3.6, Flash Player 10.0 debugger.<br />Moving 5000 objects after 70 seconds. Compiled frame rate is 30.</p>
<ol>
<li>Singleton frame-loop manager:<br />- Average FPS: <strong>23-24<br /></strong>- Max Memory: <strong>~ 20.900</strong> MB</li>
<li>Singleton EnterFrame manager:<br />- Average FPS: <strong>24<br /></strong>- Max Memory: <strong>~ 20.900</strong> MB</li>
<li>Multi-instances, frame-loop movie:<br />- Average FPS: <strong>18</strong><br />- Max Memory: <strong>~ 24.300</strong> MB</li>
<li>Multi-instances, EnterFrame event :<br />- Average FPS: <strong>13</strong><br />- Max Memory: <strong>~ 24.000</strong> MB</li>
</ol>
<p>The source code of my demo is <a href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/EnterFrameTest" target="_blank" rel="noopener">placed here</a>.</p>
<h3>What is learned from those numbers?</h3>
<ol>
<li>First, with a single event listener or frame-loop, there&rsquo;s virtually <strong>no difference in performance and memory</strong>.</li>
<li>Multi instances of frame-loops or enterframe handlers will both <strong>significantly reduce our application performance</strong>.</li>
<li>The fact that frame rate of demo 3 higher than demo 4 can be considered a <strong>proof that frame-loop doesn&rsquo;t generate objects</strong> (hence it&rsquo;s performance is better).</li>
<li>Although faster, demo 3 consumes more memory due to the fact that it must create a 2-frame MovieClip for its every instance. (I haven&rsquo;t tried to improved this anyway)</li>
<li><strong>Creating many objects is </strong>really an <strong>&lsquo;evil&rsquo; </strong>thing to application performance.</li>
</ol>
<h3>Conclusion</h3>
<p>The Myth Buster way:</p>
<ul>
<li>Many event listeners (EnterFrame in particular) will reduce performance: <strong>Confirmed</strong></li>
<li>Frame-loop doesn&rsquo;t create EnterFrame objects: <strong>Feasible</strong></li>
</ul>
<p>My way:</p>
<ul>
<li><strong>It is strongly recommended that you should use an EnterFrameManager or TickManager</strong> (depending on how you call it) for every project needs EnterFrame events. The demo is using Signals to manage handlers. You can implement a non-Signals Manager with ease.</li>
<li>It&rsquo;s possible to conclude that frame-loop is more efficient than EnterFrame events. However, the fact that 2 singleton approaches don&rsquo;t have significant difference in performance, you can <strong>safely use the traditional (singleton) event approach for the sake of simplicity</strong>.</li>
</ul>
<p>[Vietnamese tag: giải m&atilde; những giả thuyết về vấn đề tối ưu tốc độ của sự kiện EnterFrame]</p>
<p>Visit <a href="https://rubiks-cu.be/" rel="nofollow noopener">www.Rubiks Cu.be</a>, a new website dedicated to the puzzle cube. Try the online simulator, the solver, learn the easiest solution method and measure your solution times.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project Pop Rox</title>
    <link href="https://int3ractive.com/blog/2010/project-pop-rox/"/>
    <updated>2010-06-15T04:20:00Z</updated>
    <id>https://int3ractive.com/blog/2010/project-pop-rox/</id>
    <content type="html"><![CDATA[
      
<p><a href="https://lh6.ggpht.com/_47w2iQ8-NcE/TViug2ICCkI/AAAAAAAADIY/Ac925H8hghQ/s1600-h/poproxcity_1%5B1%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="Intro screen" border="0" alt="Intro screen" src="https://lh4.ggpht.com/_47w2iQ8-NcE/TViuinAB5VI/AAAAAAAADIg/OyHU4rP6zxU/poproxcity_1_thumb.png?imgmax=800" width="410" height="311" /></a>This part-time project is about making a role playing game with a turn-base battle system. The story and events of the game can be easily scripted via an XML file. I have joined created the basic structure and workflow of the game based on PureMVC framework; created the scriptable story teller. This is a medium project with 4 developers.</p>  <p>My role: Team leader, Flash developer</p>  <p>Tech notes: </p>  <ul>   <li><a href="http://puremvc.org/" target="_blank">PureMVC</a> framework </li>    <li><a href="http://gskinner.com/libraries/gtween/" target="_blank">GTween</a> engine </li>    <li>AddictingGames’ sponsor teaser </li> </ul>  <p><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/TViuoBi87uI/AAAAAAAADIo/qh8Cq1hR3XY/s1600-h/poproxcity_2%5B1%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Map and HUD" border="0" alt="Map and HUD" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TViup0jhQEI/AAAAAAAADIw/zbu39fjgQoc/poproxcity_2_thumb.png?imgmax=800" width="244" height="185" /></a> <a href="https://lh6.ggpht.com/_47w2iQ8-NcE/TViur29-oYI/AAAAAAAADI4/IVEb9dcI-Xw/s1600-h/poproxcity_3%5B1%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Inventory" border="0" alt="Inventory" src="https://lh6.ggpht.com/_47w2iQ8-NcE/TViusXZsnnI/AAAAAAAADI8/xjXwAOEcfPg/poproxcity_3_thumb.png?imgmax=800" width="244" height="185" /></a> <a href="https://lh4.ggpht.com/_47w2iQ8-NcE/TViuvfj2GdI/AAAAAAAADJI/GFFrSFmddZE/s1600-h/poproxcity_6%5B1%5D.png" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Battle" border="0" alt="Battle" src="https://lh5.ggpht.com/_47w2iQ8-NcE/TViuwGzIOcI/AAAAAAAADJc/Do51vO4tVXQ/poproxcity_6_thumb.png?imgmax=800" width="244" height="184" /></a></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Optimal Unicode range for Vietnamese font libraries</title>
    <link href="https://int3ractive.com/blog/2010/optimal-unicode-range-for-vietnamese/"/>
    <updated>2010-06-08T11:49:00Z</updated>
    <id>https://int3ractive.com/blog/2010/optimal-unicode-range-for-vietnamese/</id>
    <content type="html"><![CDATA[
      
<p>As an old-school tip, in order to display correct Vietnamese Unicode characters, we must include these character sets: <strong>Basic Latin + Latin I + Latin Extended A + Latin Extended Additional.</strong></p>  <p>Although those 4 sets contain <strong>994 glyphs</strong>, Vietnamese characters scatter in those sets and only take about one third of that number of glyphs. It is a waste to include other Latin characters that Vietnamese language never uses.</p>  <p>So I’ve done a quick experiment and come up with an <strong>optimal unicode range for Vietnamese characters</strong> (for [Embed] tags and compiled with Flex SDK):</p> <a name='more'></a>  <div class="actionscript3"><font face="Courier New">//This unicode range include: Basic Latin + Vietnamese Unicode      <br /><strong>//(243 glyphs)</strong>&#160; <br />'U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E,U+00C0-U+00C3,U+00C8-U+00CA,U+00CC-U+00CD,U+00D0,U+00D2-U+00D5,U+00D9-U+00DA,U+00DD,U+00E0-U+00E3,U+00E8-U+00EA,U+00EC-U+00ED,U+00F2-U+00F5,U+00F9-U+00FA,U+00FD,U+0102-U+0103,U+0110-U+0111,U+0128-U+0129,U+0168-U+0169,U+01A0-U+01B0,U+1EA0-U+1EF9'       <br />//To support additional Vietnamese <strong>composite</strong> unicode characters,       <br />//append this range <strong>(total 337 glyphs)</strong>&#160; <br />U+02C6-U+0323</font></div>  <p>However, Flash Player render composite unicodes very ugly (see demo). So the best advice is <strong>avoid using them</strong>. BTW, you cannot embed composite characters in Flash CS* even though you select all Latin* sets, weird!</p>  <p>Below is a simple demo which display full range of Vietnamese characters (you can also try entering or pasting some Vietnamese text):</p>  <p style="border-right: 1px solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid"><embed src="http://www.fileden.com/files/2009/8/2/2530043/flash/VietnameseUnicodeDemo.swf" bgcolor="#FFFFFF" type="application/x-shockwave-flash" allowscriptaccess="none" align="middle" width="600" height="400"></embed></p>  <p>The demo would take<strong> 23KB</strong> (<strong>18KB</strong> without composite) compared to <strong>50KB </strong>of the same demo embedding 4 full sets of characters. And this is only 1 style of 1 font.</p>  <p>You can download the demo source code for usage reference <a title="VietnameseFont" href="https://thanhtran-sources.googlecode.com/svn/trunk/demos/VietnameseUnicode/src/VietnameseFont.as" target="_blank">here</a>.</p>  <p><font size="1">[Vietnamese tag: danh sách tối thiểu các ký tự unicode cho Tiếng Việt khi nhúng font động]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Sans serif font improves code editor readability</title>
    <link href="https://int3ractive.com/blog/2010/sans-serif-font-improves-code-editor/"/>
    <updated>2010-05-29T17:06:00Z</updated>
    <id>https://int3ractive.com/blog/2010/sans-serif-font-improves-code-editor/</id>
    <content type="html"><![CDATA[
      
<p>In Windows, I often use <strong style="FONT-FAMILY: Courier New">Courier New</strong> font for my code editor since it is the default monospace font which support a decent range of Unicode characters. However, the Courier New is a typewriter-like font which is somehow difficult to read because of its short, broad face with over-emphasized serifs. <em>(Serif: a short line at the end of the main strokes of a character)</em>.</p>

<p>In Ubuntu, the default editor font in Eclipse is <strong>Monospace</strong> which is a sans-serif font. <em>(<strong>Sans serif</strong> is a type of font without serif)</em>. To my observation, this font is much more legible than Courier New especially when the characters are small in size. Sadly, the font doesn't support many Unicode letters especially Vietnamese and extended Latin. Looking around in Ubuntu's default font sets, I've found <strong>WenQuanYi Micro Hei Mono.</strong> This sans serif monospace font contains a broad range of Unicode letters including Vietnamese and other East Asian languages. This is exactly what I'm looking for in terms of readibility and Unicode support.</p>
<p>To my studies, <strong>WenQuanYi Micro Hei</strong> is an open source derivative of <a href="http://www.droidfonts.com/droidfonts/" target="_blank" title="Droid Sans family">Droid Sans</a> Fallback and is powered by many Linux distros. As you may guess, Droid Sans is the font for the hottie mobile platform - <a href="http://www.android.com/" target="_blank" title="Android platform">Android</a>. Windows users can download WQY Micro Hei font <a href="https://sourceforge.net/project/downloading.php?group_id=128192&amp;filename=wqy-microhei-0.2.0-beta.tar.gz&amp;a=95328517" target="_blank" title="Download WQY Micro Hei Mono">here</a> (The file format is a true type collection .ttc).</p>
<p>Here's the screenshot of Courier New (top) and WQY Micro Hei Mono (bottom) both in size 11pt, 100% zoom:</p>
<p><img src="https://lh4.ggpht.com/_47w2iQ8-NcE/TAFJqYupb-I/AAAAAAAAClI/KKEVwLaIsRw/monospace_compare.jpg?imgmax=640" style="BORDER-RIGHT: 1px; BORDER-TOP: 1px; BORDER-LEFT: 1px; BORDER-BOTTOM: 1px" height="600" alt="monospace_compare.jpg" width="600"/></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Demystify the “root” property of DisplayObject</title>
    <link href="https://int3ractive.com/blog/2010/demystify-root-property-of/"/>
    <updated>2010-05-18T07:06:00Z</updated>
    <id>https://int3ractive.com/blog/2010/demystify-root-property-of/</id>
    <content type="html"><![CDATA[
      
<p>Every DisplayObject has a property named “root”. What does this property refer to? Do all display objects share the same root object?</p>  <p>According to <a title="Help on DisplayObject.root" href="http://help.adobe.com/en_US/AS3LCR/Flash_10.0/flash/display/DisplayObject.html#root" target="_blank">Adobe’s Help</a>, the <font face="Courier New">root</font> property is the top-most display object in the portion of the display list's tree structure represented by that SWF file. In other words, root is the document class of that SWF. (By saying document class, I mean the movie clip that is linked with document class in Flash CS or the target class which you compile with Flex SDK)</p>  <p>There are other cases mentioned in the document:</p>  <ul>   <li>Root of Stage is the Stage itself. </li>    <li>Root of a loaded image (jpg, png, gif) whose content is a Bitmap is the Bitmap. </li>    <li>If a DisplayObject is created by code and (for e.g. <font face="Courier New">new Sprite()</font>), its root is <font face="Courier New">null</font> until it is added to a container which has non-null root. (The container’s root will be passed to its child). The container is not necessary to be on stage. </li> </ul> <a name='more'></a>  <p>Besides, I have made some experiments to come up with some more conclusions:</p>  <ul>   <li>If we add a new display object directly to Stage (by pass document class), its root will be the Stage. </li>    <li>The root of document class is always itself even it is removed off stage (and then added again to stage) or even added to another display object which has a different root. </li> </ul>  <p>Below is my summary about <font face="Courier New">root</font>:</p>  <p><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/S_I8XHweQMI/AAAAAAAACkU/kTf992AyoP4/s1600-h/display_list_tree%5B7%5D.png"><img title="display list tree" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="385" alt="display list tree" src="https://lh4.ggpht.com/_47w2iQ8-NcE/S_I8cwcGMqI/AAAAAAAACkY/VbYWsX-FO0E/display_list_tree_thumb%5B6%5D.png?imgmax=800" width="538" border="0" /></a> </p>  <table cellspacing="0" cellpadding="0" width="500" border="0"><tbody>     <tr>       <td valign="top" width="200"><font face="Courier New">stage.root</font></td>        <td valign="top" width="300"><font face="Courier New">= stage</font></td>     </tr>      <tr>       <td valign="top" width="200"><font face="Courier New">documentClass.root</font></td>        <td valign="top" width="300"><font face="Courier New">= documentClass</font></td>     </tr>      <tr>       <td valign="top" width="200"><font face="Courier New">documentChild.root</font></td>        <td valign="top" width="300"><font face="Courier New">= documentClass</font></td>     </tr>      <tr>       <td valign="top" width="200"><font face="Courier New">stageChild.root</font></td>        <td valign="top" width="300"><font face="Courier New">= stage</font></td>     </tr>      <tr>       <td valign="top" width="200"><font face="Courier New">stageGrandChild.root</font></td>        <td valign="top" width="300"><font face="Courier New">= stage</font></td>     </tr>      <tr>       <td valign="top" width="200"><font face="Courier New">loadedDocumentClass.root</font> </td>        <td valign="top" width="300"><font face="Courier New">= loadedDocumentClass</font></td>     </tr>      <tr>       <td valign="top" width="200"><font face="Courier New">loadedChild.root</font> </td>        <td valign="top" width="300"><font face="Courier New">= loadedDocumentClass</font> </td>     </tr>   </tbody></table>  <p><font size="2">Download my experiment code </font><a title="Root Object Demo" href="http://www.fileden.com/files/2009/8/2/2530043/flash/TestRootObject.zip" target="_blank"><font size="2">here</font></a><font size="2">.</font></p>  <h4>Conclusion</h4>  <p>The <font face="Courier New">root</font> object is just an old revived property from ActionScript 2. But back then, since new movie clips must be instanciated from another existing movie clip, all <font face="Courier New">_root</font> properties will point to a single top-most display object, and hence <font face="Courier New">_root</font> reference is consistent.</p>  <p>In ActionScript 3, because of this inconsistence in object reference, I think <strong>we should AVOID using <font face="Courier New">root</font></strong> and should use other approaches to get your intended reference.</p>  <p><font size="1">[Vietnamese tags: Giải mã đối tượng root của DisplayObject, AS3]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Using Flash Proxy Class</title>
    <link href="https://int3ractive.com/blog/2010/using-flash-proxy-class/"/>
    <updated>2010-05-11T07:07:00Z</updated>
    <id>https://int3ractive.com/blog/2010/using-flash-proxy-class/</id>
    <content type="html"><![CDATA[
      
<p>According to <a href="http://livedocs.adobe.com/livecycle/8.2/programLC/common/langref/flash/utils/Proxy.html" target="_blank" rel="noopener">Adobe&rsquo;s Help</a>, the <strong>Proxy</strong> class (flash.utils.Proxy) lets you override the default behavior of ActionScript operations (such as retrieving and modifying properties) on an object.</p>

<p>The usage note sounds interesting but this is one of the least used classes in AS3. In fact there are some use cases of this class which prove it is extremely powerful and may help you save many lines of code. Some of those are:</p>
<ul>
<li>OrderedObject: an object whose properties order are strictly maintained.</li>
<li>TraversableObject: an object which allow you to traverse through its declared properties by using for loop.</li>
</ul>
<p>First let&rsquo;s see how to use it.</p>
<p>&nbsp;</p>
<h4>The Proxy Class</h4>
<p>The Proxy class is meant to be extended. In your own class definition, you must override some special methods of Proxy class which are responsible for some object operations in AS.</p>
<p>They are:</p>
<p>Override this when you want to set property, i.e MyObject.myProperty = &ldquo;something&rdquo;;</p>
<div>
<div>override flash_proxy functionsetProperty(name:*,value:*):void{ }</div>
</div>
<p>Override this when you want to get property, i.e trace(MyObject.myProperty);</p>
<div>
<div>override flash_proxy functiongetProperty(name:*):*{ }</div>
</div>
<p>Override these when you need to traverse through properties with for..in or for each..in</p>
<div>
<ol>
<li>
<div>override flash_proxy functionnextNameIndex(index:<a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html">int</a>):<a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html">int</a>{}&nbsp;</div>
</li>
<li>
<div>override flash_proxy functionnextName(index:<a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html">int</a>):<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>{}</div>
</li>
<li>
<div>override flash_proxy functionnextValue(index:<a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html">int</a>):*{}</div>
</li>
</ol>
</div>
<p>Override this when you call object&rsquo;s method hasOwnProperty()</p>
<div>
<div>override flash_proxy functionhasProperty(name:*):<a href="http://www.google.com/search?q=boolean%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:boolean.html">Boolean</a>{}</div>
</div>
<p>Override this when there&rsquo;s a need to delete properties with delete operator.</p>
<div>
<div>override flash_proxy functiondeleteProperty(name:*):<a href="http://www.google.com/search?q=boolean%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:boolean.html">Boolean</a>{}</div>
</div>
<p>Override this if you want to use descedant (..) operator with your object. Normally, the descendant operator only available in E4X objects. One example for this operation: you want to get MyObject..myProp which will recursively traverse through the object&rsquo;s properties and the properties&rsquo; properties etc. and return an array of values whose name is myProp</p>
<div>
<div>override flash_proxy functiongetDescendants(name:*):*{}</div>
</div>
<p>Please note:</p>
<ul>
<li>Your Proxy-extended class will have no default behaviour for object operations. Flash Player will throw exceptions for any operations that are not defined by you in your custom class.</li>
<li>Most of these operations only affect dynamic properties. For example: if you have a declared member &ldquo;prop&rdquo;, when you get obj.prop, your object will return the value of &ldquo;prop&rdquo; directly and the method getProperty() is not invoked.</li>
</ul>
<p>Let&rsquo;s take a look at some use cases to understand more about Proxy.</p>
<h4>OrderedObject (<a title="Link to source on Google Code" href="https://thanhtran-sources.googlecode.com/svn/trunk/demos/FlashProxy/src/org/thanhtran/model/data/OrderedObject.as" target="_blank" rel="noopener">source code</a>)</h4>
<p>As you may notice, when you iterate through an object with for loop, you don&rsquo;t access its properties in the order you created them. For example:</p>
<div>var obj:<a href="http://www.google.com/search?q=object%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:object.html">Object</a> = {a:1,b:2,c:3};<br />obj.d = 4;<br />obj.e = 5;<br />for(var prop:<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>in obj){<br /> trace(prop +" - "+ obj[prop]);// not in order 1, 2, 3, 4, 5 <br />}</div>
<p>This issue of order, most of the time, is acceptable. However, there are cases where the order of properties is very important. For example: a QueryString object which parse this string &ldquo;a=1&amp;b=2&amp;c=3&amp;d=4&amp;e=5&rdquo; and hold all the values in its dynamic properties. Unfortunately, when you iterate the properties list and return the string back, the output are not the same with input anymore. Imagine you use this class to work with <a href="http://www.asual.com/swfaddress/" target="_blank" rel="noopener">SWFAddress</a>, you will get 2 different URLs for the same page access (the browser will see http://yourdomain.com/?a=1&amp;b=2&amp;c=3&amp;d=4&amp;e=5 different from http://yourdomain.com/?c=3&amp;d=4&amp;a=1&amp;e=5&amp;b=2).</p>
<p>With <strong>OrderedObject </strong>and its extension <strong>QueryString</strong>, I can solve the above issue.</p>
<p>OrderedObject example:</p>
<div>import org.thanhtran.model.data.OrderedObject;<br /><br />var obj: OrderedObject = new OrderedObject(["a",1,"b",2,"c",3]);<br />obj.d = 4;<br />obj.e = 5;<br />for(var prop:<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>in obj){<br /> trace(prop +" - "+ obj[prop]);//in order a &ndash; 1, b &ndash; 2, c &ndash; 3, d &ndash; 4, e &ndash; 5 <br />}</div>
<p>QueryString example:</p>
<div>import org.thanhtran.model.data.QueryString; <br /><br />var query: QueryString = new QueryString("a=1&amp;b=2&amp;c=3&amp;d=4&amp;e=5");<br />trace(query.toString());//a=1&amp;b=2&amp;c=3&amp;d=4&amp;e=5 <br />//change parameters <br />query.a = "one";<br />query.e = "five";<br />trace(query.toString());//a=one&amp;b=2&amp;c=3&amp;d=4&amp;e=five</div>
<h4>TraversableObject (<a title="Link to source on Google Code" href="https://thanhtran-sources.googlecode.com/svn/trunk/demos/FlashProxy/src/org/thanhtran/model/data/TraversableObject.as" target="_blank" rel="noopener">source code</a>)</h4>
<p>Say, your project may have a few data objects (AKA value objects) which are used to transfer data among components. There a times you want to iterate through their properties list to quickly copy the values or something. However, it is impossible to use for..in and for each..in statement to iterate declared properties.</p>
<p>By extending <strong>TraversableObject</strong> (which is an implementation of Proxy), your object properties can now be iterated through with for loop.</p>
<p>Here&rsquo;s how:</p>
<div>publicclass MyObject extends TraversableObject {<br /> publicvar a:<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a> = "1";<br /> publicvarb:<a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html">int</a> = 2;<br /> publicvarc:<a href="http://www.google.com/search?q=number%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:number.html">Number</a> = 3;<br /><br /> publicfunction MyObject(){<br /> //list all the public properties you want to iterate here <br /> //DO NOT list private or dynamic ones <br /> propertyList = ["a","b","c"];<br /> }<br />}<br />/* &hellip; */<br />var obj: MyObject = new MyObject();<br />for(var prop:<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>in obj){<br /> trace(prop +" - "+ obj[prop]);//in order a &ndash; 1, b &ndash; 2, c &ndash; 3 <br />}<br />&nbsp;</div>
<p>You can check out the demo FlashDevelop project <a href="https://thanhtran-sources.googlecode.com/svn/trunk/demos/FlashProxy" target="_blank" rel="noopener">here</a>.</p>
<p>These are just some practical applications of Proxy class, I think there must be plenty of circumstances where this special class proves useful.</p>
<p>[Vietnamese tags: Sử dụng lớp Proxy của Flash: thay đổi c&aacute;ch truy xuất v&agrave; c&aacute;c thao t&aacute;c l&ecirc;n đối tượng trong ActionScript]</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Featured Presentation – Quick As A Flash</title>
    <link href="https://int3ractive.com/blog/2010/featured-presentation-quick-as-flash/"/>
    <updated>2010-05-04T17:04:00Z</updated>
    <id>https://int3ractive.com/blog/2010/featured-presentation-quick-as-flash/</id>
    <content type="html"><![CDATA[
      
<p>“One hundred slides on Flash optimization, covering general theory, code, media, and graphics,” by <a href="http://gskinner.com/blog/archives/2004/06/conference_sess.html" target="_blank">Grant Skinner</a>.</p>  <p><a title="Click to open the slides in a new window" href="http://gskinner.com/talks/quick" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Click to open the slides in a new window" border="0" alt="Click to open the slides in a new window" src="https://lh4.ggpht.com/_47w2iQ8-NcE/S-BThA5DP0I/AAAAAAAACkM/Q43Ki1m4kpA/quick_as_flash_1%5B4%5D.jpg?imgmax=800" width="404" height="304" /></a> </p>  <p>These slides are recommended to any Flasher who seeks for serious code optimization and extreme performance improvement.</p>  <p>Note: When entering the page, press Left or Right to navigate the slides.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Links about Flash vs others</title>
    <link href="https://int3ractive.com/blog/2010/links-about-flash-vs-others/"/>
    <updated>2010-04-22T19:16:00Z</updated>
    <id>https://int3ractive.com/blog/2010/links-about-flash-vs-others/</id>
    <content type="html"><![CDATA[
      
<p><img style="display: block; float: none; margin-left: auto; margin-right: auto" src="http://overtlyopen.com/cartoons/f-2010-03-21-evolution-death-flash.png" width="400" height="293" /> </p>  <p>Since the event that Flash is not supported by Apple’s latest “magical” gadget – the iPad, there came a lot of debates with Flash platform against others, from HTML5 (the biggest), to it’s poor performance on MAC/iPhone OS and even to user experiences in touch devices,…</p>

<p>This post of mine is to bookmark any interesting read related to or address those debates, especially, the so-called “The Great Flash vs HTML5 Debate of 2010”. I admit that I’m bias so maybe most of the links here are pro-Flash. Anyway, you can read the comments for counter-arguments but I’ve seen a lot of *bullshit* yell-outs against Flash with no proof or reasonable points at all.</p>  <p>I’ll update this post regularly whenever I come across any read-worthy articles (and sort them in chronological order).</p> <a name='more'></a>

<ul>
<li><strong>Kevin Lynch&rsquo;s </strong><a href="http://blogs.adobe.com/conversations/2010/02/open_access_to_content_and_app.html" target="_blank" rel="noopener"><strong>Open Access to Content and Applications</strong></a> &ndash; 2010-02-02 <br /> &ldquo;The Flash team will drive innovation over the coming years as they have over the past decade to enable experiences that aren't otherwise possible. With the ability to update the majority of Web clients in less than a year, Flash can make this innovation available to our customers much more quickly than HTML across a variety of browsers.&rdquo;<br />Follow up the post, Kevin has a <a href="http://blogs.adobe.com/conversations/2010/02/open_access_to_content_and_app.html#comment-2137153" target="_blank" rel="noopener">comment</a> reveal Flash team effort to prevent crash: <br /> &ldquo;Before we release a new version of Flash Player we run more than 100,000 test cases and have built an automated system that has scanned over 1 million SWFs that we use for testing from across the web. Our QA lab has a very large variety of machines to represent the machines in real use on the web.&rdquo;</li>
<li><strong>**** Grant Skinner&rsquo;s </strong><a href="http://www.gskinner.com/blog/archives/2010/02/my_thoughts_on.html" target="_blank" rel="noopener"><strong>thought on the future of Flash</strong></a> &ndash; 2010-02-03 <br /> &rdquo;This skill set is applicable to so many things: WPF on Windows, Cocoa development on Mac / iPhone (ex. Core Animation), Silverlight, mobile development, and of course the emerging HTML 5 standard. Languages are easy to learn - mental models, process, and the experience gained from years of working with rich interactive are a whole lot harder.&rdquo;</li>
<li><strong>** Jeremy Allaire on TechCrunch&rsquo;s </strong><a href="http://techcrunch.com/2010/02/05/the-future-of-web-content-html5-flash-mobile-apps/" target="_blank" rel="noopener"><strong>The Future of Web Content &ndash; HTML5, Flash &amp; Mobile Apps</strong></a> &ndash; 20010-02-05 <br /> &ldquo;&hellip;Likewise, and more important, whatever standards and models deliver the broadest reach will ultimately drive what is adopted by publishers, developers and ISVs.&rdquo;</li>
<li><strong>Tinic Uro&rsquo;s </strong><a href="http://www.kaourantin.net/2010/02/core-animation.html" target="_blank" rel="noopener"><strong>Core Animation</strong></a> &ndash; 2010-02-11 (Flash Player technical) <br /> &ldquo;Flash Player 10.1 implements the Core Animation drawing model to fix [issue of sharing performance with HTML renderer], among others.&rdquo;</li>
<li><strong>Mike Chamber&rsquo;s </strong><a href="http://www.mikechambers.com/blog/2010/02/22/flash-player-content-mouse-events-and-touch-input/" target="_blank" rel="noopener"><strong>Flash Player content, Mouse Events, and Touch input</strong></a> &ndash; 2010-02-22 &ndash; in response to Daniel Eran Dilger&rsquo;s <a href="http://www.roughlydrafted.com/2010/02/20/an-adobe-flash-developer-on-why-the-ipad-cant-use-flash/" target="_blank" rel="noopener">An Adobe Flash developer on why the iPad can&rsquo;t use Flash</a><br /> &ldquo;Hover events do work in Flash content on touch devices. Any issues with mouse input on a touch device are not specific to Flash, but affect all content, including HTML based content.&rdquo;</li>
<li><strong>** Matt Kenefick&rsquo;s </strong><a href="Strictly Democratic Tools Build Boredom and Disinterest" target="_blank" rel="noopener"><strong>Strictly Democratic Tools Build Boredom and Disinterest</strong></a> &ndash; 2010-04-20 <br /> &ldquo;There are situations where Javascript is more suitable, there are situations where Flash is better, and there are also situations where Silverlight shines. *pun* To say that you're strictly an "X Developer," is just limiting your own abilities and forgoing your complete potential as a developer.&rdquo;</li>
<li><strong>Mike Chamber&rsquo;s </strong><a href="http://www.mikechambers.com/blog/2010/04/20/on-adobe-flash-cs5-and-iphone-applications/" target="_blank" rel="noopener"><strong>On Adobe, Flash CS5 and iPhone Applications</strong></a> &ndash; 2010-04-20 <br /> &ldquo;Essentially, [Apple&rsquo;s iPhone SDK 4.0 license &ndash; section 3.3.1 ] has the effect of restricting applications built with a number of technologies, including Unity, Titanium, MonoTouch, and Flash CS5. [&hellip;] <br />We will still be shipping the ability to target the iPhone and iPad in Flash CS5. However, we are not currently planning any additional investments in that feature.&rdquo;</li>
<li><strong>*** Branden Hall&rsquo;s </strong><a href="http://www.waxpraxis.org/blog/2010/04/little-boxes-in-the-browser/" target="_blank" rel="noopener"><strong>Little Boxes in the Browsers</strong></a><strong>&hellip;</strong> &ndash; 2010-04-21 <br /> &ldquo;Like it or not, the web, for many, many people, is just an entertainment medium. HTML still has ways to go to match the kind of entertainment you can build with Flash.&rdquo;</li>
<li><strong>Serge Jespers&rsquo;s </strong><a href="http://www.webkitchen.be/2010/04/22/flash-is-as-open-as-html5/" target="_blank" rel="noopener"><strong>Flash is as open as HTML 5</strong></a> &ndash; 2010-04-22 <br /> &ldquo;[HTML5, CSS and JavaScript] are open, right? Well yeah. The specs are open meaning that everyone can download those specs and build an application around it to display that language. [&hellip;] That sounds a lot like Flash! The specs for [FLV, SWF, AMF and RTMP] are all published and can be downloaded by anyone.&rdquo;</li>
<li><strong>Steve Jobs&rsquo; </strong><a href="http://www.apple.com/hotnews/thoughts-on-flash/" target="_blank" rel="noopener"><strong>Thoughts on Flash</strong></a> &ndash; 2010-04-29 <br />(Apple&rsquo;s official explanation why Flash is not available on iDevices) <br /> &ldquo;New open standards created in the mobile era, such as HTML5, will win on mobile devices (and PCs too). Perhaps Adobe should focus more on creating great HTML5 tools for the future, and less on criticizing Apple for leaving the past behind.&rdquo;</li>
<li><strong>Jesse Warden&rsquo;s </strong><a href="http://jessewarden.com/2010/04/steve-jobs-on-flash-correcting-the-lies.html" target="_blank" rel="noopener"><strong>Steve Jobs on Flash: Correcting the Lies</strong></a>&ndash; 2010-04-29 <br /> &ldquo;Apple has posted Steve Jobs&rsquo; &ldquo;Thoughts on Flash&ldquo;. There are a lot of lies and half truths. No one will care. The article has enough valid points that people won&rsquo;t check up on them.&rdquo; <br />Another post addressing Steve Jobs&rsquo; letter is: Steve McDonald&rsquo;s <a href="http://enginpost.com/blogs/development/2010-may/apple-steve-jobs-letter-rebuttle" target="_blank" rel="noopener">Apple Steve Jobs Letter Rebuttal</a> (2010-05-02).</li>
</ul>

<p>[Updated 2010-05-09]</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Simple AS3 Line Smoothing</title>
    <link href="https://int3ractive.com/blog/2010/simple-as3-line-smoothing/"/>
    <updated>2010-04-20T06:02:00Z</updated>
    <id>https://int3ractive.com/blog/2010/simple-as3-line-smoothing/</id>
    <content type="html"><![CDATA[
      
<p>While researching for drawing tools, I’ve come up with a simple implementation of a pencil tool and line smoothing.</p> <p>Here’s the idea:</p> <ul> <li>Capture the points drawn by pencil tool in an array.  <li>Filter a new points array from the original one by skipping points in the middle (to reduce turns &amp; angles)  <li>Finally, use a simple point-to-point curve drawing algorithm. I use sample code from <a href="http://www.gskinner.com/blog/archives/2008/05/drawing_curved.html" target="_blank">this article</a> by gskinner.com </li></ul> <p>The result:</p> <p><a title="Line Smoothing Demo" href="http://www.fileden.com/files/2009/8/2/2530043/flash/line_smoothing.swf" rel="shadowbox;width=800;height=600"><img title="Click to view the demo" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="314" alt="Click to view the demo" src="https://lh6.ggpht.com/_47w2iQ8-NcE/S81DhcR3WoI/AAAAAAAACkI/VPSjEf3Hjeo/line_smoothing_demo_thumb1.jpg?imgmax=800" width="444" border="0"></a> </p> <p>You can find the source of this demo <a href="https://thanhtran-sources.googlecode.com/svn/trunk/demos/DrawingTools/src/org/thanhtran/drawing/TestPencil.as" target="_blank">here</a>.</p> <p><font size="1">[Vietnamese tag: Làm mượt nét vẽ đơn giản với ActionScript]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>as3signals: new approach for AS3 Events</title>
    <link href="https://int3ractive.com/blog/2010/as3signals-new-approach-for-as3-events/"/>
    <updated>2010-03-28T15:24:00Z</updated>
    <id>https://int3ractive.com/blog/2010/as3signals-new-approach-for-as3-events/</id>
    <content type="html"><![CDATA[
      
<p>There are times you may find that the built-in events of AS3 are limited and even troublesome. Here are some circumstances that EventDispatchers turn against developers:</p>

<ol>
	<li><strong>Objects MUST extend EventDispatcher</strong> in order to be able to dispatch events. Implementing IEventDispatcher alone is impossible because the event target is read-only and you cannot change it from outside of EventDispatcher.</li>
	<li><strong>It&rsquo;s difficult to manage events</strong>. There&rsquo;s no way you can remove all event handlers attached to an event dispatcher at once. So in some cases, you don&rsquo;t remove them properly and they start causing bugs. (BTW, using weak references is not reliable and not recommended.)</li>
	<li>You<strong> cannot pass extra data to you listener</strong> unless you extends a new Event object</li>
	<li>You<strong> cannot set up your interface</strong> in a way that it can enforce implementing classes to dispatch the required events.</li>
	<li>On performance perspective, creating objects is one of the most evil things. That&rsquo;s why any advanced programmers must know and practically use objects pool. However, we are still<strong> wasting a lot of resources creating event objects</strong>, especially repetitive events like mouse move or enter frame.</li>
	<li>Read <a href="http://robertpenner.com/flashblog/2009/09/my-critique-of-as3-events-part-2.html" target="_blank" rel="noopener">here</a> for more critiques on AS3 events</li>
</ol>
<p>So in order to address those issues, <a href="http://robertpenner.com/flashblog/" target="_blank" rel="noopener">Robert Penner</a> has adopted an alternative to AS3 events namely <a href="http://github.com/robertpenner/as3-signals" target="_blank" rel="noopener">as3signals</a>. (Follow the link for more info and get the library) <br />Here&rsquo;s the briefing from <a href="http://wiki.github.com/robertpenner/as3-signals/" target="_blank" rel="noopener">as3signals wiki page</a>:</p>
<blockquote><strong>Signals: Think Outside the Event.</strong><br />Signals are light-weight, strongly-typed AS3 messaging tools. <br />Wire your application with better APIs and less boilerplate than AS3 Events. <br /><strong>Concept</strong><br />
<ul>
	<li>A Signal is essentially a mini-dispatcher specific to one event, with its own array of listeners.</li>
	<li>A Signal gives an event a concrete membership in a class.</li>
	<li>Listeners subscribe to real objects, not to string-based channels.</li>
	<li>Event string constants are no longer needed.</li>
	<li>Signals are inspired by C# events and signals/slots in Qt.</li>
</ul>
</blockquote>
<p>Let&rsquo;s see how as3signals gains advantages over AS3 events:</p>
<h4>1. Any object can dispatch events</h4>
<p>Here&rsquo;s how you create an event dispatching object with Signals:</p>
<div>
<ol>
<li>
<div>import org.osflash.signals.Signal;</div>
</li>
<li>
<div>publicclass Radio {</div>
</li>
<li></li>
<li>
<div>&nbsp;&nbsp;&nbsp; // This is the public API to which listeners subscribe.</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicvar messageChanged:Signal;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; privatevar _message:<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicfunction Radio(){</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create a Signal that dispatches a String.</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; messageChanged = new Signal(<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>);</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicfunctiongetmessage():<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>{return _message;}</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; // The setter uses the Signal to dispatch the changed value.</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; publicfunctionsetmessage(value:<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>):void{</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _message = value;</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; messageChanged.dispatch(_message);</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; }</div>
</li>
<li>
<div>}</div>
</li>
</ol>
</div>
<p>Here&rsquo;s how you add event listeners:</p>
<div>
<ol>
<li>
<div>var radio: Radio = new Radio();</div>
</li>
<li>
<div>// Hook the listener up to the Radio's Signal.</div>
</li>
<li>
<div>radio.messageChanged.add(messageChangedHandler);</div>
</li>
<li></li>
<li>
<div>function messageChangedHandler(message:<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>):void{</div>
</li>
<li>
<div>&nbsp;&nbsp;&nbsp; trace("heard message: "+message);</div>
</li>
<li>
<div>}</div>
</li>
</ol>
</div>
<h4>2. With signals, managing events is much less hassle</h4>
<p>You can remove all event handlers with one convenient method:</p>
<div>signal.removeAll();</div>
<p>You can retrieve number of listeners:</p>
<div>signal.numListeners;</div>
<p>You can add a listener that will be removed automatically after just one event:</p>
<div>signal.addOnce(theListener);// result: signal has one listener<br />signal.dispatch(theEvent);&nbsp;&nbsp; // result: theListener is called, signal now has no listeners</div>
<h4>3. You can dispatch with any number of arguments to listener</h4>
<p>You can define types for your arguments</p>
<div>// A Signal that will dispatch a String and an integer:<br />progress = new Signal(<a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html">String</a>,<a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html">int</a>);</div>
<p>Later on, when you dispatch events, as3signals can detect and notify argument error</p>
<div>//later:<br />progress.dispatch();// will throw ArgumentError <br />progress.dispatch('The Answer');// will throw ArgumentError <br />progress.dispatch('The Answer',42.5);// will throw ArgumentError <br />progress.dispatch('The Answer',42);// will succeed</div>
<p>When adding listeners, they are all so checked for argument types.</p>
<h4>4. It&rsquo;s possible that you enforce events in interface</h4>
<p>To see an example, please follow this link <a title="http://snipt.org/wSm" href="http://snipt.org/wSm">http://snipt.org/wSm</a></p>
<h4>5. It&rsquo;s performance gain because no event object is created in Signals</h4>
<p>But that&rsquo;s not everything yet. The ultimate deal is to replace ENTER_FRAME event. <br />As we know that ENTER_FRAME event is the key to time-based animations and are widely used. Normally, ENTER_FRAME event can create 25 &ndash; 30 objects per second, that&rsquo;s 1500-1800 objects per minute. But we are aware that that creating objects is evil. So some guys have tried to replace the ENTER_FRAME event with Signals. Read <a href="http://alecmce.com/as3/replacing-enter_frame" target="_blank" rel="noopener">this blog</a> for more info. (The site is currently down, so please use this <a href="http://74.125.153.132/search?q=cache:z4_I5r8RVZkJ:alecmce.com/as3/replacing-enter_frame+http://alecmce.com/as3/replacing-enter_frame&amp;cd=1&amp;hl=vi&amp;ct=clnk&amp;gl=vn" target="_blank" rel="noopener">cache from Google</a>)</p>
<h4>6. Signals only projects</h4>
<p>Signals can wrap the native events of AS3 so that the whole project will use a consistent messaging system for communication between components. For example:</p>
<div>varclick:NativeSignal = new NativeSignal(this,<a href="http://www.google.com/search?q=mouseevent%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:mouseevent.html">MouseEvent</a>.CLICK,<a href="http://www.google.com/search?q=mouseevent%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:mouseevent.html">MouseEvent</a>);</div>
<p>The author also claimed that he&rsquo;s experimenting <a href="http://wiki.github.com/robertpenner/as3-signals/features" target="_blank" rel="noopener">the bubble feature</a> (the ability to forward events among objects in display list).</p>
<h4>Conclusion</h4>
<p>It is still under development and improvement but as3signals&rsquo; current feature set can satisfy most common project&rsquo;s needs. Some guys even love it so much that they branch some frameworks to work purely with Signals, for example:</p>
<ul>
<li><a href="http://github.com/piercer/puremvc-as3-multicore/tree/as3Signals" target="_blank" rel="noopener">PureMVC AS3 Multicore &ndash; as3signal branch</a></li>
<li><a href="http://richtextformat.co.uk/blog/?p=445" target="_blank" rel="noopener">RobotSignals &ndash; RobotLegs &amp; as3signals combination</a></li>
<li><a href="http://www.kilometer0.com/blog/code/swfaddress-and-as3signals/" target="_blank" rel="noopener">SWFAddress as3signals version</a></li>
<li>See more examples <a href="http://wiki.github.com/robertpenner/as3-signals/community-examples" target="_blank" rel="noopener">here</a></li>
</ul>
<p>For now, I see no shortcomings of signals but I&rsquo;m still skeptical that there might be some disadvantages compared to AS3 events because nothing is perfect. (Please help me pointing them out) <br />Anyway, it is worth trying as3signals in my upcoming projects to see if it really &lsquo;shines&rsquo; in real applications. <br />(Credit: some of the sample code are revised from this <a href="http://wiki.github.com/robertpenner/as3-signals/hello-world" target="_blank" rel="noopener">Hello World example</a>) <br />[Vietnamese tags: as3signals: c&aacute;ch tiếp cận mới cho sự kiện (event) trong AS3]</p>
<p>Generate div table elements with <a href="https://divtable.com/table-styler/" target="_blank" rel="noopener">this table generator</a>, a free online tool! It is also capable of generating and convert grid elements.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>AS3 Type Conversion &amp; Common Mistakes</title>
    <link href="https://int3ractive.com/blog/2010/as3-type-conversion-common-mistakes/"/>
    <updated>2010-03-21T12:41:00Z</updated>
    <id>https://int3ractive.com/blog/2010/as3-type-conversion-common-mistakes/</id>
    <content type="html"><![CDATA[
      
<p>In this article, I’ll discuss some common mistakes that AS3 developers (including myself) often make when working with (implicit) type conversion.</p>

<h4>1. Check whether a dynamic property is set</h4>  <p>Dynamic properties can be added to dynamic object at run-time. Consequently, there’s often a need to test whether they are set before using them.</p>  <p>Here’s how some developers do it:</p>  <div class="actionscript3">   <ol>     <li class="li1">       <div class="de1"><span class="kw2">var</span> initObj<span class="sy0">:</span> <a href="http://www.google.com/search?q=object%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:object.html"><span class="kw5">Object</span></a> = <span class="br0">{</span>embed<span class="sy0">:</span> <span class="kw1">true</span><span class="sy0">,</span> <span class="kw7">color</span><span class="sy0">:</span> 0xFF0000<span class="sy0">,</span> <span class="kw7">text</span><span class="sy0">:</span> <span class="st0">&quot;Hello&quot;</span> <span class="br0">}</span><span class="sy0">;</span> </div>     </li>      <li class="li1">       <div class="de1"><span class="co2">/* ... */</span>&#160;</div>     </li>      <li class="li1">       <div class="de1"><span class="kw1">if</span> <span class="br0">(</span>initObj<span class="sy0">.</span>embed<span class="br0">)</span> <span class="br0">{</span> <span class="co2">/*apply embed*/</span> <span class="br0">}</span> </div>     </li>      <li class="li1">       <div class="de1"><span class="kw1">if</span> <span class="br0">(</span>initObj<span class="sy0">.</span><span class="kw7">color</span><span class="br0">)</span> <span class="br0">{</span> <span class="co2">/*apply this color*/</span> <span class="br0">}</span> </div>     </li>      <li class="li2">       <div class="de2"><span class="kw1">if</span> <span class="br0">(</span>initObj<span class="sy0">.</span><span class="kw7">text</span><span class="br0">)</span> <span class="br0">{</span> <span class="co2">/*apply this text*/</span> <span class="br0">}</span></div>     </li>   </ol> </div>  <p>The first test with Boolean is ok. But be careful when the input for color is black (0x000000) or the text is empty (“”). In that case, <strong>zeros and empty strings casted to Boolean equal <font color="#0000ff" face="Courier New">false</font></strong>, and definitely the code will run incorrectly.</p>  <p>So, the best practice to check whether a dynamic property is set is to do as following:</p>  <div class="actionscript3">   <ol>     <li class="li1">       <div class="de1"><span class="kw1">if</span> <span class="br0">(</span>initObj<span class="sy0">.</span>embed <span class="sy0">!</span>= <span class="kw1">undefined</span><span class="br0">)</span> </div>     </li>      <li class="li1">       <div class="de1"><span class="kw1">if</span> <span class="br0">(</span>initObj<span class="sy0">.</span><span class="kw7">color</span> <span class="sy0">!</span>= <span class="kw1">undefined</span><span class="br0">)</span> </div>     </li>      <li class="li1">       <div class="de1"><span class="kw1">if</span> <span class="br0">(</span>initObj<span class="sy0">.</span><span class="kw7">text</span> <span class="sy0">!</span>= <span class="kw1">undefined</span><span class="br0">)</span></div>     </li>   </ol> </div> <a name='more'></a> <h4>2. Check whether an (E4X) XML node exists</h4>  <p>Given an XML like this:</p>  <div class="actionscript3"><span class="kw2">var</span> xml<span class="sy0">:</span> <a href="http://www.google.com/search?q=xml%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:xml.html"><span class="kw5">XML</span></a> =     <br />&lt;data&gt;     <br />&#160;&#160; &lt;book id=”b001”&gt;     <br />&#160;&#160;&#160;&#160;&#160; &lt;title&gt;Flash CS4&lt;/title&gt;     <br />&#160;&#160;&#160;&#160;&#160; &lt;author&gt;&lt;/author&gt;     <br />&#160;&#160; &lt;/book&gt;     <br />&lt;/data&gt;; </div>  <p>Since AS3, E4X has enabled a very neat way to select and get data from XML, something like:</p>  <div class="actionscript3"><span class="kw2">var</span> title<span class="sy0">:</span> <a href="http://www.google.com/search?q=string%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:string.html"><span class="kw5">String</span></a> = xml<span class="sy0">.</span>book<span class="sy0">.</span><span class="br0">(</span>@id==<span class="st0">&quot;b001&quot;</span><span class="br0">)</span><span class="sy0">.</span>title<span class="sy0">;</span> </div>  <p>However, because it is so compact, many developers don’t realize there are a lot of implicit type conversions beneath.</p>  <p>They often check for the existence of a node by writing:</p>  <div class="actionscript3">if (xml.book.price)</div>  <p>Or check whether an element has data:</p>  <div class="actionscript3">if (xml.book.author)</div>  <p>Of even check whether an element exists with conditional selection:</p>  <div class="actionscript3">if (xml.book.(@id==&quot;b013&quot;))</div>  <p>They often assume that these XPath selections will return null or undefined if the elements/nodes don’t exist.</p>  <p>In fact,<strong> these tests always return <font color="#0000ff" face="Courier New">true</font> because for any XPath query in E4X, they always return an XMLList object</strong>. Obviously, if the selected element doesn’t exist, the XMLList object doesn’t have any child. And if the element exists but have no child or text value, it will return empty string “” when casted to String.</p>  <p>So the best practice to check for XML element is to write as following:</p>  <div class="actionscript3">if (xml.book.price[0]);&#160; <br /><font color="#008000">/* OR */</font>     <br />if (xml.book.price.toString());</div>  <p>For conditional selection, [0] notation is preferable because the condition may (by mistake) return more than one matched elements.</p>  <h4>3. Get Boolean value from String:</h4>  <p>Wrong:</p>  <div class="actionscript3">   <ol>     <li class="li1">       <div class="de1"><span class="co1">//even the flashvar equal “false”, any non-empty string will be casted to Boolean as true </span></div>     </li>      <li class="li1">       <div class="de1"><span class="kw2">var</span> autoPlay<span class="sy0">:</span> <a href="http://www.google.com/search?q=boolean%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:boolean.html"><span class="kw5">Boolean</span></a> = <span class="kw1">this</span><span class="sy0">.</span><span class="kw7">loaderInfo</span><span class="sy0">.</span><span class="kw7">parameters</span><span class="br0">[</span><span class="st0">&quot;autoPlay&quot;</span><span class="br0">]</span><span class="sy0">;</span></div>     </li>   </ol> </div>  <p>Right:</p>  <div class="actionscript3">   <ol>     <li class="li1">       <div class="de1"><span class="kw2">var</span> autoPlay<span class="sy0">:</span> <a href="http://www.google.com/search?q=boolean%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:boolean.html"><span class="kw5">Boolean</span></a> = <span class="br0">(</span><span class="kw1">this</span><span class="sy0">.</span><span class="kw7">loaderInfo</span><span class="sy0">.</span><span class="kw7">parameters</span><span class="br0">[</span><span class="st0">&quot;autoPlay&quot;</span><span class="br0">]<span class="sy0">.</span><span class="kw7">toLowerCase()</span></span> == <span class="st0">&quot;true&quot;</span><span class="br0">)</span> <span class="sy0">?</span> <span class="kw1">true</span> <span class="sy0">:</span> <span class="kw1">false</span><span class="sy0">;</span></div>     </li>   </ol> </div>  <h4>Reference:</h4>  <ul>   <li><a href="http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f87.html" target="_blank">Adobe Help – Type Conversion</a> </li>    <li><a href="http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f9d.html" target="_blank">Adobe Help – Variables &amp; default values</a> </li>    <li><a href="http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e6b.html" target="_blank">Adobe Help – Traversing XML</a> </li> </ul>  <p><font size="1">[Vietnamese tag – Chuyển đổi kiểu dữ liệu trong AS3 và một số lỗi thường gặp]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Featured Presentation - Moving from Flex 3 to Flex 4</title>
    <link href="https://int3ractive.com/blog/2010/featured-presentation-moving-from-flex/"/>
    <updated>2010-03-19T16:15:00Z</updated>
    <id>https://int3ractive.com/blog/2010/featured-presentation-moving-from-flex/</id>
    <content type="html"><![CDATA[
      
This screen cast is from <a href="http://tv.adobe.com/watch/max-2009-develop/moving-from-flex-3-to-flex-4/">tv.adobe.com</a>. Any Flex guys should watch it.<div><br />
<object height="256" width="425"><param name="movie" value="http://images.tv.adobe.com/swf/player.swf"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="FlashVars" value="fileID=2466&context=162&embeded=true&environment=production"></param><embed src="http://images.tv.adobe.com/swf/player.swf" flashvars="fileID=2466&context=162&embeded=true&environment=production" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="256"></embed></object></div>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Case Study Isometric Multi-player Virtual World</title>
    <link href="https://int3ractive.com/blog/2010/case-study-isometric-multi-player/"/>
    <updated>2010-03-12T15:30:00Z</updated>
    <id>https://int3ractive.com/blog/2010/case-study-isometric-multi-player/</id>
    <content type="html"><![CDATA[
      
<p><a href="https://lh4.ggpht.com/_47w2iQ8-NcE/S5peICy1GKI/AAAAAAAACkA/5h-pfGQ02W4/s1600-h/mattel%5B4%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="mattel" border="0" alt="mattel" src="https://lh3.ggpht.com/_47w2iQ8-NcE/S5peJdFzITI/AAAAAAAACkE/3BlEO45EeCw/mattel_thumb%5B2%5D.jpg?imgmax=800" width="504" height="328" /></a> </p>  <p>This is my team’s <a href="http://demo.pyramid-consulting.com/3dvirtualworld/index.html" target="_blank">case study</a> to demonstrate our capability to build a MMORPG (Massively Multiplayer Online Role Playing Game). The site features 2.5D isometric scene and realtime multiplayer virtual world utilizing <a href="http://www.smartfoxserver.com/" target="_blank">SmartFox</a> server.</p>  <p>My role: key researcher, team leader</p>  <p>Tech notes:</p>  <ul>   <li>Flash Player 9 / Actionscript 3</li>    <li><a href="http://code.google.com/p/as3isolib/" target="_blank">AS3IsoLib</a> Isometric engine</li>    <li><a href="http://code.google.com/p/red5/" target="_blank">Red5</a> server (in first phase)</li>    <li>SmartFox multiplayer server (Java backend)</li> </ul>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project ASB Minisites</title>
    <link href="https://int3ractive.com/blog/2010/project-asb-minisites/"/>
    <updated>2010-03-12T14:32:00Z</updated>
    <id>https://int3ractive.com/blog/2010/project-asb-minisites/</id>
    <content type="html"><![CDATA[
      
<p><a href="https://lh6.ggpht.com/_47w2iQ8-NcE/S5pQSlvRYRI/AAAAAAAACjo/54-0LPiEXtM/s1600-h/image13.jpg"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="ASB Horsemen Minisite" border="0" alt="ASB Horsemen Minisite" src="https://lh5.ggpht.com/_47w2iQ8-NcE/S5pQTkqY-5I/AAAAAAAACjs/gsT1P5QzR9A/image1_thumb1.jpg?imgmax=800" width="404" height="266" /></a> </p><p>This is an all-flash minisite for a key flying <a href="http://www.asb.tv/horsemen" target="_blank">performer team</a> from Air Show Buzz community. This site is to deliver videos, photos and other information related to the team in a centralized and convenient way. The site features PureMVC framework in the front-end flash site and PHP as backend services. The site was designed in a way that new contents and panels can be added/removed dynamically, and theme color can be changed via XML-based site config. (In fact, with the same swfs, it has been cloned into a few other minisites.)</p>

<p>My role: Technical leader</p>  <p>Tech notes:</p>  <ul>   <li>Flash 9 / Actionscript 3 </li>    <li>PureMVC framework </li>    <li>Flash CS3 &amp; Flex SDK workflow </li>    <li>Clearspring sharing service </li>    <li>Google Map API for Flash </li> </ul>  <p><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/S5pQUu0oFaI/AAAAAAAACjw/A3-Tz1Q8NTU/s1600-h/image22.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image2" border="0" alt="image2" src="https://lh4.ggpht.com/_47w2iQ8-NcE/S5pQVa8olzI/AAAAAAAACj0/TdTm0KmqjpY/image2_thumb.jpg?imgmax=800" width="244" height="160" /></a> <a href="https://lh3.ggpht.com/_47w2iQ8-NcE/S5pQXqfib6I/AAAAAAAACj4/Bu70SWS-xyA/s1600-h/image72.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image7" border="0" alt="image7" src="https://lh3.ggpht.com/_47w2iQ8-NcE/S5pQYlOW6qI/AAAAAAAACj8/FL70atTeM2Y/image7_thumb.jpg?imgmax=800" width="244" height="160" /></a></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project Smile Shutter</title>
    <link href="https://int3ractive.com/blog/2010/project-smile-shutter/"/>
    <updated>2010-03-12T13:32:00Z</updated>
    <id>https://int3ractive.com/blog/2010/project-smile-shutter/</id>
    <content type="html"><![CDATA[
      
<p><a href="https://lh3.ggpht.com/_47w2iQ8-NcE/S5pCLRGTraI/AAAAAAAACjA/wPotG4UrHm0/s1600-h/2010-02-23_100521%5B5%5D.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="Smile Shutter" border="0" alt="Smile Shutter" src="https://lh5.ggpht.com/_47w2iQ8-NcE/S5pCOC4aXbI/AAAAAAAACjE/syKum8zKr_I/2010-02-23_100521_thumb%5B3%5D.png?imgmax=800" width="404" height="291" /></a>&#160;</p>  <p>This is a another key <a href="http://www.sonyericsson.com/smileshutter" target="_blank">campaign site</a> (2009) for Sony Ericsson to show off their latest mobile phones with smile capture technology (C510, C903). Apart from Flex and Cairngorm framework, this site features SOAP service communication and complicated back office management to handle a big photo gallery and users database. The site is also localized into over 30 languages.</p>  <p>My role: Flex technical leader; Flex developer</p>  <p>Tech notes:</p>  <ul>   <li>Flex 3 / Actionscript 3 </li>    <li>Cairngorm MVC micro-architecture framework </li>    <li>Loaded CSS (dynamic font &amp; styles) </li>    <li>Custom effects </li>    <li>XML-based localization </li>    <li>SOAP services </li>    <li>Large scale photo gallery (.NET backend) </li> </ul>  <p><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/S5pCUTclYRI/AAAAAAAACjI/e373enozyv0/s1600-h/2010-02-23_094146%5B3%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Smile Shutter Home Page" border="0" alt="Smile Shutter Home Page" src="https://lh3.ggpht.com/_47w2iQ8-NcE/S5pCW2JJaFI/AAAAAAAACjM/AkBDLbbDCrY/2010-02-23_094146_thumb%5B1%5D.png?imgmax=800" width="244" height="175" /></a> <a href="https://lh5.ggpht.com/_47w2iQ8-NcE/S5pCbQfRf_I/AAAAAAAACjQ/SdLJptGjRGE/s1600-h/2010-02-23_100637%5B2%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Smile Shutter Gallery" border="0" alt="Smile Shutter Gallery" src="https://lh3.ggpht.com/_47w2iQ8-NcE/S5pCcn0CERI/AAAAAAAACjU/sKVPlKCGEL4/2010-02-23_100637_thumb.png?imgmax=800" width="244" height="175" /></a></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Ubuntu for Flash Developers</title>
    <link href="https://int3ractive.com/blog/2010/ubuntu-for-flash-developers/"/>
    <updated>2010-03-07T06:55:00Z</updated>
    <id>https://int3ractive.com/blog/2010/ubuntu-for-flash-developers/</id>
    <content type="html"><![CDATA[
      
<p>I love Linux and free (but cool) softwares. But running Linux as a pure environment for Flash development seem to be a mission impossible (at least to the time of this post). Although I have discovered many good alternative programs, the most needed Flash authoring tool – Flash CS4 is not available in Linux. And that prevents me from moving 100% from Windows to Ubuntu.</p>  <p>Here are the list of application choices in Ubuntu which comes from my own experiences that I think necessary for any Flash developers to work comfortably in Linux world:</p>

<table border="1" cellspacing="0" cellpadding="2" width="592"><tbody>     <tr>       <td valign="top" width="10">         <p align="center"><strong>No</strong></p>       </td>        <td valign="top" width="103">         <p align="center"><strong>Tool</strong></p>       </td>        <td valign="top" width="137">         <p align="center"><strong>Windows application</strong></p>       </td>        <td valign="top" width="137">         <p align="center"><strong>Linux alternative</strong></p>       </td>        <td valign="top" width="204">         <p align="center"><strong>Note on Linux alternatives</strong></p>       </td>     </tr>      <tr>       <td valign="top" width="10">01</td>        <td valign="top" width="103">Flash IDE or Fla authoring tool</td>        <td valign="top" width="137"><a href="http://www.adobe.com/products/flash/" target="_blank">Adobe Flash CS4</a></td>        <td valign="top" width="137">N/A</td>        <td valign="top" width="204">make do with <a href="http://www.virtualbox.org/wiki/Linux_Downloads" target="_blank">Virtual Box</a> + WinXP + Flash CS4 (cost a lot of RAM)</td>     </tr>      <tr>       <td valign="top" width="10">02</td>        <td valign="top" width="103">ActionScript editor</td>        <td valign="top" width="137"><a href="http://www.flashdevelop.org/" target="_blank">FlashDevelop</a> (free and cool)</td>        <td valign="top" width="137">         <p><a href="http://www.eclipse.org/downloads/" target="_blank">Eclipse</a> + <a href="http://www.eclipse.org/downloads/" target="_blank">FDT plugin</a> or <a href="http://labs.adobe.com/technologies/flex/flexbuilder_linux/" target="_blank">Flex Builder 3 alpha</a></p>       </td>        <td valign="top" width="204">FDT Basic is free but lacks refactoring and debug tool (however it is comparable with current FD version)</td>     </tr>      <tr>       <td valign="top" width="10">03</td>        <td valign="top" width="103">Flex &amp; MXML tool</td>        <td valign="top" width="137"><a href="http://www.adobe.com/products/flex/" target="_blank">Flex</a>/<a href="http://labs.adobe.com/technologies/flashbuilder4/" target="_blank">Flash Builder</a></td>        <td valign="top" width="137">Eclipse + FDT plugin or Flex Builder 3 alpha</td>        <td valign="top" width="204">Currently, there is no tool comparable with Flash Builder in MXML design.          <br />Flex Builder in Linux doesn’t have MXML design either.</td>     </tr>      <tr>       <td valign="top" width="10">04</td>        <td valign="top" width="103">Flash trace &amp; debugging</td>        <td valign="top" width="137">Debugger in Flex Builder and <a href="http://www.sephiroth.it/firefox/flashtracer/" target="_blank">Flash tracer</a> in Firefox.</td>        <td valign="top" width="137">Flash tracer in FF and MAYBE debugger of FDT</td>        <td valign="top" width="204">I haven’t tried debugging with FDT.</td>     </tr>      <tr>       <td valign="top" width="10">05</td>        <td valign="top" width="103">Browsers and web debugging tools</td>        <td valign="top" width="137">Firefox + <a href="https://addons.mozilla.org/en-US/firefox/addon/1843" target="_blank">Firebug</a>           <br />OR IE + <a href="http://www.fiddler2.com/fiddler2/version.asp" target="_blank">Fiddler</a></td>        <td valign="top" width="137">Firefox + Firebug</td>        <td valign="top" width="204">It is as ‘comfy’ and easy as in Wins</td>     </tr>      <tr>       <td valign="top" width="10">07</td>        <td valign="top" width="103">Personal web host for testing</td>        <td valign="top" width="137">IIS or Apache</td>        <td valign="top" width="137"><a href="http://httpd.apache.org/" target="_blank">Apache</a></td>        <td valign="top" width="204">&#160;</td>     </tr>      <tr>       <td valign="top" width="10">&#160;</td>        <td valign="top" width="103"><strong>Other</strong></td>        <td valign="top" width="137"><strong>professional</strong></td>        <td valign="top" width="137"><strong>tools</strong></td>        <td valign="top" width="204">&#160;</td>     </tr>      <tr>       <td valign="top" width="10">08</td>        <td valign="top" width="103">VPN Client</td>        <td valign="top" width="137">Cisco&#160; Systems VPN Client</td>        <td valign="top" width="137">Built-in Network Manager + VPNC package</td>        <td valign="top" width="204">Very convenient VPN solution</td>     </tr>      <tr>       <td valign="top" width="10">09</td>        <td valign="top" width="103">Chat / IM</td>        <td valign="top" width="137"><a href="http://messenger.yahoo.com/" target="_blank">Yahoo</a>, <a href="http://download.live.com/?sku=messenger" target="_blank">MSN</a></td>        <td valign="top" width="137"><a href="http://www.pidgin.im/download/" target="_blank">Pidgin</a></td>        <td valign="top" width="204">         <p>Pidgin manages both of my Yahoo &amp; MSN accounts.            <br />There are, in fact, some limitations compared with the original applications.</p>       </td>     </tr>      <tr>       <td valign="top" width="10">10</td>        <td valign="top" width="103">Voice conference</td>        <td valign="top" width="137"><a href="http://www.skype.com/intl/en/" target="_blank">Skype</a></td>        <td valign="top" width="137"><a href="http://www.skype.com/intl/en/download/skype/linux/" target="_blank">Skype for Linux</a></td>        <td valign="top" width="204">Not fully functional like Windows’ counterpart but it’s still the best voice chat application</td>     </tr>      <tr>       <td valign="top" width="10">11</td>        <td valign="top" width="103">FTP client</td>        <td valign="top" width="137"><a href="http://filezilla-project.org/download.php?type=client" target="_blank">Filezilla</a></td>        <td valign="top" width="137"><a href="http://filezilla-project.org/download.php?type=client" target="_blank">FileZilla</a></td>        <td valign="top" width="204">&#160;</td>     </tr>      <tr>       <td valign="top" width="10">12</td>        <td valign="top" width="103">SVN client</td>        <td valign="top" width="137"><a href="http://tortoisesvn.net/downloads" target="_blank">TortoiseSVN</a></td>        <td valign="top" width="137"><a href="http://wiki.rabbitvcs.org/wiki/download" target="_blank">RabbitVCS</a> + <a href="http://rapidsvn.tigris.org/" target="_blank">RapidSVN</a></td>        <td valign="top" width="204">Inspired by TortoiseSVN, RabbitVCS is an integrated client working as shell commands in Ubuntu’s default file manger – Nautilus. By the time of this post, there’s still an issue with authentication so I need rapidSVN for first checkout.</td>     </tr>      <tr>       <td valign="top" width="10">13</td>        <td valign="top" width="103">Screen capture</td>        <td valign="top" width="137"><a href="http://www.faststone.org/FSCaptureDetail.htm" target="_blank">Fastone Capture</a> (<a href="http://www.aplusfreeware.com/categories/mmedia/FastStoneCapture.html" target="_blank">free version</a>)</td>        <td valign="top" width="137"><a href="http://shutter-project.org/" target="_blank">Shutter</a></td>        <td valign="top" width="204">Shutter comes with a handy drawing tool for taking notes and marking. BTW, the Ubuntu default tool “Take Screenshot” really sucks.</td>     </tr>      <tr>       <td valign="top" width="10">14</td>        <td valign="top" width="103">Remote desktop viewer</td>        <td valign="top" width="137">Remote Desktop Connection OR <a href="http://www.tightvnc.com/download.html" target="_blank">VNC viewer</a></td>        <td valign="top" width="137">Terminal Server Client OR Remote Desktop Viewer</td>        <td valign="top" width="204">Terminal Server Client is totally comparable with Windows’ RDC</td>     </tr>      <tr>       <td valign="top" width="10">15</td>        <td valign="top" width="103">Office suite</td>        <td valign="top" width="137"><a href="http://www.openoffice.org/" target="_blank">Open Office</a> or MS Office</td>        <td valign="top" width="137"><a href="http://www.openoffice.org/" target="_blank">Open Office</a></td>        <td valign="top" width="204">&#160;</td>     </tr>      <tr>       <td valign="top" width="10">16</td>        <td valign="top" width="103">Image editing tool</td>        <td valign="top" width="137">Photoshop</td>        <td valign="top" width="137"><a href="http://www.gimp.org/" target="_blank">GIMP</a></td>        <td valign="top" width="204">Honestly, there is no tool comparable with Photoshop. I can make do with GIMP in some simple tasks but for serious “business” (like my wedding photos :D) I’ll need Photoshop anyway.</td>     </tr>   </tbody></table>  <p>When I first moved to Ubuntu, I though I couldn’t do anything with it. But now I feel quite comfortable and “workable”. Though it still lacks some tools (like Live Writer which I’m using to post this blog) but thanks to its open environment, sooner or later, there’ll be good (and free) alternatives. (As I’m expecting ScribeFire to be sophisticated enough to replace Live Writer).</p>  <p>It’s high time we moved to Linux not only for the sake of free softwares but also because it has become mature enough.</p>  <p>Update: I have added some links to the softwares’ home page for easy reference. However, most of the Linux alternatives can be found in Ubuntu software center</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Happy Vietnamese New Year 2010</title>
    <link href="https://int3ractive.com/blog/2010/happy-vietnamese-new-year-2010/"/>
    <updated>2010-02-06T11:58:00Z</updated>
    <id>https://int3ractive.com/blog/2010/happy-vietnamese-new-year-2010/</id>
    <content type="html"><![CDATA[
      
<p>It been a while I haven't done any animation/e-card for my dear friends. This year, I want to make something different to mark my mature in the Flash carear after 2 years. Here it is (click on the thumb to open the flash movie:</p>

<h4>HAPPY VIETNAMESE NEW YEAR 2010! <br>WELCOME THE YEAR OF THE TIGER!</h4> <p><a href="http://www.fileden.com/files/2009/8/2/2530043/flash/Tet2010.swf" rel="shadowbox;width=1024;height=768" title="Happy Vietnamese New Year 2010"><img title="Click to view the card" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="300" alt="facebook" src="https://lh3.ggpht.com/_47w2iQ8-NcE/S21ZYFJN-LI/AAAAAAAACiA/OGBO27c_sLs/facebook_thumb%5B1%5D.jpg?imgmax=800" width="404" border="0"></a> </p> <p>The images are loaded from my FaceBook friends list.</p> <p>You can find the source code of this app <a href="http://code.google.com/p/thanhtran-sources/source/browse/#svn/trunk/demos/Tet2010" target="_blank">here</a>.</p> <p><strong>Update 14-June-2010</strong>: Profile picture URLs were fetched once via FaceBook API tester and stored in an embedded XML. They may be outdated over time.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Quick Note on Local to Global in Papervision3D</title>
    <link href="https://int3ractive.com/blog/2010/quick-note-on-local-to-global-in/"/>
    <updated>2010-01-23T06:09:00Z</updated>
    <id>https://int3ractive.com/blog/2010/quick-note-on-local-to-global-in/</id>
    <content type="html"><![CDATA[
      
<p>Normally, if you want to get the scene coordinates of a child 3D object, use these properties:</p>

<div class="actionscript3">   <ol>     <li class="li1">       <div class="de1"><span class="kw2">var</span> <span class="kw7">x</span><span class="sy0">:</span> <a href="http://www.google.com/search?q=number%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:number.html"><span class="kw5">Number</span></a> = <span class="kw7">child</span><span class="sy0">.</span>sceneX<span class="sy0">;</span></div>     </li>      <li class="li1">       <div class="de1"><span class="kw2">var</span> <span class="kw7">y</span><span class="sy0">:</span> <a href="http://www.google.com/search?q=number%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:number.html"><span class="kw5">Number</span></a> = <span class="kw7">child</span><span class="sy0">.</span>sceneY<span class="sy0">;</span></div>     </li>      <li class="li1">       <div class="de1"><span class="kw2">var</span> z<span class="sy0">:</span> <a href="http://www.google.com/search?q=number%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:number.html"><span class="kw5">Number</span></a> = <span class="kw7">child</span><span class="sy0">.</span>sceneZ<span class="sy0">;</span></div>     </li>   </ol> </div>  <p>However, if you want to get the screen coordinates of a local point other than the object’s original position (for e.g. side of a plane, some random points on a surface of a sphere…), then you have to deal with Matrix3D transform.</p>  <p>Don’t worry, you don’t need to understand what Matrix3D is because I don’t either :). Let’s use what people have concluded <a href="http://forum.papervision3d.org/viewtopic.php?f=14&amp;t=1617&amp;start=0" target="_blank">here</a>:</p>  <blockquote style="background: #ddffdd">   <p><em>If local to global is: </em></p>    <p><em><font face="Courier New">child.transform.calculateMultiply(parent.world, child.transform);</font> </em></p>    <p><em>then global to local is: </em></p>    <p><em><font face="Courier New">child.transform.calculateMultiply(Matrix3D.inverse(parent.world), child.transform);</font></em></p> </blockquote>  <p>There are 2 things to note with above conclusion:</p>  <ul>   <li>I have to invert method’s arguments (from what’s originally stated in the <a href="http://forum.papervision3d.org/viewtopic.php?f=14&amp;t=1617&amp;start=0" target="_blank">post</a>) to get the correct conversion. I’m using PV3D 2.1 </li>    <li><strike>I haven’t tried the global to local method, hence I don’t guarantee it works.</strike> The global to local transform works correctly. </li> </ul>  <p>So here’s how I convert any local positions to global:</p>  <div class="actionscript3">   <ol>     <li class="li1">       <div class="de1"><span class="kw2">var</span> <span class="kw7">matrix</span><span class="sy0">:</span> Matrix3D = Matrix3D<span class="sy0">.</span>IDENTITY<span class="sy0">;</span> <span class="co1">//a recommended way to create new Matrix3D </span></div>     </li>      <li class="li1">       <div class="de1"><span class="kw7">matrix</span><span class="sy0">.</span>n14 = <span class="kw7">localX</span><span class="sy0">;</span> </div>     </li>      <li class="li1">       <div class="de1"><span class="kw7">matrix</span><span class="sy0">.</span>n24 = <span class="kw7">localY</span><span class="sy0">;</span> </div>     </li>      <li class="li1">       <div class="de1"><span class="kw7">matrix</span><span class="sy0">.</span>n34 = localZ<span class="sy0">;</span> </div>     </li>      <li class="li1">       <div class="de1"><span class="kw7">matrix</span><span class="sy0">.</span>calculateMultiply<span class="br0">(</span><span class="kw7">child</span><span class="sy0">.</span><span class="kw7">parent</span><span class="sy0">.</span>world<span class="sy0">,</span> <span class="kw7">matrix</span><span class="br0">)</span><span class="sy0">;</span> <span class="co1">//child must be a DisplayObject3D </span></div>     </li>      <li class="li1">       <div class="de1"><span class="kw2">var</span> scenePos<span class="sy0">:</span> Number3D = <span class="kw1">new</span> Number3D<span class="br0">(</span><span class="kw7">matrix</span><span class="sy0">.</span>n14<span class="sy0">,</span> <span class="kw7">matrix</span><span class="sy0">.</span>n24<span class="sy0">,</span> <span class="kw7">matrix</span><span class="sy0">.</span>n34<span class="br0">)</span><span class="sy0">;</span></div>     </li>   </ol> </div>  <p>If you want to convert the rotation as well, use <font face="Courier New">Matrix3D.copy()</font> to copy all transformation info from the child object. And then after <font face="Courier New">calculateMultiply()</font>, apply the matrix to your scene object with <font face="Courier New">DisplayObject3D.copyTransform()</font>.</p>  <p><font size="1">[Vietnamese Tag – Chuyển đổi tọa độ local sang global trong Papervision3D]</font></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>3D Paper Flip Effect – First Attempt</title>
    <link href="https://int3ractive.com/blog/2010/3d-paper-flip-effect-first-attempt/"/>
    <updated>2010-01-16T14:16:00Z</updated>
    <id>https://int3ractive.com/blog/2010/3d-paper-flip-effect-first-attempt/</id>
    <content type="html"><![CDATA[
      
<p>Recently, a challenge have been raised to me if I can make a similar page flip effect like the one at <a href="http://labs.logosware.com/flash/flipper3/demo/lwSite/skin03/book1/" target="_blank">this page</a>. The difference from other <a href="http://megazine.mightypirates.de/demo/index.html" target="_blank">page flip libraries</a> is that the page turning effect looks more 3D-like and realistic.</p>

<p>At first glance, the effect might look difficult to replicate. But then I realized that it may be even easier to implement from the traditional page flip effect which requires a lot of overly complicated math. Thanks to 3D engines and modifier libraries at my disposal, I’m hoping to be able to create a 3D paper and manipulate it into a page turning animation.</p> <p>So if I want to bend or fold something in Flash 3D, the first thing came to my mind is using <a href="http://code.google.com/p/as3dmod/" target="_blank">AS3DMod</a>. However, when I look into it, the modifiers are so limited in terms of controlling interactions. For example, the Perlin modifier can makes the plane wavy like cloth or paper but there no way you can control it since Perlin noise is randomly generated. With Bend modifier, I can bend it only at one section. I can add more modifiers to bend at multiple sections but it is still too difficult to simulate the paper physically. </p> <p>Here my attemp with AS3Dmod and Papervision3D (click to open the Flash demo): <br><a href="http://www.fileden.com/files/2009/8/2/2530043/flash/3dpaper_as3dmod.swf" rel="shadowbox[PaperFlip1];width=550;height=400" title="With AS3DMod"><img title="Click to view the demo" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="294" alt="The demo preview" src="https://lh4.ggpht.com/_47w2iQ8-NcE/S1HKS9ertUI/AAAAAAAAChw/_MNU85XWfEg/01_3Dpaper_as3dmod%5B8%5D.jpg?imgmax=800" width="404" border="0"></a> </p> <p>So I decided to quit AS3DMod although I still thought that I might be missing something. (Somebody please prove I’m wrong with AS3DMod).</p> <p>My only hope now is to access the vertices of the 3DPlane and control them with a physics simulator. Fortunately in the Flipper3Maker mentioned above, the paper is not bent from any direction; the bend lines are in parallel. So I’ve come up with the following demo:</p> <p><a href="http://www.fileden.com/files/2009/8/2/2530043/flash/3dpaper_chain.swf" rel="shadowbox[PaperFlip1];width=550;height=400" title="With 2D chain simulator"><img title="Click to view the demo" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="295" alt="demo preview" src="https://lh6.ggpht.com/_47w2iQ8-NcE/S1HKTSYnOAI/AAAAAAAACh0/B_i-Tcc5MDc/2010-01-16_191134%5B4%5D.jpg?imgmax=800" width="404" border="0"></a> </p> <p>I used a simple 2D chain simulator which I got from <a href="http://www.prodevtips.com/2007/11/06/dynamics-and-procedural-animation-in-flash/" target="_blank">here</a> (was AS2) and then apply the transform on the rows of vertices on the 3D plane. The achievement here is that I can interact with the “paper” although it doesn’t look like a page turning effect yet.</p> <p>My next step is to find the right simulator for this page turning effect and I’m about to begin with Box2D.</p> <p>You can find the source code of above demos <a title="Source at Google Code" href="http://thanhtran-sources.googlecode.com/svn/trunk/demos/AS3DMod" target="_blank">here</a>.</p> <p>[Vietnamese Tag – Hiệu Ứng Lật Trang 3D – Cố Gắng Đầu Tiên]</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Pyco Flash Framework (Beta)</title>
    <link href="https://int3ractive.com/blog/2009/pyco-flash-framework-beta/"/>
    <updated>2009-12-25T11:46:00Z</updated>
    <id>https://int3ractive.com/blog/2009/pyco-flash-framework-beta/</id>
    <content type="html"><![CDATA[
      
<p>Pyco Flash Department has just released its beta version of Pyco Flash Framework (PFF). Its capabilities are demonstrated via our team’s minisite at <a href="http://www.pycoflash.co.cc">www.pycoflash.co.cc</a></p>  <p>This framework is aim to </p>  <ul>   <li>Set up a standard foundation for almost all Pyco Flash projects. I must say “almost” because some projects may not benefit from deploying PFF, especially ones that are too small and their file size is really a matter. (PFF and PureMVC take up to ~ 90 kB in the main swf).</li>    <li>Reduce the time and hassle of setting up the same project’s frame and common components over again. And therefore, reduce the effort spending on the project.</li>    <li>Drive team members to a new development approach which helps improve teamwork collaboration and source code’s maintainability</li> </ul>  <p>PFF features some of the latest techniques and approaches in the Flash universe:</p>  <ul>   <li>Flex SDK compilation: </li> </ul>  <ul>   <ul>     <li>Deploy FlashCS 3/4 &amp; Flex SDK workflow </li>      <li>Using precompiled libraries SWC extensively to separate UI and logic and to accelerate project build time </li>      <li>All SWFs are compiled using <a href="http://opensource.adobe.com/wiki/display/flexsdk" target="_blank">Flex SDK</a> compiler </li>      <li>Build and deployment can be automated using build script like FlexANT, ANT, batch…</li>   </ul> </ul>  <ul>   <li>The framework core is based on <a href="http://puremvc.org/" target="_blank">PureMVC</a> and <a href="http://trac.puremvc.org/Utility_AS3_Loadup" target="_blank">Loadup</a> utility</li>    <li>An MVC-based page manager. </li> </ul>  <ul>   <ul>     <li>The page manager supports external (loaded) and internal pages. <i>Demo: Login form is an internal page (no waiting for loading). Researches' framework top page is a internal blank containing page</i></li>      <li>Popups are supported (special pages which appear on top of other pages) <i>Demo: Login form is a popup</i></li>      <li>Custom transition for each page. <i>Demo: Member page</i></li>      <li>Page redirection. <i>Demo: Redirection from Researches top page to Research Intro</i></li>      <li>Linking page redirect users to an external URL<i>. Demo: Forum</i></li>      <li>Page accessibilty which requires authentication<i>. Demo: Works (who wants to see this page may contact me for the password)</i></li>   </ul> </ul>  <ul>   <li>Deep linking (AKA <a href="http://www.asual.com/swfaddress/" target="_blank">SWFAddress</a>). </li> </ul>  <ul>   <ul>     <li>The deeplinking module can be activated or omitted completely from project's build </li>      <li>Page system has deep linking by default (if deep linkng is activated).<i> Demo: All pages in the demo</i></li>      <li>Especially, each page can implement its own sub-deeplink logic. This is an unprecedented feature which never be seen in other frameworks. <i>Demo: Gallery page</i></li>   </ul> </ul>  <ul>   <li>Multilingual support and dynamic fonts loading. A unique text style manager which centralized all fonts assets and styles. No character is embeded twice. </li>    <li>A tracking manager which is designed to handle multiple tracking services at the same time. Trackers can be activated/deactivated completely from source code. Currently support Omniture, Webtrends and GoogleAnalytics. Future tracking services can be plugged in easily. </li>    <li>Common utilities and controls: Scrollbar, Tooltip, StringUtil, Cookies, Random...</li>    <li>Other modules and features to bundle in the framework: TBD</li> </ul>  <p>We are currently making the documents and API reference for it. Next step is to train every member of the team the usage of PFF.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>OpenZoom library &amp; SDK</title>
    <link href="https://int3ractive.com/blog/2009/openzoom-library-sdk/"/>
    <updated>2009-12-22T15:53:00Z</updated>
    <id>https://int3ractive.com/blog/2009/openzoom-library-sdk/</id>
    <content type="html"><![CDATA[
      
<p>I intended to note this on twitter but afraid that it will be washed away by other tweets. So I decided to bookmark any interesting ActionScript library here in a special category: ‘libraries’</p>  <p>Here’s the first:</p>  <blockquote>   <h4>“OpenZoom SDK</h4>    <p>The open source <strong>OpenZoom SDK</strong> is a toolkit for the <a href="http://www.adobe.com/flashplatform/">Adobe Flash Platform</a> that enables you to easily build <a href="http://tandem.gasi.ch/">powerful applications</a>, <a href="http://www.albawater.com.vn/">beautiful sites</a> and <a href="http://openzoom.org/webtrendmap/">stunning maps</a> which use a zooming metaphor and high-resolution images. It is freely available under the <a href="http://www.mozilla.org/MPL/MPL-1.1.html">MPL</a>/<a href="http://www.gnu.org/licenses/gpl-3.0.txt">GPL</a>/<a href="http://www.gnu.org/licenses/lgpl-3.0.txt">LGPL</a> trilicense.”</p> </blockquote>  <p>Main site: <a href="http://openzoom.org/">http://openzoom.org/</a>    <br />Code: <a title="http://openzoom.org/go/code" href="http://openzoom.org/go/code">http://openzoom.org/go/code</a>    <br />Document API: <a title="http://docs.openzoom.org/sdk" href="http://docs.openzoom.org/sdk">http://docs.openzoom.org/sdk</a>    <br />Author’s blog: <a title="http://gasi.ch/blog" href="http://gasi.ch/blog">http://gasi.ch/blog</a></p>  <p>Checkout this <a href="http://gasi.ch/examples/2008/10/13/inside-deep-zoom/mont-saint-michel/flash/" target="_blank">example</a>. (Try: + – W A S D click wheel drag)    <br />Interestingly, there is a Vietnamese showcase: <a title="http://www.albawater.com.vn/" href="http://www.albawater.com.vn/">http://www.albawater.com.vn/</a></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Red5 Data Mapping</title>
    <link href="https://int3ractive.com/blog/2009/red5-data-mapping/"/>
    <updated>2009-12-18T11:46:00Z</updated>
    <id>https://int3ractive.com/blog/2009/red5-data-mapping/</id>
    <content type="html"><![CDATA[
      
<p><a href="http://code.google.com/p/red5/" target="_blank"><img style="display: inline; margin-left: 0px; margin-right: 0px" title="Red5 Logo" alt="Red5 Logo" align="right" src="http://red5.googlecode.com/svn/doc/trunk/FinalLogo.png" width="200" height="81" /></a>When sending data to Red5 handlers, it is important to know the counter-part data types used in the server’s Java code. </p>  <p>There’s is one article mentioning about this at <a title="http://jira.red5.org/confluence/display/codecs/Data+Type+Mappings" href="http://jira.red5.org/confluence/display/codecs/Data+Type+Mappings">http://jira.red5.org/confluence/display/codecs/Data+Type+Mappings</a></p>  <p>However, for an unknown reason, the page is not accessible any more. I have to produce a test and observe the conversion of data as following:</p>  <p>From Flash to Red5 (valid to Red5 0.8 / 0.9)</p>  <table border="1" cellspacing="0" cellpadding="2" width="586"><tbody>     <tr>       <td width="280">         <p align="center"><strong>ActionScript 3</strong></p>       </td>        <td width="304">         <p align="center"><strong>Red5</strong></p>       </td>     </tr>      <tr>       <td width="280">Boolean</td>        <td width="304">java.lang.Boolean</td>     </tr>      <tr>       <td width="280">String</td>        <td width="304">java.lang.String</td>     </tr>      <tr>       <td width="280">uint (&lt; 2147483647)          <br />int (-2147483648 to below 2147483647)           <br />Number (integer value within int range)</td>        <td width="304">java.lang.Integer</td>     </tr>      <tr>       <td width="280">uint (&gt;= 2147483647)          <br />Number (integer value out of int range)</td>        <td width="304">java.lang.Long</td>     </tr>      <tr>       <td width="280">Number (fraction value)</td>        <td width="304">java.lang.Double</td>     </tr>      <tr>       <td width="280">Date</td>        <td width="304">java.util.Date</td>     </tr>      <tr>       <td width="280">Array</td>        <td width="304">java.util.ArrayList</td>     </tr>      <tr>       <td width="280">Object / Custom Object</td>        <td width="304">org.red5.io.utils.ObjectMap</td>     </tr>      <tr>       <td width="280">XML, XMLDocument</td>        <td width="304">org.apache.xerces.dom.DeferredDocumentImpl          <br />(<em>this class seems not to be in Red5’s lib folder</em>)</td>     </tr>      <tr>       <td width="280">ByteArray</td>        <td width="304">org.red5.io.amf3.ByteArray</td>     </tr>      <tr>       <td width="280"><strong>Special Values:</strong></td>        <td width="304">&#160;</td>     </tr>      <tr>       <td width="280">NaN</td>        <td width="304">NaN</td>     </tr>   </tbody></table>  <p>Notes:</p>  <ul>   <li>Negative integer value is limited at –2147483648 even if the variable is declared as Number. If you try to send a value less than this number, it will be rounded up to –2147483648. </li>    <li>If one of the params in the remote call is <font face="Courier New">null</font> or <font face="Courier New">undefined</font>, the handler will not be executed. </li> </ul>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project - Shiho</title>
    <link href="https://int3ractive.com/blog/2009/project-shiho/"/>
    <updated>2009-09-01T14:57:00Z</updated>
    <id>https://int3ractive.com/blog/2009/project-shiho/</id>
    <content type="html"><![CDATA[
      
<a href="https://lh3.ggpht.com/_47w2iQ8-NcE/Sp1BGwmOO7I/AAAAAAAACgQ/hHTXIBEEdQg/s1600-h/se_shiho_02%5B5%5D.jpg"><img alt="Shiho" border="0" height="256" src="https://lh3.ggpht.com/_47w2iQ8-NcE/Sp1BIKs5wpI/AAAAAAAACgU/cw012NuN-cI/se_shiho_02_thumb%5B3%5D.jpg?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="Shiho" width="404" /></a> <br />
<a href="http://www.sonyericsson.com/bigpictures">Campaign microsite</a> for Sony Ericsson C905 – code name Shiho. This site features Cairngorm MVC framework and a flexible localization mechanism. Every text in the site is configurable via XML. The embedded fonts with specific character sets are selectively loaded for different languages. (For e.g: basic Latin for English, French; Cyrillic for Bulgarian, Russian…) Non-embedded languages like Chinese are also possible. Animations which demonstrate the phone features are made with Flash IDE and loaded into the Flex-based application progressively to optimize bandwidth.<br />
<br />
My role: Team leader (during localization phase), Flash developer<br />
<br />
Tech notes:<br />
<ul><li>Flex 3 / Actionscript 3 </li>
<li>Cairngorm MVC micro-architecture framework</li>
<li>Loaded CSS (dynamic font &amp; styles) </li>
<li>Flex’ custom effect </li>
<li>Flash + Flex combination </li>
<li>XML-based localization</li>
</ul><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/Sp1BJV1icMI/AAAAAAAACgY/QD1wE7S9at4/s1600-h/se_shiho_01%5B29%5D.jpg"><img alt="Home page" border="0" height="132" src="https://lh6.ggpht.com/_47w2iQ8-NcE/Sp1BKCVYSBI/AAAAAAAACgc/WcVCBAepdvA/se_shiho_01_thumb%5B22%5D.jpg?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline;" title="Home page" width="204" /></a>&nbsp;&nbsp; <a href="https://lh5.ggpht.com/_47w2iQ8-NcE/Sp1BLJpHCCI/AAAAAAAACgg/R2zNOEmayKY/s1600-h/se_shiho_05%5B10%5D.jpg"><img alt="Signup form" border="0" height="132" src="https://lh5.ggpht.com/_47w2iQ8-NcE/Sp1BMNCb1YI/AAAAAAAACgk/pu_Upid5HNA/se_shiho_05_thumb%5B6%5D.jpg?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline;" title="Signup form" width="207" /></a>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project - Female Form Factor</title>
    <link href="https://int3ractive.com/blog/2009/project-female-form-factor/"/>
    <updated>2009-08-11T15:17:00Z</updated>
    <id>https://int3ractive.com/blog/2009/project-female-form-factor/</id>
    <content type="html"><![CDATA[
      
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://2.bp.blogspot.com/_47w2iQ8-NcE/SoGcpCY2u3I/AAAAAAAACVQ/B0AmRmiNXKQ/s1600-h/se_femaleformfactor_04.jpg"></a><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://4.bp.blogspot.com/_47w2iQ8-NcE/SoGMpXP72BI/AAAAAAAACUQ/qpZlA1gbjrY/s1600-h/se_femaleformfactor_01.jpg"><img style="cursor:pointer; cursor:hand;width: 400px; height: 216px;" src="https://4.bp.blogspot.com/_47w2iQ8-NcE/SoGMpXP72BI/AAAAAAAACUQ/qpZlA1gbjrY/s400/se_femaleformfactor_01.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5368726873045719058" /></a>

A campaign microsite for the Sony Ericsson mobile phone - T303. The site includes 4 stylish studios in which you will try out the new phone with its featured features: camera (capture a photo from the room and display it in a frame), music player (listen to some pieces of music that are chosen to match with the room's mood) and Internet access (buy some items and put them in the room). There is also a quiz to help user choosing the matching room for them. This site was finished in 8/2008.<div>
</div><div>The site is integrated as iframe in www.sonyericsson.com under T303 phone page. However, you can google the phrase 'Female Form Factor' to receive <a href="http://www.sonyericsson.com/campaignframe/mobilestyle/flash/?cc=za&amp;lc=en">this direct link</a>.
<div>
</div><div>My role: Team leader, Flash developer</div><div>
</div><div>Technical notes:<div><ul><li>Flash 8 / Actionscript 2</li><li>Object Oriented</li><li>Displacement Map Filter: used to make the camera viewport look wider</li><li>Dynamic font embedding: load the font set specific to a localized language. Since there's no dynamic font registering in Flash 8, a special technique was used involving dynamic shared library.</li><li>.NET service.</li></ul></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://lh4.ggpht.com/_47w2iQ8-NcE/SoGfqEHSYCI/AAAAAAAACVY/gM0sV4GSyr8/s1600-h/se_femaleformfactor_02.jpg"><img src="https://lh4.ggpht.com/_47w2iQ8-NcE/SoGfqEHSYCI/AAAAAAAACVY/gM0sV4GSyr8/s200/se_femaleformfactor_02.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5368747775809970210" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 200px; height: 108px; " /></a><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://4.bp.blogspot.com/_47w2iQ8-NcE/SoGcZ1cN2PI/AAAAAAAACVI/WjsOwsk-NJA/s1600-h/se_femaleformfactor_03.jpg"><img src="https://4.bp.blogspot.com/_47w2iQ8-NcE/SoGcZ1cN2PI/AAAAAAAACVI/WjsOwsk-NJA/s200/se_femaleformfactor_03.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5368744198458431730" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 200px; height: 108px; " /></a><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://lh4.ggpht.com/_47w2iQ8-NcE/SoGcpCY2u3I/AAAAAAAACVQ/B0AmRmiNXKQ/s1600-h/se_femaleformfactor_04.jpg"><img src="https://lh4.ggpht.com/_47w2iQ8-NcE/SoGcpCY2u3I/AAAAAAAACVQ/B0AmRmiNXKQ/s200/se_femaleformfactor_04.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5368744459632032626" style="float: left; margin-top: 0px; margin-right: 10px; margin-bottom: 10px; margin-left: 0px; cursor: pointer; width: 200px; height: 108px; " /></a></div>
</div></div>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Google Map for Flash with daylight layer</title>
    <link href="https://int3ractive.com/blog/2009/google-map-for-flash-with-daylight/"/>
    <updated>2009-08-05T15:08:00Z</updated>
    <id>https://int3ractive.com/blog/2009/google-map-for-flash-with-daylight/</id>
    <content type="html"><![CDATA[
      
<div>When I visit this site: www.daylightmap.com, I was excited how it could show the daylight on the world map in real time. Very interesting because I can visually know some friends of mine in other part of the Earth are in the light of sun or in the shadow of darkness. :)</div><div>The site is using Google Map API (javascript) for the map and its own service for the daylight layer. Although the author provides a limited free service there was no code for the Google Map API for Flash so I decided to examine the service call to get the input needed and port it to Flash-based Google Map.</div><div>
</div><div>I assume that you already know how to use <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#TileLayerOverlay">TileLayerOverlay</a> or extends the <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#TileLayerBase">TileLayerBase</a> in the API to create a new map layer above default ones.</div><div>Basically, like other tile layer, the Google map need to get the correct tile image via the tile's x and y coordinate in a certain zoom level.</div><div>Here's the service call break down:</div><div>
</div><div><span class="Apple-style-span"  style="font-family:'courier new';">tileURL = "http://www.daylightmap.com/tiles/cache/" + "tile_" + <span class="Apple-style-span"  style="color:#CC0000;">lightOn</span> + <span class="Apple-style-span"  style="color:#CC0000;">zoom</span> + "_" + <span class="Apple-style-span"  style="color:#CC0000;">tileX</span> + "_" + <span class="Apple-style-span"  style="color:#CC0000;">tileY</span> + "_" + <span class="Apple-style-span"  style="color:#CC0000;">secs</span> + ".png";</span></div><div>
</div><div>Luckily, since the service is for Google Map API, there's no need to convert the zoom, tileX, tileY values forwarded from the API.</div><div>What we need to manipulate are:</div><div><span class="Apple-style-span"  style="font-family:'courier new';">- lightOn ("n_"|"")</span>: if you want to get the shadow images with city lights or not</div><div><span class="Apple-style-span"  style="font-family:'courier new';">- secs</span>: number of seconds since 01/01/1970 00:00:00 UTC which, in AS3, can be get by:</div>
<div class="actionscript3"   style="color: #006; border: 1px solid #d0d0d0; background-color:#f0f0f0; font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="kw2">var</span> now<span class="sy0">:</span> <a href="http://www.google.com/search?q=date%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:date.html"><span class="kw5">Date</span></a> = <span class="kw1">new</span> <a href="http://www.google.com/search?q=date%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:date.html"><span class="kw5">Date</span></a><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> <span class="co1">//get local time</span></div></li><li class="li1"><div class="de1"><span class="kw2">var</span> secs<span class="sy0">:</span> <a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html"><span class="kw5">int</span></a> = <a href="http://www.google.com/search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html"><span class="kw5">int</span></a><span class="br0">(</span>now<span class="sy0">.</span><span class="kw7">getTime</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">/</span> 1000<span class="br0">)</span><span class="sy0">;</span> <span class="co1">//convert from milliseconds to seconds</span></div></li></ol></div><span class="Apple-style-span"  style="color:#000066;">
</span><div>Here's the demo:
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="570" height="450" id="Player" align="middle">
<param name="allowScriptAccess" value="always">
<param name="allowFullScreen" value="false">
<param name="movie" value="http://www.fileden.com/files/2009/8/2/2530043/flash/GoogleDaylightMap.swf">
<param name="quality" value="high">
<param name="bgcolor" value="#FFFFFF">

<embed src="http://www.fileden.com/files/2009/8/2/2530043/flash/GoogleDaylightMap.swf" quality="high" bgcolor="#FFFFFF" width="570" height="450" name="Player" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>
</object>

</div><div>Download <a href="http://thanhtran-sources.googlecode.com/files/GoogleDayLightMap.zip">source code here</a>.</div><div>
</div><div>Side notes:</div><div><ul><li>There's also a service in which we can get local time as well as current position of the Sun (in lat/long). However, the site currently doesn't allow crossdomain service call. So I just left an example in the demo but commented it out. If you need those features, you might need to ask the site's author to create a crossdomain.xml file in his website.</li><li>Since daylight layer is a kind of real time data, obviously, we need to reload the map after an interval of time. I haven't done this in my demo. But you should understand the situation:
When I wrote this demo, the API was 1.9 and it doesn't support any way to force a tile layer to reload new data. However, a work-around is hinted on its developers' group forum that we can force the map to reload completely by resizing the map (maybe just 1 or 2 pixels).
By the time of this article, API v1.16 was released and it provides a new <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#TileLayerOverlay.refresh">refresh()</a> method in the TileLayerOverlay which can be used to solve our problem. I leave this to anyone who wants to improve it.</li></ul></div>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project - Offset The Evil</title>
    <link href="https://int3ractive.com/blog/2009/project-offset-evil/"/>
    <updated>2009-08-02T07:43:00Z</updated>
    <id>https://int3ractive.com/blog/2009/project-offset-evil/</id>
    <content type="html"><![CDATA[
      
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://3.bp.blogspot.com/_47w2iQ8-NcE/SnVM5ccucuI/AAAAAAAACE8/rEpYXYGLTKE/s1600-h/offsettheevil_com_01.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 190px;" src="https://3.bp.blogspot.com/_47w2iQ8-NcE/SnVM5ccucuI/AAAAAAAACE8/rEpYXYGLTKE/s320/offsettheevil_com_01.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5365279080854745826" /></a>Like its name, this flash site is to offset the evil from those played the bloody game <a href="http://en.wikipedia.org/wiki/Condemned_2:_Bloodshot">Condemned 2</a>. The site includes 3 simple fun games (one of them was removed for the reason I don't know) which are totally unrelated to Comdemned 2 and some other activities related to the game. This site was finished in 4/2008. By the time of this post, the site is still live at: <a href="http://www.offsettheevil.com/">http://www.offsettheevil.com/</a><div>
</div><div>The 3 games were developed by my team and I was in charge of the Lolipop Parade.</div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://1.bp.blogspot.com/_47w2iQ8-NcE/SnVNGGx5CtI/AAAAAAAACFE/8AY3SprHUII/s1600-h/offsettheevil_com_02.jpg"><img src="https://1.bp.blogspot.com/_47w2iQ8-NcE/SnVNGGx5CtI/AAAAAAAACFE/8AY3SprHUII/s400/offsettheevil_com_02.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5365279298376239826" style="cursor: pointer; width: 400px; height: 234px; " /></a>
<div>My role was: Flash Developer</div><div>Technology notes:</div><div><ul><li>Object Oriented</li><li>Flash Player 8 / ActionScript 2</li><li>Tweener </li></ul></div></div>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>Project Spa Water Coach</title>
    <link href="https://int3ractive.com/blog/2008/project-spa-water-coach/"/>
    <updated>2008-09-15T14:23:00Z</updated>
    <id>https://int3ractive.com/blog/2008/project-spa-water-coach/</id>
    <content type="html"><![CDATA[
      
<p><a href="https://lh4.ggpht.com/_47w2iQ8-NcE/S5pPxtczg3I/AAAAAAAACjY/z-p6TZTmwVY/s1600-h/spadel_widget%5B4%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="Spa Water Coach" border="0" alt="Spa Water Coach" src="https://lh4.ggpht.com/_47w2iQ8-NcE/S5pPyivHBDI/AAAAAAAACjc/xEVYTXJjfBU/spadel_widget_thumb%5B2%5D.jpg?imgmax=800" width="400" height="311" /></a></p>

<p>(2008) The main purpose of this website is to deliver a desktop application which calculates user’s water needs and reminds them to drink enough a day. The project comprised of 2 parts: a full Flash website to let user input necessary data for the calculation of needed water consumption; a desktop widget (made with Adobe AIR) to run regularly on user’s desktop to keep track and remind them to drink water.</p>

<p>My role: team leader, AIR developer</p>

<p>Tech notes:</p>  <ul>   <li>Flash 9 / Actionscript 3</li>    <li>Adobe AIR</li>    <li>Tweener tweening library</li> </ul>  <p><a href="https://lh5.ggpht.com/_47w2iQ8-NcE/S5pP0KgSenI/AAAAAAAACjg/gwESydoedvU/s1600-h/spadel%5B2%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Spa Water Coach website" border="0" alt="Spa Water Coach website" src="https://lh3.ggpht.com/_47w2iQ8-NcE/S5pP1VYXVlI/AAAAAAAACjk/uqmLFxSbNX4/spadel_thumb.jpg?imgmax=800" width="244" height="185" /></a></p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>ActionScript 3 Sound Player</title>
    <link href="https://int3ractive.com/blog/2008/actionscript-3-sound-player/"/>
    <updated>2008-03-17T06:20:00Z</updated>
    <id>https://int3ractive.com/blog/2008/actionscript-3-sound-player/</id>
    <content type="html"><![CDATA[
      
<p>I've just spent my weekend experiencing some sound handling capabilities of AS3 and have come out with this demo. This is a simple sound (wav, mp3) player features: common functions like play, pause, stop, fast-forward, rewind, seeker and other advanced functions like volume, pan, channel switch, especially the ID3 tags and spectrum info.</p>

<embed src="http://www.fileden.com/files/2009/8/2/2530043/flash/AS3-SoundPlayer.swf" quality="high" bgcolor="#000000" name="SoundPlayer" allowscriptaccess="sameDomain" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" align="middle" height="400" width="550"></embed>

<p>You can test the player by opening any online mp3 file. For e.g: http://www.fileden.com/files/2009/8/2/2530043/KhongConMuaThu.mp3 (Note: if the mp3 is hosted on a cross-domain site, that domain must have a crossdomain policy file so that this player can access ID3 tag and spectrum from the mp3s)</p>

<p>Download <a href="http://thanhtran-sources.googlecode.com/files/AS3-SoundPlayer.zip">source code here</a>.</p>

    ]]></content>
  </entry>
	
  
  <entry>
    <title>FlickrCloud: Flickr API &amp; Papervision 3D</title>
    <link href="https://int3ractive.com/blog/2008/flickrcloud-flickr-api-papervision-3d/"/>
    <updated>2008-02-15T16:32:00Z</updated>
    <id>https://int3ractive.com/blog/2008/flickrcloud-flickr-api-papervision-3d/</id>
    <content type="html"><![CDATA[
      
Let me start my fisrt blog post with my rencent demo:<br />
In a few days free from client projects, I have done some studies and made this demo. With this embeddable flash application, you can browse your and your friends' flickr public photos with a stunning 3D experience. (up to 50 latest photos) I named it <strong>FlickrCloud</strong> (Flickr + PaperCloud).

<br />
<embed align="middle" allowfullscreen="true" bgcolor="#000000" flashvars="flickrid=9803330@N04" height="428" src="http://www.fileden.com/files/2009/8/2/2530043/flash/FlickrCloud.swf" type="application/x-shockwave-flash" width="570"></embed><br />
Technical info: This application is the combination of<br />
<ul><li>Flash Player 9 (Action Script 3)</li>
<li><a href="http://www.flickr.com/services/api/">Flickr API</a> (with the help of Adobe <a href="http://labs.adobe.com/wiki/index.php/ActionScript_3:resources:apis:libraries#Flickr">AS3 Flickr Library</a>)</li>
<li><a href="http://blog.papervision3d.org/">Papervision3D</a> engine.</li>
<li>Original 3D effect from <strong>PaperCloud</strong> demo (included in Papervision3D classes and examples).</li>
</ul>Get the source <a href="http://thanhtran-sources.googlecode.com/files/FlickrCloud_PV3D.zip">here</a>.<br />
Try this application yourself: put these codes into your blog html<br />
<span style="font-family: 'courier new';"><span style="font-family: 'courier new';">&lt;embed src="http://www.fileden.com/files/2009/8/2/2530043/flash/FlickrCloud.swf" bgcolor="#000000" type="application/x-shockwave-flash" flashvars="" flickrid="<span style="color: #cc33cc;">9803330@N04</span>" allowscriptaccess="none" align="middle" height="480" width="640" /&gt;</span></span><br />
That <em>flashvars</em> thing is used to inform the application the startup user ID. Remember to replace my flickr ID (9803330@N04) with your choice of user. (Don't know your flickr ID? Log into your flickr account and look at the URL on your browser's address bar, you will find the ID that looks like mine.)

    ]]></content>
  </entry>
	
</feed>
