[转载]VirtualHost Examples - Apache HTTP Server

mikel阅读(821)

[转载]VirtualHost Examples – Apache HTTP Server.

This document attempts to answer the commonly-asked questions about setting up virtual hosts. These scenarios are those involving multiple web sites running on a single server, via name-based or IP-based virtual hosts.

top

Running several name-based web sites on a single IP address.

Your server has a single IP address, and multiple aliases (CNAMES) point to this machine in DNS. You want to run a web server for www.example1.com and www.example2.org on this machine.

Note

Creating virtual host configurations on your Apache server does not magically cause DNS entries to be created for those host names. You must have the names in DNS, resolving to your IP address, or nobody else will be able to see your web site. You can put entries in your hosts file for local testing, but that will work only from the machine with those hosts entries.

Server configuration

# Ensure that Apache listens on port 80
Listen 80

# Listen for virtual host requests on all IP addresses
NameVirtualHost *:80

<VirtualHost *:80>
DocumentRoot /www/example1
ServerName www.example1.com

# Other directives here

</VirtualHost>

<VirtualHost *:80>
DocumentRoot /www/example2
ServerName www.example2.org

# Other directives here

</VirtualHost>

The asterisks match all addresses, so the main server serves no requests. Due to the fact that www.example1.com is first in the configuration file, it has the highest priority and can be seen as the default or primary server. That means that if a request is received that does not match one of the specified ServerName directives, it will be served by this first VirtualHost.

Note

You can, if you wish, replace * with the actual IP address of the system. In that case, the argument to VirtualHost must match the argument to NameVirtualHost:

NameVirtualHost 172.20.30.40

<VirtualHost 172.20.30.40>
# etc ...

However, it is additionally useful to use * on systems where the IP address is not predictable – for example if you have a dynamic IP address with your ISP, and you are using some variety of dynamic DNS solution. Since * matches any IP address, this configuration would work without changes whenever your IP address changes.

The above configuration is what you will want to use in almost all name-based virtual hosting situations. The only thing that this configuration will not work for, in fact, is when you are serving different content based on differing IP addresses or ports.

top

Name-based hosts on more than one IP address.

Note

Any of the techniques discussed here can be extended to any number of IP addresses.

The server has two IP addresses. On one (172.20.30.40), we will serve the “main” server, server.domain.com and on the other (172.20.30.50), we will serve two or more virtual hosts.

Server configuration

Listen 80

# This is the "main" server running on 172.20.30.40
ServerName server.domain.com
DocumentRoot /www/mainserver

# This is the other address
NameVirtualHost 172.20.30.50

<VirtualHost 172.20.30.50>
DocumentRoot /www/example1
ServerName www.example1.com

# Other directives here ...

</VirtualHost>

<VirtualHost 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example2.org

# Other directives here ...

</VirtualHost>

Any request to an address other than 172.20.30.50 will be served from the main server. A request to 172.20.30.50 with an unknown hostname, or no Host: header, will be served from www.example1.com.

top

Serving the same content on different IP addresses (such as an internal and external address).

The server machine has two IP addresses (192.168.1.1 and 172.20.30.40). The machine is sitting between an internal (intranet) network and an external (internet) network. Outside of the network, the name server.example.com resolves to the external address (172.20.30.40), but inside the network, that same name resolves to the internal address (192.168.1.1).

The server can be made to respond to internal and external requests with the same content, with just one VirtualHost section.

Server configuration

NameVirtualHost 192.168.1.1
NameVirtualHost 172.20.30.40

<VirtualHost 192.168.1.1 172.20.30.40>
DocumentRoot /www/server1
ServerName server.example.com
ServerAlias server
</VirtualHost>

Now requests from both networks will be served from the same VirtualHost.

Note:

On the internal network, one can just use the name server rather than the fully qualified host name server.example.com.

Note also that, in the above example, you can replace the list of IP addresses with *, which will cause the server to respond the same on all addresses.

top

Running different sites on different ports.

You have multiple domains going to the same IP and also want to serve multiple ports. By defining the ports in the “NameVirtualHost” tag, you can allow this to work. If you try using <VirtualHost name:port> without the NameVirtualHost name:port or you try to use the Listen directive, your configuration will not work.

Server configuration

Listen 80
Listen 8080

NameVirtualHost 172.20.30.40:80
NameVirtualHost 172.20.30.40:8080

<VirtualHost 172.20.30.40:80>
ServerName www.example1.com
DocumentRoot /www/domain-80
</VirtualHost>

<VirtualHost 172.20.30.40:8080>
ServerName www.example1.com
DocumentRoot /www/domain-8080
</VirtualHost>

<VirtualHost 172.20.30.40:80>
ServerName www.example2.org
DocumentRoot /www/otherdomain-80
</VirtualHost>

<VirtualHost 172.20.30.40:8080>
ServerName www.example2.org
DocumentRoot /www/otherdomain-8080
</VirtualHost>

top

IP-based virtual hosting

The server has two IP addresses (172.20.30.40 and 172.20.30.50) which resolve to the names www.example1.com and www.example2.org respectively.

Server configuration

Listen 80

<VirtualHost 172.20.30.40>
DocumentRoot /www/example1
ServerName www.example1.com
</VirtualHost>

<VirtualHost 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example2.org
</VirtualHost>

Requests for any address not specified in one of the <VirtualHost> directives (such as localhost, for example) will go to the main server, if there is one.

top

Mixed port-based and ip-based virtual hosts

The server machine has two IP addresses (172.20.30.40 and 172.20.30.50) which resolve to the names www.example1.com and www.example2.org respectively. In each case, we want to run hosts on ports 80 and 8080.

Server configuration

Listen 172.20.30.40:80
Listen 172.20.30.40:8080
Listen 172.20.30.50:80
Listen 172.20.30.50:8080

<VirtualHost 172.20.30.40:80>
DocumentRoot /www/example1-80
ServerName www.example1.com
</VirtualHost>

<VirtualHost 172.20.30.40:8080>
DocumentRoot /www/example1-8080
ServerName www.example1.com
</VirtualHost>

<VirtualHost 172.20.30.50:80>
DocumentRoot /www/example2-80
ServerName www.example1.org
</VirtualHost>

<VirtualHost 172.20.30.50:8080>
DocumentRoot /www/example2-8080
ServerName www.example2.org
</VirtualHost>

top

Mixed name-based and IP-based vhosts

On some of my addresses, I want to do name-based virtual hosts, and on others, IP-based hosts.

Server configuration

Listen 80

NameVirtualHost 172.20.30.40

<VirtualHost 172.20.30.40>
DocumentRoot /www/example1
ServerName www.example1.com
</VirtualHost>

<VirtualHost 172.20.30.40>
DocumentRoot /www/example2
ServerName www.example2.org
</VirtualHost>

<VirtualHost 172.20.30.40>
DocumentRoot /www/example3
ServerName www.example3.net
</VirtualHost>

# IP-based
<VirtualHost 172.20.30.50>
DocumentRoot /www/example4
ServerName www.example4.edu
</VirtualHost>

<VirtualHost 172.20.30.60>
DocumentRoot /www/example5
ServerName www.example5.gov
</VirtualHost>

top

Using Virtual_host and mod_proxy together

The following example allows a front-end machine to proxy a virtual host through to a server running on another machine. In the example, a virtual host of the same name is configured on a machine at 192.168.111.2. The ProxyPreserveHost On directive is used so that the desired hostname is passed through, in case we are proxying multiple hostnames to a single machine.

<VirtualHost *:*>
ProxyPreserveHost On
ProxyPass / http://192.168.111.2/
ProxyPassReverse / http://192.168.111.2/
ServerName hostname.example.com
</VirtualHost>

top

Using _default_ vhosts

_default_ vhosts for all ports

Catching every request to any unspecified IP address and port, i.e., an address/port combination that is not used for any other virtual host.

Server configuration

<VirtualHost _default_:*>
DocumentRoot /www/default
</VirtualHost>

Using such a default vhost with a wildcard port effectively prevents any request going to the main server.

A default vhost never serves a request that was sent to an address/port that is used for name-based vhosts. If the request contained an unknown or no Host: header it is always served from the primary name-based vhost (the vhost for that address/port appearing first in the configuration file).

You can use AliasMatch or RewriteRule to rewrite any request to a single information page (or script).

_default_ vhosts for different ports

Same as setup 1, but the server listens on several ports and we want to use a second _default_ vhost for port 80.

Server configuration

<VirtualHost _default_:80>
DocumentRoot /www/default80
# ...
</VirtualHost>

<VirtualHost _default_:*>
DocumentRoot /www/default
# ...
</VirtualHost>

The default vhost for port 80 (which must appear before any default vhost with a wildcard port) catches all requests that were sent to an unspecified IP address. The main server is never used to serve a request.

_default_ vhosts for one port

We want to have a default vhost for port 80, but no other default vhosts.

Server configuration

<VirtualHost _default_:80>
DocumentRoot /www/default
...
</VirtualHost>

A request to an unspecified address on port 80 is served from the default vhost any other request to an unspecified address and port is served from the main server.

top

Migrating a name-based vhost to an IP-based vhost

The name-based vhost with the hostname www.example2.org (from our name-based example, setup 2) should get its own IP address. To avoid problems with name servers or proxies who cached the old IP address for the name-based vhost we want to provide both variants during a migration phase.
The solution is easy, because we can simply add the new IP address (172.20.30.50) to the VirtualHost directive.

Server configuration

Listen 80
ServerName www.example1.com
DocumentRoot /www/example1

NameVirtualHost 172.20.30.40

<VirtualHost 172.20.30.40 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example2.org
# ...
</VirtualHost>

<VirtualHost 172.20.30.40>
DocumentRoot /www/example3
ServerName www.example3.net
ServerAlias *.example3.net
# ...
</VirtualHost>

The vhost can now be accessed through the new address (as an IP-based vhost) and through the old address (as a name-based vhost).

top

Using the ServerPath directive

We have a server with two name-based vhosts. In order to match the correct virtual host a client must send the correct Host: header. Old HTTP/1.0 clients do not send such a header and Apache has no clue what vhost the client tried to reach (and serves the request from the primary vhost). To provide as much backward compatibility as possible we create a primary vhost which returns a single page containing links with an URL prefix to the name-based virtual hosts.

Server configuration

NameVirtualHost 172.20.30.40

<VirtualHost 172.20.30.40>
# primary vhost
DocumentRoot /www/subdomain
RewriteEngine On
RewriteRule ^/.* /www/subdomain/index.html
# ...
</VirtualHost>

<VirtualHost 172.20.30.40>
DocumentRoot /www/subdomain/sub1
ServerName www.sub1.domain.tld
ServerPath /sub1/
RewriteEngine On
RewriteRule ^(/sub1/.*) /www/subdomain$1
# ...
</VirtualHost>

<VirtualHost 172.20.30.40>
DocumentRoot /www/subdomain/sub2
ServerName www.sub2.domain.tld
ServerPath /sub2/
RewriteEngine On
RewriteRule ^(/sub2/.*) /www/subdomain$1
# ...
</VirtualHost>

Due to the ServerPath directive a request to the URL http://www.sub1.domain.tld/sub1/ is always served from the sub1-vhost.
A request to the URL http://www.sub1.domain.tld/ is only served from the sub1-vhost if the client sent a correct Host: header. If no Host: header is sent the client gets the information page from the primary host.
Please note that there is one oddity: A request to http://www.sub2.domain.tld/sub1/ is also served from the sub1-vhost if the client sent no Host: header.
The RewriteRule directives are used to make sure that a client which sent a correct Host: header can use both URL variants, i.e., with or without URL prefix.

[转载]怎么使用Appserv配置多站点访问

mikel阅读(1346)

[转载]怎么使用Appserv配置多站点访问 | PHP网站开发-PHP教程-LeapSoul.CN.

在之前的Appserv教程中,我介绍了AppServ配置与安装使用教程,Appserv作为PHP集成环境安装包,可以实现多种功能,配置Appserv实现多站点功能可方便PHP开发团队实时调试多个PHP网站,有访友向我提出怎么使用Appserv配置多站点问题,通过实践验证后,我以Appserv教程形式来作下解答。

Appserv配置多站点教程第一步:下载Appserv并安装

我下载的是Appserv-Win32-2.5.10版本,下载后直接双击并根据提示安装即可。

Appserv配置多站点教程第二步:修改Windows系统hosts文件

我的Appserv安装环境是WindowsXP,为什么首先要修改hosts文件呢?这是因为一般情况下Appserv的安装调试都是在本机 上进行的,当使用Appserv配置多站点时,域名指向都是127.0.0.1,你需要对不同的域名进行映射,否则即便配置完毕也是无法访问的,除非你有 公网IP,并通过DNS进行映射。

找到WINDOWS\system32\drivers\etc\hosts文件并打开,找到127.0.0.1  localhost,并添加需要映射的测试站点域名,比如

1
2
3
127.0.0.1  www.leapsoul.cn

127.0.0.1  www.phptest.cn

保存hosts文件

Appserv配置多站点教程第三步:修改Apache配置文件,启用虚拟主机配置

在Appserv安装目录中找到Apache2.2\conf目录,打开apache配置文件httpd.conf,找到# Virtual hosts

1
#Include conf/extra/httpd-vhosts.conf

中的#去除。

由于Appserv配置中Apache配置是以定制方式存在,上述语句代表Apache启用虚拟主机配置。同时Appserv多站点配置功能是以虚拟主机的方式实现,你可以一并将httpd配置文件中的

1
#LoadModule vhost_alias_module modules/mod_vhost_alias.so

#去除(经过我的测试,其实此Apache Module加不加载没太大关系)

Appserv配置多站点教程第四步:修改Apache虚拟主机配置

打开conf/extra/httpd-vhosts.conf配置文件,文件中本身存在两条虚拟主机配置记录,只要稍作修改即可。

将ServerAdmin(邮件地址)、DocumentRoot(网站根目录,我设定的目录为”C:/AppServ/www /wwwleapsoulcn/”和C:/AppServ/www/wwwphptestcn/) 、ServerName(站点域名信息)、ServerAlias(站点域名别名)配置选项设置为你需要设定的信息即可。Appserv配置多站点实例如 下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<VirtualHost *:80>
ServerAdmin 你的邮箱地址
DocumentRoot “C:/AppServ/www/wwwleapsoulcn/”
ServerName leapsoul.cn
ServerAlias www.leapsoul.cn
ErrorLog “logs/dummy-host.x-error.log”
CustomLog “logs/dummy-host.x-access.log” common
</VirtualHost>

<VirtualHost *:80>
ServerAdmin 你的邮箱地址
DocumentRoot “C:/AppServ/www/wwwphptestcn/”
ServerName www.phptest.cn
ErrorLog “logs/dummy-host2.x-error.log”
CustomLog “logs/dummy-host2.x-access.log” common
</VirtualHost>

Appserv多站点配置提示:如果同时配置多个虚拟主机,务必确保第一条虚拟主机记录不可缺失ServerAlias选项,否则配置不会成功。

最后保存conf/extra/httpd-vhosts.conf配置文件。

重启Apache时注意请在CMD模式下通过net start apache2.2net stop apache2.2方式重启Apache。

此时通过IE以域名方式即可访问使用Appserv配置的多个站点了。

上述方法是以域名方式使用Appserv配置多站点访问功能,如果以IP方式也是可以实现此配置功能,区别在于需要使用不同的端口。除了原有的上述httpd.conf配置外,需要再Listen 80语句后,添加需要侦听的端口,比如

1
2
Listen 8080
Listen 8081

然后将conf/extra/httpd-vhosts.conf配置文件中的<VirtualHost *:80>修改为<VirtualHost 对应IP:对应侦听端口>即可,其他配置不变。

最后删除hosts文件中之前设定的配置,重启Apache服务即可。

至此,怎么使用Appserv以域名或IP地址方式实现配置多站点访问教程就介绍完了。

PHP网站开发教程-leapsoul.cn版权所有,转载时请以链接形式注明原始出处及本声明,谢谢。

[转载]将Access转为SQLite数据库

mikel阅读(937)

[转载]将Access转为SQLite数据库 – badsun – 博客园.

SQLite是一个轻量型的数据库,各方面由于Access,对于小型网站来说,非常适合!我今天决定将系统的数据库由Access转换为SQLite。 在网上搜索了一下,找到了DBManager这个工具,不得不说,这个软件确实好,很强大,在网上找注册码也找到半天,找不到一个!

只要将Access转换为SQLite,然后使用System.Data.SQLite.dll来访问数据库。我们用DbManager创建一个SQLite数据库。

如下图:

2.选择数据,并点击工具 – 数据管理 – 导入数据

3.按照向导,选择Access,mdb文件,并选择文件位置后将会列出Access数据库的所有表。选择所有表,并包括数据

4.点击确认开始导入数据,导入完成后,打开表发现跟原来的数据完全一致!

数据库导入的工作已经完成了,我们可以将这个SQLite数据库用到我们的项目中!

可惜的是,读取SQLite时候,给报一个错:

File opened that is not a database file
file is encrypted or is not a database

用SQLiteSpy打开SQLite数据库时候提示输入密码。

我就为这个问题,弄了一下午时间,网上说数据库损坏了,也有的说在连接字符串设置密码。

经过反复的思考之后,觉得问题应该出在SQLite的版本上,只能通过其他方式来将Access转为SQLite了。

还好,数据库都支持SQL,我只有设法将数据导出为SQL文件,然后通过SQLiteSpy创建一个支持ASP.NET调用的文件。在这个文件中执行脚本!

结果终于搞定!

DBManager也支持SQLite数据导出为SQL文件:选择数据库->Dump,按照向导出脚本

脚本导出之后,我们就可以使用SQLiteSpy创建新的数据库了:File->New DataBase

创建完成之后,执行刚才保存的SQL脚本。

现在,可以将这个数据库文件放到我们的项目中供System.Data.SQLite.dll 调用了!

文章由:(www.ops.cc)奥博网络站长编写,原文地址:http://www.ops.cc/archive.aspx/view/168c38d4460946bd/

[转载]运用Composite模式构造JSON

mikel阅读(1151)

[转载]运用Composite模式构造JSON – 小城故事 – 博客园.
Json是如今流行的Ajax或Service数据交换格式,.NET使用DataContractJsonSerializer(System.Runtime.Serialization.Json命名空间下),可以很方便地在json字符串和实体对象间转换。

Restful WCF服务站点上,更无须写代码序列化Json。服务默认以xml形式返回结果,但如果Web请求头信息中的Accept属性为application/json,客户端得到的就是以json格式序列化了结果。

客户端用JQuery实现很简单,只要调用ajax函数时,设置dataType:’json’就可以了。

客户端也可以发送json到让服务处理,只要把请求头的ContentType设为text/json(JQuery的ajax函数也有这个属性),服务会自动将请求内容反序列化为实体。

然而很多情况下,我们输出的json不是标准的实体集合,可能只输出其中个别属性,或者掺点别的东西,比如分页查询,我们要告诉客户返回的结果 集是第几页,一共有多少页,这样的json还得我们自己通过代码输出。这就比较烦了,业务复杂点没办法,但写那些单引双引,花括号方括号,经常还得转义, 可一点不好玩。比如一个最简单的实体:

var sb = new StringBuilder("[");
foreach (var user in lstUser)
{
    sb.AppendFormat("{{'name':'{0}','email':'{1}'}},",user.Name,user.Email);
}
sb.Remove(sb.Length - 1, 1);
sb.Append("]");

  能一遍写对这段代码的人,绝非等闲之辈。偶打草稿时还写错了。相形之下,json的老大哥xml就给力多了,因为里面所有操作都可以通过对象,比如XAttribute、XText、XComment等。

class Program
{
    static void Main()
    {
        var lstUser = new List<User>{
            new User { Name = "潘金莲",  Email="pjl@sh.com"},
            new User { Name = "武松",  Email="ws@sh.com"},
            new User { Name = "西门庆",  Email="xmq@sh.com"}               
        };

        var xe = new XElement("Users",
            from u in lstUser
            select new XElement("User",
                new XAttribute("name", u.Name),
                new XAttribute("email", u.Email)));

        Console.WriteLine(xe);
        Console.ReadLine();
    }

    class User
    {
        public string Name { get; set; }
        public string Email { get; set; }
    }
}

  优雅的5行代码,把潘金莲和她最重要的两个男人潇洒地绑在一起。写Json也能如此优雅吗,完全可以,其实我们早就有了Json.Net,重量级拳手,我感觉,玩我们日常的应用如同高射炮打麻雀,还不如做个弹弓来的实惠。

  仿照XNode,定义了几个Json对象类型:

/// <summary>
/// 表示json数组
/// </summary>
class JArray : JElement
{
    public JArray(params object[] array)
    {
        this.Elements = array.Select(o =>
        {
            var element = o as JElement;
            if (element == null) return new JElement(o);
            else return element;
        }).ToList();
    }

    public List<JElement> Elements { get; set; }

    public override string ToString()
    {
        return "[" + String.Join(",", this.Elements) + "]";
    }
}

/// <summary>
/// 表示json实体对象
/// </summary>
class JEntity : JElement
{
    public JEntity(params JProperty[] properties)
    {        
        this.Value = properties.ToList();
    }

    public List<JProperty> Properties { get { return this.Value as List<JProperty>; } }

    public override string ToString()
    {
        return "{" + String.Join(",", this.Properties) + "}";
    }
}

/// <summary>
/// 表示一个json实体的属性键值对
/// </summary>
class JProperty 
{
    public JProperty(string name, object value)
    {
        this.Name = name;

        var element = value as JElement;
        if (element == null) element = new JElement(value);
        this.Value = element;
    }

    public string Name { get; set; }

    public JElement Value { get; set; }

    public override string ToString()
    {
        return "'" + Name + "':'" + Value + "'";
    }
}

/// <summary>
/// 表示基本的json元素
/// </summary>
class JElement
{
    public JElement() { }

    public JElement(object value)
    {
        var array = value as System.Collections.IEnumerable;

        if (array != null && !(value is string))
        {
            this.Value = new JArray(array.Cast<object>().ToArray());
        }
        else this.Value = value;
    }

    public object Value { get; set; }

    public override string ToString()
    {
        var type = Value.GetType();
        if (type.IsPrimitive)
        {
            if (type == typeof(int) || type == typeof(double)) return Value.ToString();
        }

        return "'" + Value + "'";
    }
}

然后,我们就可以这么写json了,看,与输出xml的写法很相似吧:

var json = new JArray(
    (from u in lstUser
    select new JEntity(
        new JProperty("name", u.Name),
        new JProperty("email", u.Email))).ToArray());

Console.WriteLine(json);

  话说json本来就是轻量级的数据交换格式,轻量级格式也应该用轻量方法处理,并且还要能重用,最重要的是一目了然,大家可以考虑下这种方式。对JArray等几个构造函数,还待进一步改进。

  经过最近研究,发现这种优雅的方式json构造方式,莫非是暗合了江湖至高无上,OOP兵法23条中的Composite模式(《.Net设计模式》第九章)?无意中得窥至尊宝典之道,哇呀妙哉!

  最近还发现了,json还有个小弟,唤作jsonp的东东,火星了,原来就是BingMap API的脚本加载方式,经常使用还朦朣不觉。

  现在轮到自己写服务器端,不想破坏WCF自动转换的优美,想用输出替换的方式,但设置Resonse.Filter(参考)真麻烦,Response.OutputStream又只能写不能读。只好响应全局事件,在正文开始前先写入客户端回调的函数名和一个括号,在正文输出结束后添上另一个括号。虽然早就知道,可每次写起来,偶的心还是隐隐作疼,纠结一番。

[转载]Google面试题, 年薪40万的工程师多少年能在北京买一套200万的房子?!

mikel阅读(782)

[转载]Google面试题, 年薪40万的工程师多少年能在北京买一套200万的房子?! – CarsonSong – 博客园.

Google面试题, 年薪40万的工程师多少年能在北京买一套200万的房子?!

近日,偶尔看到一到谷歌的面试题,百度之,竟然发现一堆人的文章在讨论这个,于是总结于此,或表述下,或感叹下,或愤青下,或调侃下~

如果只以小学数学水平来看题目的话,200/4=5,五年就搞定了呗。但是,科技发展的时代啊,如果都这么简单,还读什么大学,读什么研,搞什么飞机 啊?!我们要考虑变数啊,房价还会每年上涨,银行利息还会被调整,加上金融危机,还会通过膨胀使得银行存款缩水,现在终于知道为啥要学函数,学方程式,学 微积分吧,就算不能拯救自己,起码死了还知道自己是什么死的吧?!至于你信不信,反正我信了!

好的,先上原题:

现在北京有一套房子,价格200万,假设房价每年上涨10%,一个软件工程师每年固定能

赚40万。如果他想买这套房子,不贷款,不涨工资,没有其他收入,每年不吃不喝不消
费,那么他需要几年才能攒够钱买这套房子?
A, 5年
B, 7年
C, 8年
D, 9年
E, 永远买不起

开始解题:

估计看到E选项,情商不低的人,很轻松就能感觉出答案来了!yes,答案就是永远买不起,这是为什么呢?

两个方法:

1. 随便取几个数,拿计算器算去。

2. 我自己看这个题的思路:假设x年后,正好能买得起房,则方程式为200*(1+0.1)^x = 40x, 变形后,1.1^x=x*1/5. 看吧,左边是一个越跑越高的指数曲线,右边是一个斜率为0.2的直线。两者PK,鹿死谁手?

深度剖析:

面向学生,好好的学习吧,特别是或许乏味的数学课,要不傻乎乎的学个博士,一样因为买不起房被拍死。而且可能将来死了都不知道咋死的哦~

面向悲观者,默哀吧,当今世风日下,就算年薪40万都买不起一套房,所以如果你买不起,不怪你;~

面向乐观者,利用好数学,利用好经济学一些杠杆理论吧,钱生钱,这个问题根本就不存在~

PS1:知道为啥Google退出中国了吧?在中国,工程师不好养啊,更何况个个都是大爷,怎么伺候得起?

PS2:引一段评论:

这道题引来无数人评论,最经典的评论就是Google暗示软件工程师买不起房。

这道题目很简单,我今天这里说的不是如何做这道题,我想说的是为什么40万年薪永远买不起初始价值200万每年上涨10%的房子呢?

第11年的时候,房子涨价到200x(1+0.1)^10 = 518.75万,而这个软件工程师赚到了440万。如果这位软件工程师善于理财,40万收入以每年20%的上涨,那第11年他赚到了741万,买房绰绰有余。

有人觉得每年10%或者20%的增加,但是连续10年或者20年这种增速,那就不得了了。所以作为一个连40万都赚不到的软件工程师,赶紧理财吧。

如果让你的财富每年增长15%,20年你的财富可以增加15倍,如果让你的财富每年增长20%,20年后你的财富可以增加37倍

PS3: 进一步考虑和推论:

如果允许贷款,首付20%的话。此人第一年就可以买房,欠银行160万。每年还银行利息约5万。5年就可以还清银行贷款,还能余15万现金。此年房子价值293万。
绝对的颠覆!
首付20%买首套房是每个人致富的权利和福利,不可剥夺。

回顾历史,有钱有权人,靠着银行成百上千万的贷款,几年后轻轻松松拉开与你我的财富差距。2005年到2010年,靠此赚上千万就这么简单。

下一个5年呢?不敢想像。

希望:
1.一定要让民间资本回到民营企业来。开放垄断领域让民间资本进入高利润行业,才能留住民间资本,这次的新非公36条一定要言而有信。
2.贷款买房一定要控制住,包括首套房。真正炒房者都是回老家拿一麻袋身份证,全是首套房。设置各种门槛不让轻易贷到款买房。
3.出台各种政策和言论,舆论上一定改变多数人对房价上涨的预期。至少让一半人认为房价能控制住,不要搞出全民贷款买房的杯具。

(蓝色字体部分转自其他网页,著作权和解释权归原作者。)

[转载]推荐8款非常有用的 CSS 开发工具

mikel阅读(787)

[转载]推荐8款非常有用的 CSS 开发工具 – 梦想天空(山边小溪) – 博客园.

这篇文章向大家推荐8款非常有用的 CSS 工具。对于Web开发人员来说,好用的CSS工具就像魔灯,可以让他那些枯燥的工作变得有趣。这些CSS工具中,有的用于帮助你学习 CSS3 属性,有的用于帮助你更高效的编写 CSS 代码,每个工具都非常有用,希望能帮助到你,记得分享和推荐一下哦。

CSS3 Patterns Gallery

推荐8款非常有用的CSS开发工具

这个CSS3模式库展示了各种使用纯 CSS3 实现的网页背景效果,可以即时修改代码浏览效果,非常棒!

Layer Styles

推荐8款非常有用的CSS开发工具

这是一个基于 HTML5 的在线应用,以非常直观的方式生成各种丰富CSS3效果,这个界面是否让你想起了 Photoshop 呢。

PrefixMyCSS

推荐8款非常有用的CSS开发工具

PrefixMyCSS 是一个可以帮助你自动补全CSS前缀的工具,帮助你更高效的编写CSS代码。

Sencha Animator

推荐8款非常有用的CSS开发工具

Sencha Animator 是一个用于制作运行在WebKit核心浏览器和触屏设备的CSS3动画的桌面应用程序,让你可以像制作Flash一样制作CSS3动画。

The Web Font Combinator

推荐8款非常有用的CSS开发工具

Web Font Combinator 是一款用于在线预览网页字体样式的工具,很适合网页设计师用的一款工具。

CSS Pivot

推荐8款非常有用的CSS开发工具

CSS Pivot 可以让你给任何网站添加样式,并可以把结果以短网址的形式分享,这个工具挺有创意的。

CSS Lint

推荐8款非常有用的CSS开发工具

CSS Lint 是一款帮助你检查CSS代码的工具,除了基本的语法检查以外,还会提醒你一些效率低下的CSS代码写法。

CSS Prism

推荐8款非常有用的CSS开发工具

CSS Prism 是一款对设计师非常有用的在线工具,输入任何网站的CSS文件地址即可分析出改网站的色谱。

[转载]两个Select标签内容多选切换之jquery方法

mikel阅读(994)

[转载]两个Select标签内容多选切换之jquery方法 – qandq – 博客园.

利用JQuery实现两个select标签多选内容从一个标签选择到另外一个标签的简单方法,区区几行代码就能搞定,支持多种浏览器。

效果如下所示:

本例中用到JQuery请自行下载。
若有不明白或者有新的功能需求请留言

代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>select标签  </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<script type="text/javascript" src="jquery.js"></script>

<SCRIPT LANGUAGE="JavaScript">
<!--
$(document).ready(function() {
    $("#toRight").click(function(){
        $("#selectLeft option:selected").each(function(){
                $("#selectRight").append("<option value=" + 
$(this).val() + ">" + $(this).html() + "</option>");
                $(this).remove();
        });
    });

    $("#toLeft").click(function(){    
        $("#selectRight option:selected").each(function(){
                $("#selectLeft").append("<option value=" + $(this).val() + 
">" + $(this).html() + "</option>");
//这个方法是默认在后面添加
                //$("#selectLeft option:first").before("<option value=" +
 $(this).val() + ">" + $(this).html() + "</option>"); 
//此种方法是在select前面加内容
                //$("#selectLeft option[value=3]").before("<option value=" +
 $(this).val() + ">" + $(this).html() + "</option>"); 
//此种方法是在selectt指定某一行加内容
                $(this).remove();
        });
    });

});
//-->
</SCRIPT>
</HEAD>

<BODY>
<table>
<tr>
    <td>
    <select  size='10' multiple id="selectLeft"  style="width:200px">
        <option value="0">Jquery API</option>
        <option  value="1">JavaScript高级程序设计</option>
        <option  value="2">锋利的jQuery</option>
        <option value="3">JavaScript 设计模式</option>
        <option  value="4">JavaScript+DOM高级程序设计</option>
        <option  value="5">PHP高级程序设计</option>
        <option  value="6">面向对象程序设计</option>
    </select>
    </td>
    <td>
    <input type="button" value=" >> " id="toRight" /><br /><br />
    <input type="button" value=" << " id="toLeft" />
    </td>
    <td>
    <select  size='10' multiple id="selectRight" style="width:200px">
    </select>
    </td>
</tr>
</table>
</BODY>
</HTML>

[转载]海量数据处理专题(七)——数据库索引及优化

mikel阅读(807)

[转载]海量数据处理专题(七)——数据库索引及优化 – 码农1946 – 博客园.

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。

数据库索引

什么是索引

数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
例如这样一个查询:select * from table1 where id=44。如果没有索引,必须遍历整个表,直到ID等于44的这一行被找到为止;有了索引之后(必须是在ID这一列上建立的索引),直接在索引里面找 44(也就是在ID这一列找),就可以得知这一行的位置,也就是找到了这一行。可见,索引是用来定位的。
索引分为聚簇索引和非聚簇索引两种,聚簇索引 是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。

概述

建立索引的目的是加快对表中记录的查找或排序。
为表设置索引要付出代价的:一是增加了数据库的存储空间,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。

B树索引-Sql Server索引方式

B树索引-SQL Server索引方式

为什么要创建索引

创建索引可以大大提高系统的性能。
第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢?因为,增加索引也有许多不利的方面。
第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

在哪建索引

索引是建立在数据库表中的某些列的上面。在创建索引的时候,应该考虑在哪些列上可以创建索引,在哪些列上不能创建索引。一般来说,应该在这些列上创建索引:
在经常需要搜索的列上,可以加快搜索的速度;
在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
同样,对于有些列不应该创建索引。一般来说,不应该创建索引的的这些列具有下列特点:
第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
第二,对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少,不利于使用索引。
第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改操作远远多于检索操作时,不应该创建索引。

数据库优化

此外,除了数据库索引之外,在LAMP结果如此流行的今天,数据库(尤其是MySQL)性能优化也是海量数据处理的一个热点。下面就结合自己的经验,聊一聊MySQL数据库优化的几个方面。
首先,在数据库设计的时候,要能够充分的利用索引带来的性能提升,至于如何建立索引,建立什么样的索引,在哪些字段上建立索引,上面已经讲的很清楚了, 这里不在赘述。另外就是设计数据库的原则就是尽可能少的进行数据库写操作(插入,更新,删除等),查询越简单越好。如下:

数据库设计

数据库设计


其次,配置缓存是必不可少的,配置缓存可以有效的降低数据库查询读取次数,从而缓解数据库服务器压力,达到优化的目的,一定程度上来讲,这算是一个“围 魏救赵”的办法。可配置的缓存包括索引缓存(key_buffer),排序缓存(sort_buffer),查询缓存(query_buffer),表描 述符缓存(table_cache),如下图:

配置缓存

配置缓存


第三,切表,切表也是一种比较流行的数据库优化方法。分表包括两种方式:横向分表和纵向分表,其中,纵向分表比较有使用意义,但是分表会造成查询的负担,因此在数据库设计之初,要想好:

分表

分表


第四,日志分析,在数据库运行了较长一段时间以后,会积累大量的LOG日志,其实这里面的蕴涵的有用的信息量还是很大的。通过分析日志,可以找到系统性能的瓶颈,从而进一步寻找优化方案。

性能分析

性能分析


以上讲的都是单机MySQL的性能优化的一些经验,但是随着信息大爆炸,单机的数据库服务器已经不能满足我们的需求,于是,多多节点,分布式数据库网络出现了,其一般的结构如下:

分布式数据库结构

分布式数据库结构


这种分布式集群的技术关键就是“同步复制”。。。未完待续~~~

[转载]Android与IIS身份验证——基本验证

mikel阅读(1050)

[转载]Android与IIS身份验证——基本验证 – 刘冬.NET – 博客园.

内容摘要

前言

1.服务器端

2.Android客户端

3.IIS部署

4.运行效果

Android移动项目开发中,访问服务器时,为了简洁方便,我们经常使用http协议来传递JSON格式的数据。然而有些项目需要有一定的 安全性,如使用Android客户端登陆到MIS系统。虽然我们是通过Android手机客户端的登陆Activity中登陆到系统的,但是略懂电脑的黑 客是能够跳过登陆Activity,从而直接进入系统的。这样,会造成一些由于系统的不安全所带来的麻烦。建立一种防止黑客强行登录的身份验证模式尤为重 要。此时,系统的身份验证成为阻挡黑客登陆的一道屏障。那么,怎样实现一个身份验证呢?让我们以IIS为宿主,一步一步的实现身份验证吧。

一、ASP.NET服务器端

首先,我们使用VS2010创建一个web项目(可以是WebForms,也可以是MVC,我这里使用的是ASP.NET MVC项目)。图1.1所示

图1.1

然后,在HomeController的Index Action中输入:登陆成功。

[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
return Content(登陆成功);
}
}

二、Android客户端

首先,创建一个Android项目,并新建一个MainActivity类。

接着,编写一个访问IIS服务器的类。

package ld.com.authorize;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;

import android.util.Log;

public abstract class HttpHelper {

private final static String TAG = HttpHelper;

public static String invoke() {
String result
= null;
try {
final String url = http://192.168.1.104:180/;

HttpPost httpPost = new HttpPost(url);
DefaultHttpClient httpClient
= new DefaultHttpClient();

//基本身份验证
BasicCredentialsProvider bcp = new BasicCredentialsProvider();
String userName
= liudong;
String password
= 123;
bcp.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(
userName, password));
httpClient.setCredentialsProvider(bcp);

HttpResponse httpResponse = httpClient.execute(httpPost);

StringBuilder builder = new StringBuilder();
BufferedReader reader
= new BufferedReader(new InputStreamReader(
httpResponse.getEntity().getContent()));
for (String s = reader.readLine(); s != null; s = reader.readLine()) {
builder.append(s);
}
result
= builder.toString();
Log.d(TAG,
result is ( + result + ));
}
catch (Exception e) {
Log.e(TAG, e.toString());
}
Log.d(TAG,
over);
return result;
}
}

注意的是,我这里用户名和密码分别是:liudong和123。

然后,修改layout文件:main.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation
=”vertical” android:layout_width=”fill_parent”
android:layout_height
=”fill_parent”>
<TextView android:layout_width=”fill_parent”
android:layout_height
=”wrap_content” android:text=”@string/hello” />
<Button android:text=”身份码验证” android:id=”@+id/btnPassword”
android:layout_width
=”fill_parent” android:layout_height=”wrap_content”></Button>
</LinearLayout>

最后,修改MainActivity。

package ld.com.authorize;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

private final String TAG = this.getClass().getSimpleName();

private Button btnPassword;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

btnPassword = (Button) this.findViewById(R.id.btnPassword);

setInvokeOnClick();
}

private void setInvokeOnClick() {
btnPassword.setOnClickListener(
new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {

private ProgressDialog progressDialog;

@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
// super.onPostExecute(result);
progressDialog.cancel();
Toast.makeText(MainActivity.
this, result,
Toast.LENGTH_SHORT).show();

Log.d(TAG, result);
}

@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressDialog
= new ProgressDialog(MainActivity.this);
progressDialog
.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setTitle(
调用中,请稍后…);
progressDialog.show();
}

@Override
protected String doInBackground(Void… arg0) {
// TODO Auto-generated method stub
try {
return HttpHelper.invoke();
}
catch (Exception e) {
return null;
}
}

};
task.execute();
}
});
}
}

设置访问权限为:<uses-permission android:name=”android.permission.INTERNET” />

运行模拟器的效果如图2.1所示。

图2.1

三、IIS部署

首先、添加一个网站,如图3.1所示。

如图3.1

接着,在进入计算机管理–>本地用户和组–>用户,新建一个用户,如图3.2所示。

图3.2

然后,设置IIS的身份验证(图3.3所示)。

图3.3

设置其身份验证模式为:基本验证或Window身份s验证(图3.4所示)。

图3.4

最后,我们在浏览器中输入网址进行验证,验证结果见图3.5和图3.6。

图3.5

图3.6

从图中我们可以发现,浏览该网页时需要用户名和密码。我们输入了正确的用户名和密码后就可以登录这个页面了。

四,运行效果。

见图4.1和图4.2所示。

图4.1

图4.2

代码下载

出处:http://www.cnblogs.com/GoodHelper/archive/2011/08/17/android_iis_01.html

作者:刘冬.NET

欢迎转载,但须保留版权。

[转载]Android通过摇晃手机的频率来控制声音的频率

mikel阅读(1187)

[转载]Android通过摇晃手机的频率来控制声音的频率 – stay – 博客园.

通过晃动手机的频率来修改播放声音的频率。效果很给力的说。主要通过sensor来算手机摇晃的频率,摇晃的频率越高,播放声音的速度越快。

/**
* @author Stay
* 通过摇晃手机的频率来改变声音的速度
*/
public class ShakeSound extends Activity implements SensorEventListener,OnClickListener {
private static final float SHAKE_THRESHOLD = 50;
private static final String TAG = “ActivityTest”;
private SensorManager manager;
private SoundManager sm;
private long curTime, lastUpdate;
private float last_x, last_y, last_z;
private float x,y,z;
private boolean isPlaying;
private int count = -2;
private float force;
private int audioCount = 0;
private float audioForce;
private Button btn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button) this.findViewById(R.id.hello);
btn.setOnClickListener(this);
manager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sm = new SoundManager(this);
sm.addSound(1, “heixiu.ogg”);
}

@Override
public void onSensorChanged(SensorEvent event) {
curTime = System.currentTimeMillis();
if ((curTime – lastUpdate) > 100) {
count ++ ;
if (count < 0) { return; } if (count == 0) { if (!isPlaying) { Log.i(TAG, "sm.play(1, 0, 1.0f);"); sm.play(1, 0, 1.0f); } last_x = event.values[SensorManager.DATA_X]; last_y = event.values[SensorManager.DATA_Y]; last_z = event.values[SensorManager.DATA_Z]; return; } lastUpdate = curTime; x = event.values[SensorManager.DATA_X]; y = event.values[SensorManager.DATA_Y]; z = event.values[SensorManager.DATA_Z]; curTime = System.currentTimeMillis(); // 每100毫秒检测一次 float deltaForce = Math.abs(x + y + z - last_x - last_y - last_z); force = force + deltaForce; updateAudioRate(deltaForce); if (count >= SHAKE_THRESHOLD) {
Log.i(TAG, “unSensorListener”);
// onShakeCallBack(force / count); get the score
unSensorListener();
if (isPlaying) {
sm.stop();
isPlaying = false;
}
count = – 2;
force = 0;
return;
}
last_x = x;
last_y = y;
last_z = z;
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

private void updateAudioRate(float force) {
float rate=0;
float prvAudioRate = 1;
audioCount =audioCount+1;
audioForce=audioForce+force;
if(audioCount>3){
//from 0-50 maps to 0.6 to 2
//rate=audioForce/audioCount*0.03+0.5;
//from 0-50 maps to 1 to 1.8
rate=(float) (audioForce/audioCount*0.012+1.0);
//myAlert(rate);
prvAudioRate=prvAudioRate+(rate-prvAudioRate)/3;
sm.setRate(prvAudioRate);
Log.i(TAG, “sm.setRate=” + prvAudioRate);
audioForce=0;
audioCount=0;
//prvAudioRate=rate;
}
}

private void setSensorListener() {
Log.i(TAG, “setSensorListener”);
Sensor sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
manager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
}

private void unSensorListener() {
Log.i(TAG, “unregisterListener”);
manager.unregisterListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.hello:
setSensorListener();
break;
default:
break;
}
}

/**
* @author Stay
* 声音管理类
*/
public class SoundManager {
public SoundPool mSoundPool;
private HashMap mSoundPoolMap;
private AudioManager mAudioManager;
private Context mContext;
private int mStreamID;
static final String LOG_TAG = “SoundManager”;
private boolean mSoundEnable = true;
private float mRate = 1f;
private boolean playing = false;
private int loopMode = 0;
private int mPlayIndex = -1;

public SoundManager(Context mContext) {
this.mContext = mContext;
mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
mSoundPoolMap = new HashMap();
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}

public void addSound(int index, String audioName) {
// mSoundPoolMap.put(1, mSoundPool.load(mContext, SoundID, 1));
try {
mSoundPoolMap.put(index, mSoundPool.load(mContext.getAssets().openFd(audioName), 1));
} catch (IOException e) {
e.printStackTrace();
}
}

// loopMode=0:play once; loopMode=-1:loop mode;
public void play(int index, int loopMode, float rate) {
if (mSoundEnable) {
this.loopMode = loopMode;
mRate = checkRate(rate);

int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
// float streamVolume = 0.1f;
// notes: for loop mode, the priority should be set to 0, else it can’t be stopped
// mStreamID=mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, loopMode, mRate);
if (mPlayIndex < 0) { mStreamID = mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 0, loopMode, mRate); } else { mStreamID = mSoundPool.play(mSoundPoolMap.get(mPlayIndex), streamVolume, streamVolume, 0, loopMode, mRate); } playing = true; } } // added for v 1.0.1, enable changing the audio remotely public void setPlayIndex(int index) { mPlayIndex = index; } public void setRate(float rate) { if (mSoundEnable) { mRate = checkRate(rate); mSoundPool.setRate(mStreamID, mRate); } } private float checkRate(float rate) { if (rate > 2f) {
return 2f;
} else if (rate < 0.5f) { return 0.5f; } else { return rate; } } public void stepRate(float step) { if (mSoundEnable) { mRate = mRate + step; mRate = checkRate(mRate); mSoundPool.setRate(mStreamID, mRate); } } public void pause() { if (mSoundEnable) { mSoundPool.pause(mStreamID); // mSoundPool.autoPause(); } } public void resume() { if (mSoundEnable) { if (false == playing) { play(1, loopMode, mRate); } else { mSoundPool.resume(mStreamID); } } // mSoundPool.autoResume(); } public void stop() { if (mSoundEnable) { playing = false; mSoundPool.stop(mStreamID); } } public void setSound(boolean soundEnable) { mSoundEnable = soundEnable; } public void release() { if (mSoundEnable) { playing = false; mSoundPool.release(); } mSoundPool.release(); mSoundPool = null; mSoundPoolMap.clear(); mSoundPoolMap = null; } } [/java]