YJ Park 的个人资料YJPark照片日志列表更多 工具 帮助

YJ Park

第 1 张,共 2 张

YJPark

Living & Programming (This BLOG will not be updated in the future, please visit http://yjpark.blogspot.com for future updates) (or http://www.pkblogs.com/yjpark if blogspot.com is not reachable for you)
2007/8/1

Web park prototype release (See more than 1 pages in one tab)

Current I am using a relative big screen(22' widescreen LCD) which is at 1680X1050. It's pretty good, but it's hard to utilize it when surfing web, most web pages will only take a small part of the whole screen, for example a maximized firefox browsing google will look like this:
I really don't like the blank area, so I develop a prototype for using the big screen more efficiently, currently it looks like this:


As you can see, two different pages are shown together(it's configurable, if you have a really big screen, you can show more than 2 pages). and click on google's search result will load the page on it's right, so to me, means a lot of tab operations become needless.

This project is currently in a very early stage, only have some basic functions, if you want to try it out, just visit http://yjpark.3322.org/webpark, click the left-top button to install an extension for firefox (It's needed to add hook to user's click)

The second button is for login which is not implemented yet, the third can config how many pages you want to see in the window, the fourth can add a new page. on right side, each opened page will have a thumbnail(currently all same, will customize it in the future), you can click on it to switch(sub page will have no thumbnail, a sub page is the one which supposed to be on a new window, but with the extension, I can catch it and display it on right of the original page). the small buttons on top of each page can be used to maximize and close a page.
2006/12/11

Backup svn local modifications

When we are working on a task, our local modifications are not in repository yet, so it's not safe, I don't want to make branch just for backup, so I wrote a script to backup local modifications, here is the script:

backuptask

#!/bin/bash

if [ -f TASK ] ; then
    echo
else
    echo There is not TASK file here, you must specify the task name in TASK
    exit -1
fi

export task=`cat TASK`
echo Backup Task: $task

# Create task dir if needed
if [ -d ~/tasks/$task ] ; then
    echo
else
    mkdir ~/tasks/$task
fi

svn info > svn.info

datestr=`date "+%Y-%m-%d_%H_%M"`
filename=${task}_${datestr}.tar
list=`svn status`
for line in $list; do
    if [ -f $line ]; then
        tar uvf $filename $line
    fi
done

gzip $filename
filename=$filename.gz

scp $filename yjpark@exobox:~/backup/tasks/
cp $filename ~/tasks/$task/
mv $filename ~/tasks/$task/current.tar.gz

You need to have a file named as 'TASK' in your working directory, it has only one line with the task's name, I put my backups in '~/tasks/' , you can change it if you want, and I scp the backup file to yjpark@exobox, you need to change the user and host name.

Use kompare for svn diff and code reviews

Before commit, we need to read the diff, that is done by svn diff, while the result is not easy to read, using kompare, the diff is much easier to read, here is the script I use for this

svndiff
if [ $2 ] ; then
    svn diff --diff-cmd=diff -x "-u10000" -r$1:$2 | kompare -
else
    svn diff | kompare -
fi

If provided two parameters, this command will show svn diff of two revisions, with 10000 lines context(I just want to see the whole file if there is diff, this is useful for doing code reviews), pipeline the output to kompare; otherwise, It will just use kompare to show the output of svn diff,
2006/11/16

Turbo dojo widgets

Background

In our project, we chose dojo as the AJAX toolkits, we use dojo widget programmatically, it's easy to use and easy to extend, but dojo's widget has big performance problem in our project.

In one page, we can have thousands of widgets, creating a widget in dojo is really slow, showing such a page needs like 20 minutes 100% CPU usage, it's far from acceptable, so I have to figure out some method to boost dojo dramatically.

dojo's widget is very powerful, you can define attach points and connect events in the templates, then dojo will parse the templates and pick up all the custom tags and process on them, after reading some dojo source code, I found out that the template parsing is the most time consuming part in widget creations, it takes like 80-90% of the whole time, so I decided to try to optimize this part first.

Every time creating a widget with dojo.widget.createWidget(), the template of that widget will be parsed, that is actually not needed, every kind of widget will have same template, so the result of the first parse can be cached, then it's not needed to parse the same template anymore.

I've seen some one in dojo's maillist talking about cloning a widget, I think it's the same idea I have here, but I don't have enough time to actually patch dojo to have a faster widget creation, so I first do some work to help our project running fast with dojo.

As I said before, our project create all the widgets in javascript, my turbo way only work in this scenario, if you want to use the widgets in html, this post can not help you.

My trick

common/turbo.js

dojo.provide("common.turbo");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Manager");

_cachedWidgets = {}

common.turbo.createWidget = function(name, props, refNode, position){
var prototype = _cachedWidgets[name];
if (prototype == undefined){
prototype = dojo.widget.createWidget(name, props, refNode, position);
if (prototype["turboInit"] != undefined){
prototype.widgetType = name;
prototype.index = 0;
_cachedWidgets[name] = common.turbo.cloneWidget(prototype, {}, false);
prototype.turboInit();
}else{
//alert(name);
}
return prototype;
}
var result = common.turbo.cloneWidget(prototype, props, true);
if (refNode != null) refNode.parentNode.replaceChild(result.domNode, refNode);
return result;
}

common.turbo.cloneWidget = function(prototype, props, init){
var result = {};
for (k in prototype) result[k] = prototype[k];
for (k in props) result[k] = props[k];
var widgetId = props["id"];
result.index = ++prototype.index;
if (widgetId != undefined){
result.widgetId = widgetId;
}else{
result.widgetId = prototype.widgetType + "_" + result.index;
}
result.domNode = prototype.domNode.cloneNode(true);
if (init) result.turboInit();
dojo.widget.manager.add(result);
return result;
}

The logic here is simple, in our javascript code, we call common.turbo.createWidget() instead of dojo.widget.createWidget() to create a widget.

In common.turbo.createWidget(), it will call dojo.widget.createWidget() to create the first widget, so I don't need to write code to parse template and can keep using most of dojo's power(will talk about the limitation later), then after got the widget created, we check whether it has a method named as turboInit(), if it does, then means this widget is one of our turbo widgets, then we can use common.turbo.cloneWidget() to get a clone and cache it, then if the same type of widget is needed in the future, the cached prototype can be used to make another clone, then we make sure dojo's slow widget creation will only happen once per type, that is acceptable.

Here is an example of turboed widget

dojo.provide("common.widget.Button2");
dojo.widget.manager.registerWidgetPackage("common.widget");

dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Button");

dojo.widget.defineWidget(
"common.widget.Button2",
dojo.widget.html.Button,
{
templateString: '<div class="dojoButton" style="position:relative;">'
+ '<div class="dojoButtonContents" align=center dojoAttachPoint="containerNode" style="position:absolute;z-index:2;"></div>'
+ '<img dojoAttachPoint="leftImage" style="position:absolute;left:0px;">'
+ '<img dojoAttachPoint="centerImage" style="position:absolute;z-index:1;">'
+ '<img dojoAttachPoint="rightImage" style="position:absolute;top:0px;right:0px;">'
+'</div>',

turboInit: function(){
this.containerNode = this.domNode.childNodes[0];
this.leftImage = this.domNode.childNodes[1];
this.centerImage = this.domNode.childNodes[2];
this.rightImage = this.domNode.childNodes[3];

this.containerNode.innerHTML = this.caption;
this.sizeMyself();

dojo.event.connect(this.domNode, "onmouseup", this, this.onMouseUp);
dojo.event.connect(this.domNode, "onmousedown", this, this.onMouseDown);
dojo.event.connect(this.domNode, "onmouseover", this, this.onMouseOver);
dojo.event.connect(this.domNode, "onmouseout", this, this.onMouseOut);
dojo.event.connect(this.domNode, "onclick", this, this.buttonClick);
}

}
);

This is a subclass of dojo.widget.html.Button, in turboInit(), it rebuild the dojoAttachPoint from domNode, and attach events.

The usage of Button2 is same with other widget, just use common.turbo.createWidget() to create it.

By using this simple technology, our ajax page is pretty fast now, the same page now only takes like 20-30 seconds in widget creation part. Then with some lazy loading tech, our project is fast enough now.

The limitation of this approach

The dojoAttachPoint and dojoAttachEvent only works for the first widget, all cloned widgets needs to set them up in turboInit(), now for my own widget, I just don't use them in templates, in the case of changing a current widget like the example of Button2.js, I leave them in template and setup them up again in the turboInit() now.

And for better perforamnce, I didn't call all the functions dojo calls when create a new widget, e.g. postMixInProperties() and postCreate(), it's easy to call them in common.widget.cloneWidget(), while in our project it's not needed.

The simple clone in common.widget.cloneWidget() is not a deep one, I think this is better, you can choose deep copy some property of reinitialize it in turboInit().

Not all properties needs to be copied, actually some of them may have wrong value after the copy.

Future work

As I said, if I add the similiar hack to dojo's framework, then it's possible to just make all template parsing cached for all type of widgets, and don't need the turboInit() trick. This may or may not be easy, if I got time, will try to figure it out.

2006/9/21

Use Mpd to Stream Music as Internet Radio

Mpd can work with icecast for streaming music, but the current statble version doesn't include this feature yet, so you have to check out the latest code from svn, here are the commands I used to build it.

sudo apt-get install icecast2
sudo apt-get install autoconf automake1.9 libtool make
sudo apt-get install libshout3-dev liblame-dev libmad0-dev libao-dev libflac-dev libasound2-dev
svn co https://svn.musicpd.org/mpd/trunk mpd
cd mpd
./autogen.sh
./configure
#make sure the shout is enable
make
sudo make install

Or if you are lazy can download the binary I built, but make sure to install the needed libs

wget http://yjpark.googlepages.com/mpd
sudo mv mpd /usr/bin

In your mpd configuration (/etc/mpd.conf or ~/.mpdconf), add these lines

audio_output {
        type              "alsa"
        name              "local playback"
}

################# SHOUT STREAMING ########################
#
# Set this to allow mpd to stream its output to icecast2
# (i.e. mpd is a icecast2 source)
#
audio_output {
        type              "shout"
        name              "yjpark's stream"
        host              "localhost"
        port              "8000"
        mount             "/yjpark"
        password          "******"
        quality           "10.0"  
#       bitrate           "64"
        format            "44100:16:2"

# Optional Paramters
        user            "source"
#       description     "here's my long description"
#       genre           "jazz"
} # end of audio_output
##########################################################

If you don't want to hear the music from the computer's local speaker, can remove the first audio_output section.

You need to change the name and mount point and password, and can change the quality or bitrate and format if you want, for more detail please check icecast2's documents.

And you need to edit /etc/icecast2/icecast.xml, the only things I changed are source-password(same as the one in mpd configuration), and admin-user, admin-password(can use this to admin through web interface)

then restart icecast2 and mpd, play some songs, then you can use a browser to connect to http://localhost:8000, you should see the source played by mpd, then can listen to it using an radio player(amarok, rhythembox, xmms...)

For the guys in ExoWeb, you can listen to the same songs I am listenning with http://yjpark:8000/yjpark.m3u (Hope this will not slow down my machine too bad :) )

Links:

    * http://my.opera.com/chongmeng/blog/show.dml/362421
    * http://mpd.wikia.com/wiki/Configuration
    * http://etnoy.broach.se/2006/06/your-own-internet-radio-station-with-mpdicecast.html
 
Thanks for visiting!
请稍候...
很抱歉,您输入的评论太长。请缩短您的评论。
您没有输入任何内容,请重试。
很抱歉,我们当前无法添加您的评论。请稍后重试。
若要添加评论,需要您的家长授予您相应权限。请求权限
您的家长禁用了评论功能。
很抱歉,我们当前无法删除您的评论。请稍后重试。
您已超过了一天之内允许提供的评论数上限。请在 24 小时后重试。
因为我们的系统表明您可能在向其他用户提供垃圾评论,您的帐户已禁用了评论功能。如果您认为我们错误地禁用了您的帐户,请联系 Windows Live 支持部门
完成下面的安全检查,您提供评论的过程才能完成。
您在安全检查中键入的字符必须与图片或音频中的字符一致。