Pages

8/29/2012

Install Trac with OpenID on Ubuntu Linux 12.04

Here's my short note on installing Trac on Ubuntu 12.04 + authOpenID
Trac is an enhanced wiki and issue tracking system for software development projects. Trac uses a minimalistic approach to web-based software project management (http://trac.edgewall.org/)
Installation:
  1. install packages:
    sudo apt-get install python python-babel trac trac-authopenid trac-git
    
  2. create trac environment. My environment is like this:
    1. /trac   (Trac Parent Directory)
    2. /trac/myproject    (my project directory
    sudo mkdir /trac
    sudo mkdir /trac/myproject
    sudo chown -R your-username:users /trac   #set it to belong to you, for easier setup for now
    
  3. initial Trac project
    trac-admin /trac/myproject initenv
  4. Edit myproject's trac config
    1. Go to /trac/myproject/conf/
    2. use your prefer editor (gedit,kate,vi) to open up "trac.ini"
    3. add this at the bottom for authOpenID
      [components]
      trac.web.auth.* = disabled
      authopenid.* = enabled
    4. Enable file logging(save to /trac/myproject/log/trac.log) by changing "log_type = none" to "log_type = file"
    5. set Header Logo, under "[header_logo]" edit the config like this:
      [header_logo]
      alt = My Project
      height = 200
      link = 
      src = site/images/logo.png
      width = 800
      "site/" means your local "htdocs" (/trac/myproject/htdocs). Meaning it will search for "logo.png" under /trac/myproject/htdocs/images/logo.png
    6. set other settings if you would like
  5. Try running it on standalone first, to see if the configuration works. Use command: "tracd -p 8888 /trac/myproject" .
    1. If it is working you can browse to localhost:8888 and it should be running smoothly.
    2. don't forget to login with OpenID, by clicking "OpenID Login" on top-right corner. So we can capture the OpenID username and use it later
    3. you can stop the server on the command line terminal by pressing Ctrl-C
  6. Setting OpenID user. Since we turned on logging to file, and we tried logged in with OpenID user.
    1. see the log(using vi,tail,kate,gedit) on log file located at /trac/myproject/log/trac.log
    2. What you are looking for is something like this
      2012-08-30 04:39:28,131 Trac[session] DEBUG: Retrieving session for ID u'anidear'
      The OpenID user name is in u'xxxxxxx'. In this case, it is "anidear".
    3. Using trac-admin command to grant permission to this user if he is an admin
      trac-admin /trac/myproject permission add anidear TRAC_ADMIN
      where as "anidear" is my username from previous step.
  7. Update Trac settings using command
    trac-admin /trac/myproject upgrade
    
  8. (Optional) You may need to remove all wiki pages. It can be done by this script 
    #!/bin/sh
    
    # extract the page list from trac (this filter matches only CamelCase words or numbers,
    # it will blow if there are pages which does not fit into this scheme)
    for site in `trac-admin /trac/myproject wiki list | sed -e 's/\([a-zA-Z0-9]*\).*/\1/'`
    do
        # and remove every single page
        trac-admin /trac/myproject wiki remove $site
    done
    
    ref: http://stackoverflow.com/questions/3978755/trac-pages-delete-all
  9. Change permission so Apache can read/write to it.
    But I'm single user on this machine and I want to modify the file sometimes. So I'll just set the group for "www-data" (Apache group) just enough for Apache to read the file. Otherwise, you can set both user and group to belong to Apache buy using "www-data:www-data" for it.
    sudo chown -R :www-data /trac
    sudo chmod -R 775 /trac
    
  10. Setting Trac to works with Apache2:
    1. go to /etc/apache2/sites-available and create a file named "trac-site" (need root privilege) by using any editor
    2. put this in the file:
      Listen 0.0.0.0:9999
      NameVirtualHost *:9999
      <VirtualHost *:9999>
          ServerName trac.local
      
          <Location />
              SetHandler mod_python
              PythonInterpreter main_interpreter
              PythonHandler trac.web.modpython_frontend
      #        PythonOption TracEnv /trac/myproject
              PythonOption TracEnvParentDir /trac
              PythonOption TracUriRoot /
              PythonOption TracLocale en_US.UTF8
              PythonOption PYTHON_EGG_CACHE /tmp
              Order allow,deny
              Allow from all
          </Location>
      #    <Location /login>
      #        AuthType Basic
      #        AuthName "myproject"
      #        AuthUserFile /trac/.htpasswd
      #        Require valid-user
      #    </Location>
      
          ErrorLog /var/log/apache2/trac_error.log
          # Possible values include: debug, info, notice, warn, error, crit,
          # alert, emerg.
          LogLevel warn
          CustomLog /var/log/apache2/trac_access.log combined
      </VirtualHost>
      
      
      1. Listen 0.0.0.0:9999 set to accept any IP that comes to server with port 9999 (you can limit to use within your machine by changing 0.0.0.0 to 127.0.0.1)
      2. NameVirtualHost and VirtualHost are accepting any IP on port 9999 (again, to make it private change * to 127.0.0.1)
      3. "<Location />" is for serving Trac as the root of URL "http://localhost:9999/"
      4. "PythonOption TracEnv" is for using single project. If you want to use only single project, uncomment this line
      5. "PythonOption TracEnvParentDir" points to parent directory of projects
      6. "PythonOption TracUriRoot" is the URL that we want to use when request for Trac main page. "/" means to "http://localhost:9999/"
      7. I comment out normal Trac authentication using htpasswd because we already change to use OpenID authentication.
      8. "ErrorLog","CustomLog","LogLevel" are settings for keep logging on Trac and location to save the logs to
    3. use command "sudo a2en trac-site" to enable this site on Apache2
    4. restart Apache2 using "sudo service apache2 restart"

8/25/2012

บันทึกการเริ่มเขียน Google App Engine ด้วย Python

เริ่มจากหน้า https://developers.google.com/appengine/

ตอนนี้ Google App Engine รองรับการใช้งาน 3 ภาษา:

  • Java
  • Python ( version 2.5 กับ 2.7 เขียนต่างกัน)
  • Go
บล๊อคนี้เลือกจะทำงานด้วย python 2.7 ซึ่งดูใหม่กว่า version 2.5 และมีระบบ threadsafe คือรองรับหลายๆ client แยกกันได้พร้อมกันได้

Python ยังสามารถเลือกได้ว่าจะใช้ framework อะไรในการจัดการหน้าเวป ไม่ว่าจะเป็น "webapp2" หรือ "django" แต่ตาม tutorial ของ Google จะให้เริ่มใช้งานที่ "webapp2" 

วิธีทำ
  1. มี Python 2.7 ลงอยู่ในเครื่อง (http://www.python.org/getit/releases/2.7/)
  2. ดาวน์โหลด App Engine SDK https://developers.google.com/appengine/downloads ซึ่งข้างในจะเป็น python code ที่ถูก zip เอาไว้  ข้างในมีคำสั่งสำคัญๆ สองตัวคือ:
    1. dev_appserver.py  เอาไว้รัน server ไว้ที่เครื่องตัวเอง สำหรับทดลองเขียนโค้ด
    2. appcfg.py เอาไว้สั่งอัพโหลดโค้ดขึ้นไปที่ Google App Engine
  3. แตกไฟล์ zip ที่ได้มา ไปไว้ที่ๆนึง ที่เรียกใช้ได้ถนัดๆ เช่น /opt   แล้วก็จะมีโครงสร้างเป็น
  4. /opt/
    --google_appengine/
    ----dev_appserver.py
    ----appcfg.py
    ----.........
    ----etc.
    
    
    
  5. เริ่มเขียน app.yaml ไว้สำหรับควบคุม app นี้  (app configuration file)
    • ไฟล์นี้จะต่างจากการเขียนสำหรับ python version 2.5 ตรงที่
      • [2.7] จะใช้ runtime: "python27", แต่ [2.5] จะใช้ runtime: "python25"
      • [2.7] จะใช้นามสกุลของไฟล์ว่า .app (ถึงแม้ไฟล์จริงๆจะเป็น .py) แต่ [2.5] ก็ยังใช้ .py เหมือนเดิม ดังนั้น ถ้าใน app.yaml มีบรรทัดไหนเขียนว่า .py จะเป็นสำหรับversion 2.5 และจะเกิด error ขึ้นเวลา compile บนระบบ 2.7
      • [2.7] จะเน้นใช้งานระบบ routing ภายในโค้ดที่เรียกว่า WSGIApplication มากกว่าระบบของ [2.5] ซึ่งจะต้องเขียน routing แยกแต่ละตัวที่ app.yaml เลย
        • ดังนั้น [2.7] อาจจะเขียนในไฟล์ app.yaml แค่
        • handlers:
          - url: /.*
            script: main.app
          
        • แต่ข้างใน main.app จะเป็น
        • app = webapp2.WSGIApplication([('/', MainPage), ('/another', AnotherPage), ('/test/([a-z]*)', TestPage)]);
        • ในขณะที่ [2.5] จะต้องเป็น
        • handlers:
          - url: /another
            script: another.py
          - url: /test/([a-z]*)
            script: test.py
          - url: /.*
            script: main.py
        • more : http://webapp-improved.appspot.com/guide/handlers.html
  6. โค้ดแบบง่ายของ app.yaml จะเป็น

  7. application: helloworld
    version: 1
    runtime: python27
    api_version: 1
    threadsafe: true
    
    handlers:
    - url: /.*
      script: main.app
    

  8. เริ่มเขียนโค้ด main.py

  9. import webapp2
    
    class MainPage(webapp2.RequestHandler):
        def get(self):
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.write('Hello, webapp2 World!')
    
    app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
    
    • import webapp2   ==> เรียกใช้ webapp2 framework
    • class MainPage ==> สร้างคลาส MainPage ให้เป็นชนิด RequestHandler
    • def get(self) ==> สร้าง method ให้รองรับเวลาclient ส่งคำสั่ง HTTP GET มา
      • ตรงนี้จะต้องรับ self ไปเป็นตัวแปรแรกอยู่แล้ว
      • แต่ถ้าอยากจะรับตัวแปรอื่นเพิ่มจาก URL เช่น  อยากได้  /2012/08 แล้วให้ แปลงเป็น year, month จะต้องเขียนเป็น
        • แก้เป็น def get(self, year, month)
        • app = webapp2.WSGIApplication([('/([0-9]{2,4})/([0-9]{1,2})', MainPage)], debug=True)
        • ถ้าเกิดมีการเรียกเข้ามาโดยไม่ได้ใส่ค่านั้นใน URL, ตัวแปร year, month จะกลายเป็นค่า None  และสามารถเช็คค่าได้โดยการใช้  if year is None:
    • เนื่องจาก webapp2 นั้นอัพเกรดมาจาก webapp ดังนั้นจะต้องตามอ่าน documentation ของทั้งสองตัว
    • self มีอะไรให้เล่นหลายอย่าง อ่านเพิ่มตามนี้ http://webapp-improved.appspot.com/guide/handlers.html
    • WSGIApplication เป็นตัวกำหนด routing ให้กับระบบ
    • debug=True บอกว่าถ้าเกิดมีอะไรเกิดข้อผิดพลาดในโปรแกรม(ไม่ใช่เฉพาะrouting) ให้แสดง error trace บนหน้าเวปด้วย
  10. ทดลองรันบนเครื่องตัวเองด้วยคำสั่ง
    • <path ไป AppEngine SDK>/dev_appserver.py   <path ไปหาโค้ด>
    • เช่น /opt/google_appengine/dev_appserver.py   /codes/helloworld/
    • โดย default ตัว server จะ bind ไว้กับ  127.0.0.1:8080
      • ถ้าจะเปลี่ยน bind IP ให้ใช้  -a 0.0.0.0
      • ถ้าจะเปลี่ยน bind port ให้ใช้  --port 80    (อาจจะต้องการสิทธิ์ root สำหรับ port < 8000)
  11. อัพโหลดขึ้น Google App Engine cloud
    1. ไปที่ https://appengine.google.com/ แล้ว login เข้าโดยใช้ gmail
    2. สำหรับคนที่ไม่เคยสร้างเลย อาจจะต้อง verify ตัวเองก่อน โดยการใช้เบอร์โทรศัพท์ เพื่อที่จะรับโค้ดจาก Google ผ่านทาง SMS แล้วจึงนำโค้ดนั้นมากรอกบนหน้าเวปอีกที
    3. เมื่อ verify ผ่านแล้ว  จะเริ่มสร้าง Application (สร้างได้มากสุด 10 applications) โดย
      1. กดปุ่ม Create Application
      2. ก็จะมีให้กำหนดชื่อตัวโปรแกรม Application Identifier ชื่อนี้จะถูกนำไปใช้เป็น URL ด้วย คือจะได้ <appid>.appspot.com
      3. Application Title คือชื่อที่เราคนเดียวจะเห็นเวลาเราเข้ามาดูรายการ application เพราะถ้ามีหลาย application แล้วจะได้ไม่สับสน
      4. กด Create Application
    4. เมื่อสร้าง application เรียบร้อยแล้ว ให้กลับไปแก้ไฟล์ app.yaml เพื่อให้บรรทัด application: ..... มีชื่อตรงกับ Application Identifier ที่เราเพิ่งสร้างขึ้นมา
    5. เมื่อเรียบร้อยแล้ว  ใช้คำสั่งต่อไปนี้ เพื่ออัพโหลด application ขึ้นไป
      • <path ไป AppEngine SDK>/appcfg.py  update  <path ไปหาโค้ด>
      • เช่น  /opt/google_appengine/appcfg.py  update  /codes/helloworld/
      • หรือจะระบุ email ของ account ที่ใช้ login ไปเลยก็ได้โดย เพิ่ม --email=a@gmail.com
  12. เช็คเวบไซต์ที่ http://<appid>.appspot.com ว่าทำงานได้ถูกต้องหรือไม่


References:




8/20/2012

How to Sending Keystrokes Using Ruby

Sending keystrokes requires heavily on interfacing with operating system. Therefore, the solution for Ruby to do this is different for each operating system.

For me, I'm using Ubuntu, and I found couple of tools to use purely out-of-the-box (I mean as a command-line.) These tools are:

Xautomation
My opinion, this is quite useful if you want to send a string, some characters, or single keystroke. But sending combined keystroke is a bit harder and longer to do as demonstrated in the picture below. Another point is, this tool does not have a feature to send keystrokes to a specific a application window. It only can accepts "xwindow" parameter which allows us to send a keystroke to a specific Xwindow(e.g. :0), but cannot specify which application (in that xwindow) it sends to. My guess, it only send to an active application's window only.

To install on Ubuntu:
sudo apt-get install xautomation

After installation, the command that comes with this package is not actually same as package's name, it's "xte". This tool allows you to send commands, such as "str", "key", "keyup", "keydown", "mouseclick", "mouseup", "mousedown", "mousemove", and also delay commands, such as "sleep".

Usage:
xte command param


Xdotool
I found this tool because I wanted to use a Ruby gem package called "xdo" and it requires this command line tool. It turns out this "xdotool" is a powerful tool by itself, and the ruby package("xdo") is just a ruby interface of this tool. Here are reason why I think it's more powerful than Xautomation:
  • it can send keystrokes easier, e.g. xdotool key "ctrl+c"
  • it can specified application's window it sends the keystrokes to
  • it can be set to have delay between keystrokes (default = 12ms)
  • since it allows to send keystrokes to a target window, it has its own window manipulation module built-in, which allows us to:
    • search for a window using window's title name, xwindow, desktop, pid
    • set focus/unfocus the window
    • bind window event, such as mouse-enter, mouse-leave, mouse-click, focus, etc. to an xdotool's command or external command
    • resize, minimize, , close, move window

To installation on Ubuntu:
sudo apt-get install xdotool

Usage:
xdotool command param



** I also found another tool, called "X11-guitest" which seems to be a tool/library in Perl language. Since it's in Perl, not Ruby, so I don't include it here :P

Now, It's time to write code on Ruby
As I have explain above, I am using "xdo" package on Ruby which is an interface to Xdotool. So the process of using Xdo is very similar to Xdotool on command line.

First, get started by install "xdo" gem package
sudo gem install xdo

Then, write code to use Xdo.

Here's my code to cheat on Google's doodle game, "Slalom Canoe 2012"
This game needs a player to press Left and Right alternatively, and repeatedly, as fast as possible.
So why not write a script to do it.
This should work the same way as AutoIt does on Windows, or way better because it is Ruby :)

#!/usr/bin/env ruby

# includes Xdo package
require 'xdo/keyboard'
require 'xdo/mouse'
require 'xdo/xwindow'

# search for window id using title name
win_id = XDo::XWindow.search("Slalom Canoe 2012").last 

# Uncomment to bring the window up (I don't need to bring it up)
# window = XDo::XWindow.new(win_id) # create window object (this does not create an actual new window)
# window.unfocus  #make sure the window is not focus before call .activate
# window.activate #bring the window up

# loop 1000 times to send left and right to the window
1000.times do
 XDo::Keyboard.char("Left",win_id);
 XDo::Keyboard.char("Right",win_id);
end


One thing to point out in the VDO, this code does not require the window to be focused before sending the keystrokes. It can send to any unfocused or minimized window. This could turn into a malicious annoying keystroke bastard program. LOL.

For those who live on Windows
You can try AutoIt , so you don't have to write ruby code like this.
Just in case, you want to try writing Ruby code to sending keystrokes, I found two projects that can do this.

Au3 
This is a Ruby package acting as an interface to AutoIt library. That's why its requirement is "AutoItX3.dll" which you need to install AutoIt first, then copy the file from it. Au3 also created from the same team (Automations) who created Xdo.

FFI
This is totally different from the above packages. While it still acts as a proxy between Ruby code and native libraries, it does not specified the native library nor function to bind with. Therefore, you can bind it with LibC (on linux), user32.dll(on Windows), kernel32.dll(on Windows).
To send a keystroke on Windows, you need to call "kbd_event" function, on "user32.dll".

I have not yet tried these two out. So I don't know what to say on this. If anyone has tried it, please let me know on the comment below.

References:

8/02/2012

Install Conky on Ubuntu - Cool System Monitor

Conky is an application on Ubuntu for monitoring system status. It provides:

  • Date & Time
  • CPU utilization
  • Memory utilization
  • Hard disk & swap utilization
  • Network utilization
  • Be able to continuously execute commands
  • Display running processes (from "top" command)
  • Display IP addresses
  • Display kernel version and hostname
My screen is look like this now (minus the processes bar).

Individual Conky

Steps:
  1. install conky application: execute the line below
    sudo apt-get install conky conky-all
    
  2. choose theme: choices are:
    1. http://gnome-look.org/content/search.php and search for "conky"
    2. or download my version. It was "Conky Lua" theme, then I modified it a little bit to display Blackbuntu logo, IP addresses and processes .
  3. install theme: extract the downloaded theme file and copy them into directories
    1. other themes may have different way to put theme file in, so read their instruction for properly put the files
    2. but basicaly it would be like mine, which are
      1. put ".conkyrc" in your home directory (e.x. my home is at /home/anidear)
      2. put "blackbuntu_logo.png" into ".conky" directory in home directory (ex. /home/anidear/.conky) If the ".conky" directory does not exist, create it.
      3. put "clock_rings.lua" into ".lua/script" in home (so it'll be in /home/anidear/.lua/scripts) And again, if it does not exist, create it.
  4. test run: you can type "conky" into command line to see how it's running. 
    1. While it is running, if you edit ".conkyrc" file and save, Conky will update it using the new configuration automatically.
    2. Press "Ctrl+C" on the command line to stop the running process.
  5. set it to run at startup
    1. go to either "System -> Preferences -> Sessions" or "System -> Preferences -> Startup Applications"
    2. add the new startup running program (with delay 20 seconds before it starts to let system finished loading)
      • Name: Conky
      • Comment: Conky System Monitor
      • Command: sleep 20 && conky
    3. close