增加虚拟机空间的一些方法

On 十一月 20, 2011, in 技术记录, by pensz

下面的讨论基于virtualbox(我选择virtualbox的原因是它免费,且支持各个平台),虚拟机为linux,宿主操作系统不限。

经常一开始建了一个固定大小的虚拟硬盘用来安装虚拟机,但过段时间数据越来越多,最终发现其空间不够用,这时候就很郁闷了,但如果不是你系统的目录不够用的话,下面的办法可以解决空间不够的问题:

1 增加一个虚拟硬盘的方法

优点:虚拟机中读写速度较快,虚拟硬盘也可以后面给其他的虚拟机使用

缺点:宿主机器无法读写块虚拟硬盘中的内容

操作方法:

1.1 先给虚拟机配备一个动态大小的虚拟硬盘

这个和一般的装虚拟机新建虚拟硬盘一样的操作。

打开虚拟机的配置 > storage 增加SATA控制器,然后在SATA控制器下增加一块虚拟硬盘;或者直接在IDE controller下面新增一块虚拟硬盘。

1.2 在虚拟机中进行分区,格式化,然后挂载

1.2.1 分区:

PS:必须要在root下操作,下面的描述中,橙色字体的为输入的命令。

先用fdisk -l看看,如果没有找到你的虚拟硬盘,那就是前面的虚拟硬盘没有配置对。

root@dev-desktop:/home/dev# fdisk -l
Disk /dev/sda: 8589 MB, 8589934592 bytes255 heads, 63 sectors/track, 1044 cylindersUnits = cylinders of 16065 * 512 = 8225280 bytesDisk identifier: 0×00015130
Device Boot      Start         End      Blocks   Id  System/dev/sda1   *           1         993     7976241   83  Linux/dev/sda2             994        1044      409657+   5  Extended/dev/sda5             994        1044      409626   82  Linux swap / Solaris
Disk /dev/sdb: 2845 MB, 2845835264 bytes255 heads, 63 sectors/track, 345 cylindersUnits = cylinders of 16065 * 512 = 8225280 bytesDisk identifier: 0×00000000
Disk /dev/sdb doesn’t contain a valid partition table

可以看到第二块虚拟硬盘 /dev/sdb 上面没有任何分区信息,当然无法用了。

接着 fdisk /dev/sdb 在第二块虚拟硬盘上建立分区,关于fdisk的详细用法请在进入fdisk后按m或者搜索之。

root@dev-desktop:/home/dev# fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabelBuilding a new DOS disklabel with disk identifier 0xadff2d79.Changes will remain in memory only, until you decide to write them.After that, of course, the previous content won’t be recoverable.
Warning: invalid flag 0×0000 of partition table 4 will be corrected by w(rite)
Command (m for help): n

Command action

e   extended
p   primary partition (1-4)p

Partition number (1-4): 1
First cylinder (1-345, default 1): 1

Last cylinder or +size or +sizeM or +sizeK (1-345, default 345):
Using default value 345
Command (m for help): w

The partition table has been altered!

1.2.2 格式化

有分区了,还是无法使用的,这时候需要格式化,linux下普遍使用的是ext3。我们通过mkfs对刚才的分区格式化:

root@dev-desktop:/home/dev# mkfs.ext3 /dev/sdb1
mke2fs 1.40.8 (13-Mar-2008)Filesystem label=OS type: LinuxBlock size=4096 (log=2)Fragment size=4096 (log=2)173888 inodes, 692795 blocks34639 blocks (5.00%) reserved for the super userFirst data block=0Maximum filesystem blocks=71303168022 block groups32768 blocks per group, 32768 fragments per group7904 inodes per groupSuperblock backups stored on blocks:  32768, 98304, 163840, 229376, 294912
Writing inode tables: done
Creating journal (16384 blocks): doneWriting superblocks and filesystem accounting information: done
This filesystem will be automatically checked every 38 mounts or180 days, whichever comes first.  Use tune2fs -c or -i to override.

1.2.3 挂载

通过mkdir先建立一个挂载点,如在根目录下建立一个data目录用于挂载 mkdir /data/

root@dev-desktop:/home/dev# mount /dev/sdb1 /data/

通过df命令看看挂载情况,如果有相应的挂载信息就ok了。

root@dev-desktop:/home/dev# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             7.6G  6.1G  1.2G  85% /
varrun                352M  128K  352M   1% /var/run
varlock               352M     0  352M   0% /var/lock
udev                  352M   48K  352M   1% /dev
devshm                352M     0  352M   0% /dev/shm
lrm                   352M   40M  313M  12% /lib/modules/2.6.24-27-generic/volatile
/dev/sdb1             2.7G   69M  2.5G   3% /data

1.2.4 设置 /etc/fstab

做这一步的目的在于将第二块虚拟硬盘的信息写入系统分区信息表,便于开机自动挂载,否则,每次都需要手动去mount

在目前的/etc/fstab文件后面增加一行

/dev/sdb1       /data           ext3   defaults 0 2

关于fstab的配置和各个参数的含义,可以自行搜索之。

2 和宿主机器通过数据空间共享的方法

优点:宿主和虚拟机都可以操作共享的文件,虚拟机内的空间完全决定于宿主机器的物理硬盘和实际分区,虚拟机开启后也可以使用该办法。

缺点:速度较慢

方法:

在虚拟机的设置 > 数据空间中设置宿主的目录和权限。

进入虚拟机后以root身份运行以下命令:

mount -t vboxsf  数据空间名称  挂载点

总结:如果你在宿主能够访问虚拟机中文件这方面没有需求,推荐使用增加虚拟硬盘的方法。

Tagged with:  

让mac的cpu不再狂转

On 十月 29, 2011, in mac os, by pensz

众人皆知,在mac上,flash绝对是cpu杀手,只要一开有flash的网站,那cpu马上疯狂的转,不知道是adobe的问题,还是mac的问题。

鉴于此,禁用flash是个最直接的解决方法,而且一般网站大部分flash都是广告。safari中推荐使用 clickplugins这个扩展,他可以将flash暂时屏蔽,若你需要看,点击一下即可。firefox中同样有这样的插件,名字叫做flashbock,使用方法一样,需要看的时候点一下。

关于视频网站的解决方法:在safari中可以将user agent设置为iPad,这样,大部分视频网站将会给你html5的视频,这样播放起来无压力。firefox下由于不支持html5,那都是浮云了。事实上,clickplugins这个插件会对国外网站上的视频转成html5,无需切换user agent,可惜这些网站在我朝是不存在的。

Tagged with:  

关于js执行顺序和jquery.html

On 十月 28, 2011, in 技术记录, by pensz

下面这些知识虽然是前端相关的,但是做为一个想深入web的人,还是非常有必要知道的。很多时候当前端跟你抱怨为什么我的js中明明声明了变量,但还报未定义的错;为什么我写一个alert调试就好了?很有可能就是下面所提到的问题。

1 js为什么不按代码中的次序执行了?

正常的html中外联script,script无法并行下载,阻塞后面其他资源的下载;且执行顺序可以得到保证(新版本浏览器有改进,可以并行下载js,执行顺序也会保证)。所以我们一般在html中写的js都没有问题,但问题是,这个会影响整个网页相关资源下载速度。

鉴于此,人们又想了很多方法来“欺骗”浏览器,以达到加速下载js和相关资源文件的目的,方法大概有以下几种:

  • XHR Eval :ajax获得js内容,然后执行
  • XHR Injection : ajax获得js内容,然后创建一个script的node,插入到文档dom tree中
  • Script in Iframe : iframe src为js文件
  • Script DOM Element :动态创建script,然后设置其src
  • Script Defer : script标签加入 defer属性
  • document.write Script Tag :document.write(“<script type=’text/javascript’ src=’A.js’><\/script>”);

既然可以并行下载,那么执行顺序就是一个需要确认的问题了,可惜的是,不是每种技术都能保证脚本执行的次序。具体情况可以参考下表(节选自 《Even Faster Web Sites》):

2 jquery的html函数好像有时候也不灵啊!

假设我们如此调用:

$(‘#content’).html(data);

jquery 的html函数使用同步ajax下载data中的外联js。对于inline的js,执行Script DOM Element在head节点插入一个script节点。

从上面的分析来看,data中js的执行顺序是可以保证的。但有时调用jquery.html,却仍然出现执行顺序混乱的情形,原因是外联的js是不同的域。由于ajax无法跨域,故这时候无法通过同步ajax下载来加入外联js,而是通过和内联js一样的方式:将外联的js以Script DOM Element 的方式插入到head节点。按照上面的图,执行顺序是无法在所有浏览器上保证的(ensures order)。

解决方法: 在调用jquery.html前,使用 document.write Script Tag将外联的js载入。

3 文章开头提到的问题

外联js定义了js变量,但还报undefined错:很有可能就是执行顺序不对,执行使用变量的代码时,定义的js虽然在前面,但还没有下载完呢。

alert一下,一切就是好的了:还是一个道理,定义的外联js没有下载完成,同时,你可以试试setTimeout,将你使用外联js的变量的代码晚点执行,也会是好的。

4 参考资料

下面这些资料,非常值得一读:

  • 《Even Faster Web Sites》
  • http://www.cnblogs.com/sanshi/archive/2011/02/28/1967367.html
  • http://www.cnblogs.com/sanshi/archive/2011/03/01/1968275.html
  • http://www.cnblogs.com/sanshi/archive/2011/03/02/1969224.html
Tagged with:  

从leopard升级到lion

On 十月 19, 2011, in mac os, by pensz

1 前言

话说上回将iPad2升级至iOS5,正欢天喜地的尝试wifi同步,但可惜的是我的leopard系统里面竟然连wifi同步选项都没有!我非常、极其的生气,打了一通apple的客服,无果;上苹果的论坛一看,一大堆人反映和我一样的问题。有人实测,只有在10.6.8后才能够wifi同步,连10.6.6都不行。我恨啊。

难道真的要升级系统了吗,现在老系统的问题越来越多,主要有以下方面:

  1. 输入法,可恨的输入法,竟然大部分都不支持10.6.8以下的系统
  2. 还是输入法,10.5.8里面不能设置不同窗口使用不同输入法,实在不爽(据说10.4还是可以设置的)
  3. 没有mac app store,下载软件完全靠游击战
  4. qq等很多软件不再支持10.6.8以下
  5. webkit在编译有些部分时,不支持10.6以下的系统
  6. 刚才说的,没有办法和iOS设备wifi同步

之前没有升级,主要是偶尔工作时会用,当心开发环境什么的;现在好些了,那狠下心来升级吧,为避免后面再升级,准备现在一次升到lion算了,同时,加内存到8G。

 

2 升级过程

升级的过程是 10.5.8 -> 10.6.3 -> 10.6.8 -> 10.7 -> 10.7.2,也就是从leopard到snow leopard再到lion,因为leopard是无法直接升到lion的。

其中10.6.3 -> 10.6.8和10.7 -> 10.7.2算更新,去apple网站下载更新包即可;其他的嘛,要么买正版(其实也不贵,snow lepord卖¥248,lion 下载时卖$29.9),要么你懂得。

升级到10.6.3的时候,最后时刻出现了安装失败,真的是让我心都凉了;幸好重新安装后成功,估计是光驱读盘的问题吧。

硬件的升级放在了安装上10.6.8之后,原有的2G内存早已不够lion用的了。内存倒是亲民价,2条4G的三星金条连350都不到。

拆开后盖,拔出之前的内存,换上新的内存(顺便可以清理一下风扇什么的),开机一次点亮。之前网上有人说可以使用1333MHz的内存,我这里算也是再次验证了,不过它工作的频率应该还是1066MHz。

系统信息

下面是我机器的更加详细的信息,可以看到,虽然是2008年后期的mb 466,但是还是可以升级到lion的。
系统简介

整个升级过程还算顺利,只需开机放入光盘或者点击安装程序即可,默认情况下也是升级安装,也就是说用户的程序(包括应用程序下的程序)和文档都还在的,甚至连之前应用程序的数据都在,比如safari的浏览历史,下载记录。iTunes无法识别iPad2,不过重装一下iTunes就好了,app、音乐以及图书都还在。

 

3 使用感受

  • 8G的内存没白加,lion使用起来还是非常顺畅的;另外,系统占的硬盘空间也比leopard少了4G左右。
  • 由于从leopard切换过来的,一时无法适应手势滚动方向的改变:之前leopard中,手势滚动的是滚动条,而现在lion滚动的是内容,这也和移动设备是一致的。
  • 手势程序切换以及全屏是目前使用起来比较舒服的功能。
  • safari浏览时,前进后退比以前更加酷了。
  • iTunes终于可以iPad2无线同步了。
Tagged with:  

iOS5使用有感

On 十月 14, 2011, in mac os, by pensz

ipad gestures

10月12号,apple正式发布iOS5,现在更新,虽然算不上第一时间,但这时候稳定些。下面将相关过程和初步使用体会分享一下。

更新的过程:

  1. 更新iTunes至10.5
  2. 直接在iTunes中升级至iOS5(也可以直接下载对应的固件文件,然后通过iTunes里面options(shift in windows)+恢复完成)

直接下载固件的列表:

关于更新后app都需要重新下、游戏记录都没有的问题,我这边倒是没有发现,更新后app照样在,照片也在。应该是始终用一台电脑的原因吧。总之,更新过程没有遇到什么问题,就是下载固件时间长了些。

使用感受,下面的功能是个人觉得比较好用的:

  1. 手势:通过手势切换应用程序,回到主屏幕,查看正在运行的程序等等;有了手势,可以少按home键了
  2. 更新的键盘:有输入法切换的改进,增加常用的符号输入,支持浮动、分开的布局键盘;总之,输入更加方便
  3. safari的更新,标签操作直接可以在safari的主界面搞定,和mac版的safari类似;另外还有read later以及阅读器的功能
  4. 和电脑通过wifi 同步,可惜我的Leopard系统(10.5.8)好像不支持,完全没有
  5. iCloud,可以同步一大堆数据
  6. 更好的通知中心

当然,也有些更新其实不是那么好玩了,比如报刊杂志,个人觉得是鸡肋,至于iMessage,我觉得还不好说呢。

Tagged with:  

10月4日,苹果举行了今年秋季的产品发布会。按apple之前的惯例,本应该今年早些时候发布新产品的;拖到现在,使很多投资者和消费者有了更多的期待,但总体来说还是让人比较失望的,这在苹果的股价上有很好的体现。发布会主要有以下信息:

  1. 没有iPhone5,只有iPhone 4 的升级版iPhone 4s,即使这样,连iPhone 4s的介绍也不是CEO Tim
  2. ios 5的介绍,主要是iCloud, Find my Friend 以及一个Card的程序
  3. iPod, iPhone产品全线降价
  4. 其他相关apple store, iPod, mac,iPhone, iPad, ios等数据介绍

其实我等围观之,主要是想要看看apple能够有哪些新功能的推出,但是创新也不是那么容易的,不可能每次发布会都能像iPhone, iPad刚推出来那样让人耳目一新。但个人觉得本次发布会,Siri还算是一个亮点了(Let ‘s talk iPhone 中 的talk应该是指这个意思吧),Siri虽然基础是语音识别,之前也有很多类似的语言识别程序,但之前的程序交互性不强,大多数的功能也是将语言转换成文字;而Siri则更在问答、帮忙人们完成任务这一方面更进一步。

 

上次和同事聊到了验证码中有表达式求值的问题,说起来应该是比较简单了,也是数据结构上经典的算法问题。可是自己写一写才会发现,做对一件看似简单的事情不是那么容易。

本来自己弄了一个c的stack,但是c没有模板,想不到怎么支持不同的类型,只好换用c++了。

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#include <stack>
#include <iostream>

using namespace std;

/**
 * 比较运算符之间的优先级
 */
static short int Precede(char c1, char c2) {
    if (c1 == c2) {
        if (c1 == '#') {
            return 0;
        } else if(c1 == '(') {
            return -1;
        } else {
            return 1;
        }
    }

    switch (c1) {
        case '+':
        case '-':

        if (c2 == '*' || c2 == '/' || c2 == '(') {
            return -1;
        } else {
            return 1;
        }
        break;

        case '*':
        case '/':
        if (c2 == '(') {
            return -1;
        } else {
            return 1;
        }
        break;

        case '(':
        if (c2 == ')') {
            return 0;
        } else {
            return -1;
        }
        break;

        case ')':
        return 1;
        break;

        case '#':
        return -1;
    }
}

/**
 * 对加减乘除进行求值
 */
static float Operate(float a, char theta, float b) {
    switch (theta) {
        case '+':
        return a+b;
        break;

        case '-':
        return a-b;
        break;

        case '*':
        return a*b;
        break;

        case '/':
        return a/b;
        break;
    }

    printf("bad operator");
    return 0;
}

int main() {

    stack<char> optr;
    stack<float> opnd;

    optr.push('#');

    char theta, tmp[20], *tmppoint, basechar[20];
    tmppoint = basechar;
    float a, b;

    char c = getchar();

    while (c!='#' || optr.top() != '#') {
        if (isdigit(c)) {
            *(tmppoint++) = c;
            c = getchar();
        } else {

            if (tmppoint > basechar) {
                *tmppoint = '\0';
                opnd.push(atof(basechar));
                printf ("push number %s\n", basechar);
                tmppoint = basechar;
            }

            if (c != '+' && c != '-' && c != '*' && c != '/' && c != '(' && c != ')' && c != '#' ) {
                c = getchar();
                continue;
            }

            short int precede = Precede(optr.top(), c);
            switch (precede) {
                case -1:
                optr.push(c);
                printf("pushed operator %c \n", c);
                c = getchar();
                break;

                case 0:
                optr.pop();
                c = getchar();
                break;

                case 1:
                theta = optr.top();
                optr.pop() ;

                if (opnd.empty()) {
                    printf("opnd is empty\n");
                }
                b = opnd.top();
                opnd.pop();

                a = opnd.top();
                opnd.pop();

                cout << " cal a=" << (float)a << " theta=" << theta << " b=" << (float)b << endl;

                opnd.push(Operate(a, theta, b));
                break;
            }
        }
    }

    /* 最后的结果 */
    printf("%f\n", opnd.top());
    printf("%c\n", optr.top());

    return 0;
}
Tagged with:  

从svn迁移到git

On 九月 26, 2011, in 技术记录, by pensz

最近需要从svn迁移到git了,之前虽然有简单的用过的git,但那远远不够,最近先花了点时间来看看git的使用。

git和svn的最大区别是git是分布式的,而svn仅仅是一个svn服务器,实际的来说,git有本地的代码库,可以离线提交自己的修改至本地的代码库。通过下面这个图可以有一个直观的印象。

若要修改代码,从一个版本库开始的方法:

  • git是git clone
  • svn是svn checkout

提交代码至远程服务器的方法:

  • git是git commit -am ‘comment’ 提交至本地的代码库,若要提交至远程服务器,再执行git push
  • svn 则很简单,svn commit即可

从中央服务器更新到本地代码的方法:

  • git是git fetch到本地代码库,然后再git merge,简单的办法是 git pull
  • svn很简单 svn update

撤销本地修改:

  • git是git checkout . (该命令就是将本地的workspace修改撤销至本地代码库)
  • svn是删除掉修改的文件,然后svn update

比较差异:

  • git是 git diff (获得当前workspace还没有计划提交的差异,若计划提交后但仍未提交至本地代码库则用git diff –cached)。 git diff  <remote_branch> <branch> (比较本地代码库和服务端的差异),一般的命令就是 git origin/master master
  • svn 则是svn diff即可

 

其他一些问题:

git 的本地代码库commit的撤销:

  • git revert 这个会撤销本地代码库的修改,但这个动作本身会创建一个版本,因此很容易搞混。
  • git reset –hard HEAD 这个会撤销本地代码库的修改。

git push 目标分支:

git push 可以将local的分支push到远程不同的分支上(non-fast-forwording),但是最好不要这么做。

合并本地分支:

git merge  和 git rebase, 这两个的动作都可以合并,但最终得到的分支线路会不太一样。

最简单的类似svn的工作流程:

git workflow

有用的参考:

  • http://progit.org/book/zh/
  • http://book.git-scm.com/index.html
  • http://schacon.github.com/git/everyday.html
Tagged with:  

关于C/C++的标准

On 九月 18, 2011, in 技术记录, by pensz

没有什么语言能够像C/C++这么NB了吧,这么多平台,这么多家大公司支持,拥有N多编译器,开发出来的产品大到操作系统,小到网页,C/C++无所不在;正是因为如此,弄清楚相关标准尤为重要,切不能道听途说。

这两个语言标准的情况如下:

C的标准是 ISO/IEC 9899:1999(也就是常说的C99)。

而C++较为稳定的标准是 ISO/IEC 14882:2003(C++03) ,wiki和blog上早在8月份就说ISO/IEC 14882:2011 (C++11或者C++0x) 已经在ISO通过了,而后在C++标准委员会的网站上也得到了证实(News 2011-09-11: The new C++ standard – C++11 – is published!)。

制定标准的是ISO/IEC C/C++标准委员会制定,要找标准,自然去找ISO(“黑心”的ISO组织,这两个标准都要卖钱的)。

关于C的标准可以参考以下pdf http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

而至于C++嘛,要自己根据标准名(ISO/IEC 14882:2003)去搜索一下咯。

 

参考资料:

Tagged with:  

快速排序

On 九月 12, 2011, in 技术记录, 数据结构和算法, by pensz

快速排序是分治法的思想,先设定一个标志,保证左边的数据不大于该标志,右边的数据都不小于该标志。然后分别对左右区域使用同样的处理方法,最终得到的序列即为有序序列。

下面是 c++ 的快速排序。

#include <iostream>
using namespace std;

/**
 * 调整数据,使得在一个位置左边的数据均小于 pivotkey, 右边的数据均大于 pivotkey
 */
int Partition(int *p, int low, int high) {
 int pivotkey = p[low];
 while (low < high) {
 while (low < high && p[high] > pivotkey) --high;
 p[low] = p[high];

 while (low < high && p[low] <= pivotkey) ++low;
 p[high] = p[low];
 }

 p[low] = pivotkey;

 return low;
}

/**
 * 快速排序
 */
void QuickSort(int *p, int begin,  int end) {
 if (begin < end) {
 int pivot;

 pivot = Partition(p, begin, end); // 进行一次分区
 QuickSort(p, begin, pivot-1); // 对左边的进行快速排序
 QuickSort(p, pivot+1, end); // 对右边进行快速排序
 }
}

int main() {
 int i, length, *p;
 cin >> length;
 p = (int *) malloc (length * sizeof(int));
 for (i=0; i<length; ++i) {
 cin >> p[i];
 }

 cout << "original" << endl;
 for (i=0; i<length; ++i) {
 cout << p[i] << endl;
 }    

 QuickSort(p, 0, length-1);

 cout << "sorted" << endl;
 for (i=0; i<length; ++i) {
 cout << p[i] << endl;
 }

 return 0;
}
Tagged with: