Android 能否动态修改App的桌面名称或者图标

目前的目测是不行的。

本来想想也是,如果这都可以修改的话,很容易在安装之后变成一个山寨的QQ或者支付宝,完全的不稳定因素。
但是有要求没办法,还是先调查一下。

  1. app name是在manifest文件中指定的,没有办法修改。
  2. Launcher可能会缓存应用图标,这种情况下,就算图标被修改了也只会在下次重启之后生效
  3. 使用activity-alias可以创建不同的app name和app_icon的别称,但是只是假象而已,真正的app还是按照原本的显示。
  4. 可以创建widget来在home动态展示内容,制造修改icon的假象
  5. 除非重写Launcher,没有找到其他的方法。

另外提到最多的是setTitle,这个是修改 Activity 的。

命令记录-cat

cat

来源单词:catenate(连接)

用途

主要包括下列用途:

  1. 将文本文件显示到屏幕
  2. 复制文本文件
  3. 连接文本文件
  4. 创建新的文本文件

语法

1
2
3
4
cat filename 
cat options filename
cat file1 file2
cat file1 file2 > newcombinedfile

显示文件内容

1
$ cat /etc/passwd

上面的命令显示了文件/etc/passwd的内容。默认情况下,cat将输出显示到屏幕上面,同样,可以用“>”将输出重定向到另外的命令输入或者文件。

1
$ cat /etc/passwd > /tmp/test.txt

看看下面的例子:

1
cat file1 - file2

‘-‘ 表示从键盘获取输入,因此上面的例子就是先显示file1的内容,然后显示用户输入的内容,最后现实file2的内容(按下CTRL+D可以终止用户输入)。
如果cat不加任何参数,那么默认从键盘获取输入,然后将结果输出到屏幕,例子如下:

1
2
3
4
5
cat
1
1
hello
hello

连接文件

Concatenation意味着将多个文件内容连接到一起,同时原始的文件不会被修改或者被删除。下面的例子是将 /etc/hosts, /etc/resolv.conf, and /etc/fstab这三个文件的内容连接在一起然后输出到标准输出里面(默认是屏幕)

1
cat /etc/hosts /etc/resolv.conf /etc/fstab

同样可以重定向到别的地方

1
2
3
$ cat /etc/hosts /etc/resolv.conf /etc/fstab > /tmp/outputs.txt

$ cat /tmp/outputs.txt

或者通过管道来过滤数据:

1
cat /etc/passwd | less

创建文件

下面的例子创建了一个foo.txt文件

1
$ cat > foo.txt

没有指定输入源时,默认从键盘获取输入。
你可以键入

1
This is a test.

然后按CTRL + D来保存输入。注意,如果目标目录中原本就存在foo.txt目录,cat会一声不吭的覆盖掉原有的foo.txt,如果你想在原有的foo.txt后面追加内容,按照惯例,可以将‘>’替换为”>>”:

1
$ cat >> foo.txt

复制文件

cat可以创建一个新文件并将现有文件的数据传递给新文件,从而实现copy

1
$ cat oldfile.txt > newfile.txt

创建一个新文件并从键盘获取输入:

1
cat > newfile.txt

如果要同时从键盘和文件获取输入,可以参照上文的’-‘符号:

1
cat - file1 > file2

表示先从键盘读取输入,然后从file1获取输入,最后输出到file2中

命令参数

--help  显示帮助,几乎所有的GNU软件都有这么个同意的参数,另一个就是--version。

其他几个比较重要的是:

-b, --number-nonblank    对非空输出行编号
-E, --show-ends          在每行结束处显示"$"
-n, --number             对输出的所有行编号
-s, --squeeze-blank      不输出多行空行
-T, --show-tabs          将跳格字符显示为^I
-v, --show-nonprinting   使用^ 和M- 引用,除了LFD和 TAB 之外

-A, --show-all           等于-vET
-e                       等于-vE
-t                       与-vT 等价

cat最佳实践【争议】

cat最主要的作用是连接文件,如果只有一个文件,使用cat只是增加无端的消耗而已,比如

1
$ cat /proc/cpuinfo | grep model

可以用下面的命令代替:

1
$ grep model /proc/cpuinfo

再看一个:

1
cat filename | sed -e 'commands' -e 'commands2'

可以用命令

1
sed sed -e 'commands' -e 'commands2' filename

代替。再者,cat显示大文件也比较吃力。

来源:http://www.cyberciti.biz/faq/howto-use-cat-command-in-unix-linux-shell-script/

linux 搭建SVN服务器

1.安装Subversion

1
sudo apt-get install subversion

2.创建仓库

假定我们仓库的父目录为/home/svn

1
2
cd /home/svn
sudo svnadmin create /home/svn/test

可以看到/home/svn目录下面有一个test文件夹,里面有conf,db,format,hooks,locks,README.txt几个文件

3.启动svn服务器

1
sudo svnserve -d -r /home/svn

4.测试svn服务器

1
svn co file://localhost/home/svn/test

输出:Checked out revision 0

说明安装成功

浏览器访问

如果要通过浏览器访问的,则需要与apache配合:

1.安装apache

如果没有安装apache,需要先安装apache以及libapache2-svn

1
sudo apt-get install apache libapache2-svn

2.整合SVN

修改/etc/apache2/mods-available/dav_svn.conf

1
2
3
4
5
6
7
8
9
<Location /svn>
DAV svn
SVNParentPath /home/svn
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/subversion/dav_svn.passwd
AuthzSVNAccessFile /etc/subversion/dav_svn.authz
Require valid-user
</Location>

说明:

1. SVNParentPath表示的所有库的父级目录,SVNParentPath与SVNPath只能启用一个。SVNPath只能创建一个仓库,SVNParentPath则可以创建多个,由于通常不会只有一个仓库,所以通常都会选择SVNParentPath
2. AuthUserFile 是svn的用户配置文件,位置可以自定义,文件也需要自己创建,不过得保证apache有访问权限
3. AuthzSVNAccessFile 是svn的权限控制文件,其他同AuthUserFile

3.添加SVN用户

1
sudo htpasswd -c /etc/subversion2/dav_svn.passwd username

回车之后需要输入两次密码。
据说 -c 参数创建文件会覆盖原有的信息,但是经过测试,并没有覆盖原有的用户信息,所以,执行

1
2
sudo htpasswd -c /etc/subversion2/dav_svn.passwd user1
sudo htpasswd -c /etc/subversion2/dav_svn.passwd user2

dav_svn.passwd文件中依旧会有user1和user2两个用户信息,没有冲突。

另外,/etc/subversion2/dav_svn.passwd文件需要与第2步中自定义的文件位置一致

完成之后可以看到dav_svn.passwd中有类似

xiao:$apr1$wq1l1SCM$lAgKYtQJUzpPZPgvQXTnX1

的片段,xiao是用户名,后面的是加密后的密码

4.修改SVN访问权限

编辑 /etc/apache2/dav_svn.authz
如果想开放所有权限,那么可以直接

[/]
* = rw

表示用户都有读写权限

5.重启apache

1
sudo /etc/init.d/apache2 restart

访问http://127.0.0.1/svn/test/可查看结果

补充说明:

1.整合SVN出错

出现错误:

Invalid command 'AuthzSVNAccessFile', perhaps misspelled or defined by a module not included in the server configuration
Action 'configtest' failed.

原因:没有导入auth模块
解决方法:
在/etc/apache2/mods-enabled/dav_svn.load中加入

LoadModule authz_svn_module /usr/lib/apache2/modules/mod_authz_svn.so

2.访问仓库列表

如果希望访问所有的仓库列表,可以修改/etc/apache2/mods-available/dav_svn.conf如下:

1
2
3
4
5
6
7
8
9
10
<Location /svn/>
DAV svn
SVNParentPath /home/svn
SVNListParentPath On
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/subversion/dav_svn.passwd
AuthzSVNAccessFile /etc/subversion/dav_svn.authz
Require valid-user
</Location>

注意上面的变化,%lt;Location /svn/>添加了尾部斜线,SVNListParentPath On是新添加的。
重启apache后访问http://127.0.0.1/svn/(结尾有个’/')可以看到结果

3.权限控制说明

/etc/apache2/dav_svn.authz 权限控制的一个示例

[groups] #用来分组用户
group1 = xiao, xe
group2 = user1, user2
 
[test:/] #仓库名称,[/]表示所有仓库
@group1 = rw #表示group1组的用户(xiao, xe)对test具有读写权限
@group2 = r  #表示group2组的用户(user1, user2)对test只具有读权限,没有写的权限
* = #表示所有用户都没有权限,即既不能读,也不能写
 
[test2:/]
* = rw #表示所有用户都具有读写权限

4.权限错误

出现

Can’t open directory ‘/home/svn’: Permission denied

或者

403 forbidden

错误的话,表示apache(通常账户是www-data)没有权限文档到svn所在目录的权限,此时需要检查/home/svn及其子文件夹的权限,比如

1
sudo chown -R www-data /home/svn

然后再访问http://127.0.0.1/svn/test/查看结果

5.重启apache的时候如果出现

Permission denied: make_sock: could not bind to address 0.0.0.0:80

等字样,记得加sudo

闲话历法与时间

历法是用年、月、日等时间单位计算时间的方法,现代历法是从古代一步步发展而来的,而且发展颇为曲折,古代人民交通阻塞,交流不便,但是都需要历法来指导农业生产或者活动祭祀,所以各地都独立的发展了自己的历法。西方社会有代表性的就是古希腊历法,古埃及历法和古罗马历法。

了解历法前,需要了解一点天文学和地理学的知识。我们可以回顾一下托米勒的地心说——地球居于宇宙的中心,太阳以及其他星球围绕地球在各自的轨道上绕地球运动。因此我们可以构造这么一个模型:

1

地球是一个正球形,围绕一根穿过地球球心(地心)的轴(地轴)旋转,我们虚拟出一个穿过地心并且与地轴垂直的面(“赤道平面”),此平面上方称为北半球,下方称为南半球,北半球与“地轴”的交点称为“北极点”,南半球与“地轴”的交点称为“南极点”,与地球表面的交线称为“赤道”。规定从天空到地球表面的距离都是一样的,太阳在天空表面绕地球运动。因此,从地球上看,天空是一个中空且与地球同球心的正球形,太阳的运行轨道是一个以地心为圆心的一个圆,而且圆上各点都落在天空上,这个圆所在的平面称为“黄道平面”,这个圆就称为“黄道”。

在这个模型中,太阳的运行轨道相对于地轴有一定的夹角(黄赤交角,约23.44°),所以如果我们将“赤道平面”延伸到天空,那么“赤道平面”将会与黄道相交于两个点,这两个点一个是“春分点”一个就是“秋分点”。也因为这个“黄赤交角”的原因,“黄道平面”与“赤道平面”有相同的夹角,所以太阳向南或者向北运行,偏离“赤道平面”的最大角度只能达到“黄赤交角”的大小,也就是说,太阳在地球上的直射点偏离赤道平面的最大角度同样为黄赤交角大小。太阳从南往北到达最大偏角时在黄道上处于的点称为夏至点,太阳从北往南到达最大偏角时在黄道上处于的点称为冬至点,

2

Read More

【Javascript】JSON辅助格式化

平时服务器端开发人员写好后台之后一般写一份简单的接口说明页面,类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
<form action="test.php" accept-charset="utf-8">
<div><label for="">param_1</label><input type="text" name="param_1" value="value_1"/></div>
<div><label for="">param_2</label><input type="text" name="param_2" value="value_2"/></div>
<div><label for="">param_3</label><input type="text" name="param_3" value="value_3"/></div>
<div><label for="">param_4</label><input type="text" name="param_4" value="value_4"/></div>
<div><input type="submit" value="submit"/></div>
</form>
```

由于结果是以json形式返回的,不容易一眼辨认,所以为了方便,对结果进行了简单的处理:

1,由于不能控制返回结果的页面,所以直接对请求进行了拦截并用ajax方式进行重发。
2,格式化返回的json结果,非json结果直接显示。

注:ubuntu下的chromium在处理overflow的问题上貌似有点不一样,所以结果容器写得有点罗嗦。

具体例子:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<div id="page">
<form action="test.php" accept-charset="utf-8">
<div><label for="">param_1</label><input type="text" name="param_1" value="value_1"/></div>
<div><label for="">param_2</label><input type="text" name="param_2" value="value_2"/></div>
<div><label for="">param_3</label><input type="text" name="param_3" value="value_3"/></div>
<div><label for="">param_4</label><input type="text" name="param_4" value="value_4"/></div>
<div><input type="submit" value="submit"/></div>
</form>
</div>
<script type="text/javascript" src="../js/jQuery.js"></script>
<script type="text/javascript" src="../js/JSONFormat.js"></script>
</body>
</html>
```

显示效果:

![2](/image/js_json_format.png)

JSONFormat.js内容:

```html
var JSONFormat = (function(){
var _toString = Object.prototype.toString;

function format(object, indent_count){
var html_fragment = '';
switch(_typeof(object)){
case 'Null' :0
html_fragment = _format_null(object);
break;
case 'Boolean' :
html_fragment = _format_boolean(object);
break;
case 'Number' :
html_fragment = _format_number(object);
break;
case 'String' :
html_fragment = _format_string(object);
break;
case 'Array' :
html_fragment = _format_array(object, indent_count);
break;
case 'Object' :
html_fragment = _format_object(object, indent_count);
break;
}
return html_fragment;
};

function _format_null(object){
return '<span class="json_null">null</span>';
}

function _format_boolean(object){
return '<span class="json_boolean">' + object + '</span>';
}

function _format_number(object){
return '<span class="json_number">' + object + '</span>';
}

function _format_string(object){
if(0 <= object.search(/^http/)){
object = '<a href="' + object + '" target="_blank" class="json_link">' + object + '</a>'
}
return '<span class="json_string">"' + object + '"</span>';
}

function _format_array(object, indent_count){
var tmp_array = [];
for(var i = 0, size = object.length; i < size; ++i){
tmp_array.push(indent_tab(indent_count) + format(object[i], indent_count + 1));
}
return '[\n'
+ tmp_array.join(',\n')
+ '\n' + indent_tab(indent_count - 1) + ']';
}

function _format_object(object, indent_count){
var tmp_array = [];
for(var key in object){
tmp_array.push( indent_tab(indent_count) + '<span class="json_key">"' + key + '"</span>:' + format(object[key], indent_count + 1));
}
return '{\n'
+ tmp_array.join(',\n')
+ '\n' + indent_tab(indent_count - 1) + '}';
}

function indent_tab(indent_count){
return (new Array(indent_count + 1)).join(' ');
}

function _typeof(object){
var tf = typeof object,
ts = _toString.call(object);
return null === object ? 'Null' :
'undefined' == tf ? 'Undefined' :
'boolean' == tf ? 'Boolean' :
'number' == tf ? 'Number' :
'string' == tf ? 'String' :
'[object Function]' == ts ? 'Function' :
'[object Array]' == ts ? 'Array' :
'[object Date]' == ts ? 'Date' : 'Object';
};

function loadCssString(){
var style = document.createElement('style');
style.type = 'text/css';
var code = Array.prototype.slice.apply(arguments).join('');
try{
style.appendChild(document.createTextNode(code));
}catch(ex){
style.styleSheet.cssText = code;
}
document.getElementsByTagName('head')[0].appendChild(style);
}

loadCssString(
'.json_key{ color: purple;}',
'.json_null{color: red;}',
'.json_string{ color: #077;}',
'.json_link{ color: #717171;}',
'.json_array_brackets{}');

var _JSONFormat = function(origin_data){
this.data = 'string' != typeof origin_data ? origin_data :
JSON && JSON.parse ? JSON.parse(origin_data) : eval('(' + origin_data + ')');
};

_JSONFormat.prototype = {
constructor : JSONFormat,
toString : function(){
return format(this.data, 1);
}
}

return _JSONFormat;

})();

function create_result_contatiner(){
var $result = $('<pre id="result" style=" width: 100%; height: 100%; overflow: scroll; overflow-x: scroll; overflow-y:scroll"></pre>')
var $result_container = $('<div id="result_container" style="position: fixed; top: 1%; right: 8px; width: 5%; height: 97%; margin: 0; padding: 0; border:1px solid skyblue; background: #f8f8f8; line-height: 1.2em; font-size: 14px; cursor: pointer;"></div>');
$result_container.append($result);
$result_container.hover(function(){
$(this).stop(true).animate({width:'50%'}, 'slow');
}, function(){
$(this).stop(true).animate({width:'5%'}, 'slow');
});
$('body').append($result_container);
return [$result_container, $result];
}

(function request_intercept(args){
var $result_container = args[0],
$result = args[1];
$('form *[type="submit"]').bind('click', function(){
var _form = $(this).parents('form'),
_action = (_form.attr('action') || './'),
_method = (_form.attr('method') || 'get').toLowerCase(),
_params = {};
_form.find('input[type="text"]').each(function(){
var item = $(this);
_params[item.attr('name')] = item.val();
});
$['get' == _method ? 'get' : 'post'](_action, _params, function(response){
try{
var j = new JSONFormat(JSON && JSON.parse ? JSON.parse(response) : eval('(' + response + ')'));
$result.html(j.toString());
}catch (e){
$result.html($result.text(response).html());
}
$result_container.stop(true).animate({width:'50%'}, 'slow');
});
return false;
});
})(create_result_contatiner());

Android中的shape

shape类似CSS,用于背景,边框,便于兼容各种屏幕和分辨率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 填充色 -->
<solid android:color="#e4e4e4"/>
<!-- 描边 -->
<stroke android:color="#e4e4e4" />
<!-- 圆角半径 -->
<corners android:radius="4dip" />
<!-- 渐变 -->
<gradient
android:angle="45"
android:centerX="20dip"
android:centerColor="#ff0000"
android:startColor="#ffffff"
android:endColor="#000000"/>
<padding
android:left="10dip"/>
<size android:width="60dip"
android:height="30dip"/>
</shape>

shape属性:

rectangle:矩形 
oval:椭圆 
line:线,需要 stroke 来设置宽度 
ring:环形 

solid属性:

color:填充颜色 

stroke属性:

color:边框颜色 
width:边框宽度 
dashWidth:虚线框的宽度 
dashGap:虚线框的间隔 

corners属性:

radius:四个角的半径 
topRightRadius:右上角的半径 
bottomLeftRadius:右下角的半径 
opLeftRadius:左上角的半径 
bottomRightRadius:左下角的半径 

gradient属性:

startColor:其实颜色 
centerColor:中间颜色 
endColor:结束颜色 
centerX:中间颜色的相对X坐标(0 -- 1) 
centerY:中间颜色的相对Y坐标(0 -- 1) 
useLevel:(true/false), 是否用作LevelListDrawable的标志 
angle是渐变角度,必须为45的整数倍。0从左到右,90从下到上,180从右到左,270从上到下 
type:渐变模式。 默认线性渐变,可以指定渐变为radial(径向渐变)或者sweep(类似雷达扫描的形式) 
gradientRadius:渐变半径,径向渐变需指定半径。 

padding属性:

left:左内边距 
top:上内边距 
right:右内边距 
bottom:下内边距 

size属性:

width:宽 
height:高

批量word和PPT文档转pdf

由于linux上处理word和ppt比较麻烦,而且有文件格式专利的问题,所以以下操作全部在Windows下面进行。

首先需要安装Microsoft Save as PDF加载项,官方下载地址:http://www.microsoft.com/zh-cn/download/details.aspx?id=7

安装成功后可以手工将文档另存为pdf。

需要引用“Win32::OLE”模块

use Win32::OLE;
use Win32::OLE::Const 'Microsoft Word';
use Win32::OLE::Const 'Microsoft PowerPoint';

word转pdf:

sub word2pdf{
    my $word_file = $_[0];
    my $word = CreateObject Win32::OLE 'Word.Application' or die $!;
    $word->{'Visible'} = 0;
    my $document = $word->Documents->Open($word_file) || die("Unable to open document ") ; 
    my $pdffile = $word_file.".pdf";
    $document->saveas({FileName=>$pdffile,FileFormat=>wdExportFormatPDF});
    $document -> close ({SaveChanges=>wdDoNotSaveChanges});
    $word->quit();
}

ppt转pdf

sub ppt2pdf{
    my $word_file = $_[0];
    my $word = CreateObject Win32::OLE 'PowerPoint.Application' or die $!;
    $word->{'Visible'} = 1;
    my $document = $word->Presentations->Open($word_file) || die("Unable to open document ") ; 
    my $pdffile = $word_file.".pdf";
    $document->saveas($pdffile,32);
    $document -> close ({SaveChanges=>wdDoNotSaveChanges});
    $word->quit();
}

Read More

【Javascript】有关parseInt的讨论

问题由来,某群的一个讨论:

1
parseInt(1/0, 19) = 18;

parseInt的用法:

1
parseInt(string [, radix])

注意,第一个参数是String类型,当radix未指定的时候,那么默认基地是10。

转换规则:

  1. 首先查看位置 0 处的字符,判断它是否是个有效数字;如果不是,该方法将返回 NaN,不再继续执行其他操作。
  2. 位置 0 处的字符有效,该方法将查看位置 1 处的字符,依次向后进行同样的测试,直到发现非有效数字的字符或者到达字符串末尾为止,
  3. 返回转换成功的数字

因此有比较熟悉的例子:

1
2
parseInt('F') => 'NaN'
parseInt('F', 16) => 15

下面将Infinity作为第一参数,结果就是下面这样:

1
2
parseInt(Infinity) => 'NaN'
parseInt(Infinity, 16) => 'NaN'

先将Infinity转换为String类型(Infinity.toString() => ‘Infinity’),因为不论是十进制还是十六进制,第一个字符串都会失败,所以直接返回’NaN’。

但是’I’在19 ~ 36进制情况下,是可以转换为数字的,而且表示的数字就是18,所以:

1
2
3
4
parseInt('I', 19) => 18
parseInt('I', 20) => 18
...
parseInt('I', 36) => 18

由于

1
1/0 => Infinity;

所以

1
parseInt(1/0, 19) => 18;

由于基数radix的范围介于2 ~ 36之间,所以0 ~ 9, a ~ z, A ~ Z在36进制下都可以转换成功,转换测试如下:

1
2
3
4
5
6
7
8
9
10
11
12
var arr = [], A_code = 65, Z_code = 65 + 25;
for(var i = 0; i <= 9; ++i){
arr.push(i);
}
for(var i = A_code; i <= Z_code; ++i){
arr.push(String.fromCharCode(i));
}
//arr = [0, 1, 2, ... 9, 'A', 'B', ... 'Z']
arr.forEach(function(item){
// console.log(item, ':', parseInt(item, 36));
})
//output : 0:0, 1:1, 2:2, ... Z:35;

回到Infinity的例子:

第一个字符’I’在19 ~ 36基数的情况下都可以转换成功

第二个字符’N’在36进制中表示为23, 所以’N’在24 ~ 36基数的情况下都可以转换成功,

后面的字符类推
测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function ret_output(arr){
var str_output = [];
arr.reverse().forEach(function(el, index){
str_output.push(el + ' * ' + i + '**' + index); //'**' 表示阶乘
// str_output.push(el + ' * ' + 'Math.pow(' + i + ',' + index + ')');
});
console.log( i + '进制:',str_output.join(' + '), '=', parseInt(Infinity, i));
throw new Error('trans abort');
}
for(var i = 19; i <= 36; ++i){
var arr = [];
try{
Infinity.toString().split('').forEach(function(item, s_index){
var r = parseInt(item, i);
if(isNaN(r)){
ret_output(arr);
}
arr.push(r);
         if(s_index == Infinity.toString().length - 1){
ret_output(arr);
}

})
}catch(e){
}
}

结果:

19进制: 18 * 19**0 = 18 
20进制: 18 * 20**0 = 18 
21进制: 18 * 21**0 = 18 
22进制: 18 * 22**0 = 18 
23进制: 18 * 23**0 = 18 
24进制: 18 * 24**5 + 23 * 24**4 + 15 * 24**3 + 18 * 24**2 + 23 * 24**1 + 18 * 24**0 = 151176378 
25进制: 18 * 25**5 + 23 * 25**4 + 15 * 25**3 + 18 * 25**2 + 23 * 25**1 + 18 * 25**0 = 185011843 
26进制: 18 * 26**5 + 23 * 26**4 + 15 * 26**3 + 18 * 26**2 + 23 * 26**1 + 18 * 26**0 = 224651640 
27进制: 18 * 27**5 + 23 * 27**4 + 15 * 27**3 + 18 * 27**2 + 23 * 27**1 + 18 * 27**0 = 270812475 
28进制: 18 * 28**5 + 23 * 28**4 + 15 * 28**3 + 18 * 28**2 + 23 * 28**1 + 18 * 28**0 = 324267766 
29进制: 18 * 29**5 + 23 * 29**4 + 15 * 29**3 + 18 * 29**2 + 23 * 29**1 + 18 * 29**0 = 385849803 
30进制: 18 * 30**6 + 23 * 30**5 + 15 * 30**4 + 18 * 30**3 + 23 * 30**2 + 18 * 30**1 + 29 * 30**0 = 13693557269 
31进制: 18 * 31**6 + 23 * 31**5 + 15 * 31**4 + 18 * 31**3 + 23 * 31**2 + 18 * 31**1 + 29 * 31**0 = 16647948474 
32进制: 18 * 32**6 + 23 * 32**5 + 15 * 32**4 + 18 * 32**3 + 23 * 32**2 + 18 * 32**1 + 29 * 32**0 = 20115447389 
33进制: 18 * 33**6 + 23 * 33**5 + 15 * 33**4 + 18 * 33**3 + 23 * 33**2 + 18 * 33**1 + 29 * 33**0 = 24164998832 
34进制: 18 * 34**6 + 23 * 34**5 + 15 * 34**4 + 18 * 34**3 + 23 * 34**2 + 18 * 34**1 + 29 * 34**0 = 28872273981 
35进制: 18 * 35**7 + 23 * 35**6 + 15 * 35**5 + 18 * 35**4 + 23 * 35**3 + 18 * 35**2 + 29 * 35**1 + 34 * 35**0 = 1201203301724 
36进制: 18 * 36**7 + 23 * 36**6 + 15 * 36**5 + 18 * 36**4 + 23 * 36**3 + 18 * 36**2 + 29 * 36**1 + 34 * 36**0 = 1461559270678

Android 触屏事件流

本文请忽略,初学 Android 时的幼稚记录而已。

一次触屏事件分为三个动作

  1. ACTION_DOWN
  2. ACTION_MOVE
  3. ACTION_UP

其中 ACTION_DOWN 和 ACTION_UP 在一次触屏事件中只会触发一次,ACTION_MOVE 可能触发任意次(包括0次)。

主要响应触屏的组件有两种,一种是可以包含子元素的(ViewGroup比如LinearLayout),另一种是不能包含子元素的View(最底层的View比如Button)。

当一个触屏事件产生时,正两者的响应方法有一个主要的区别就是LinearLayout有onInterceptTouchEvent方法,而Button没有onInterceptTouchEvent方法。

ViewGroup(比如LinearLayout)

1
2
3
boolean dispatchTouchEvent(MotionEvent event)
boolean onInterceptTouchEvent(MotionEvent event)
boolean onTouchEvent(MotionEvent event)

View(比如Button)

1
2
boolean dispatchTouchEvent(MotionEvent event)
boolean onTouchEvent(MotionEvent event)

总的来说,dispatchTouchEvent 决定处不处理,onInterceptTouchEvent 决定谁来处理,onTouchEvent 决定怎么处理。
所以对于Button来谁,没有小弟,自然不存在决定谁来处理的问题,故没有onInterceptTouchEvent方法

下面具体说一下这三个函数的主要作用:

dispatchTouchEvent

dispatchTouchEvent 决定处不处理,看名字就知道是事件分发,初看我还以为是分发到子元素呢,原来不是直接到子元素。其实更好的理解是这是一个过滤方法。
此方法的主要作用是决定相应事件的类型。

假如dispatchTouchEvent 返回 false,那么在响应了 ACTION_DOWN 之后,后续的 ACTION_MOVE 和 ACTION_UP 均忽略,因此ACTION_MOVE和ACTION_UP永远不会有得到处理的机会。
假如dispatchTouchEvent 返回 true,那么后续的 ACTION_MOVE 和 ACTION_UP 均被接受,可以被其他方法响应。

特别注意,如果在这一步的dispatchTouchEvent中没有调用super.dispatchTouchEvent(event),那么事件就到此为止,被终结了。
此时此刻只有dispatchTouchEvent会响应事件,另外两个方法根本没有机会来响应事件。并且,事件不会传递到子元素中。

onInterceptTouchEvent

onInterceptTouchEvent,主要决定谁来处理(即是否拦截事件)。

只要在dispatchTouchEvent中调用了super.dispatchTouchEvent(event)那么,事件(event)会被交给onInterceptTouchEvent去处理。
注意,这里事件(event)是否会调用onInterceptTouchEvent与dispatchTouchEvent的返回值是true还是false无关。
再次强调,dispatchTouchEvent只决定处理什么,并不能指定谁来调用。

假如onInterceptTouchEvent返回false,将事件(event)交自己的子元素处理(此时事件流是从外到内,从父元素到子元素)。

假如onInterceptTouchEvent返回true,将事件(event)交给自己的onTouchEvent来处理,并且如果有后续的 ACTION_MOVE 和 ACTION_UP(前一步dispatchTouchEvent中返回true)的话,将不再调用onInterceptTouchEvent,直接将事件传递给自己的onTouchEvent来处理。

onTouchEvent

注意上一步,在 onInterceptTouchEvent 返回true的情况下,onTouchEvent 将获得事件并进行具体的处理。

假如 onTouchEvent 返回 false,将事件(event)交父元素处理,(注意在这一步,事件流反向了,此时事件流是从内到外,从子元素到父元素)。
假如 onTouchEvent 返回 true,本次事件(event)就到此为止,被终结了。

对照上面的说法,下面给出实例说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class MyLinearLayout1 extends LinearLayout{

private String TAG = "第一层MyLinearLayout";

public MyLinearLayout1(Context context) {
super(context);
this.setBackgroundColor(Color.WHITE);
}
public void setTagString(String tag){
TAG = tag;
}

@Override
public boolean dispatchTouchEvent(MotionEvent event){
if(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG + "dispatchTouchEvent:", "ACTION_DOWN");
}else if(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG + "dispatchTouchEvent:", "ACTION_MOVE");
}else{
Log.v(TAG + "dispatchTouchEvent:", "ACTION_UP");
} //super.dispatchTouchEvent(event); return true;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event){super.onInterceptTouchEvent

if(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG + "onInterceptTouchEvent:", "ACTION_DOWN");
}else if(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG + "onInterceptTouchEvent:", "ACTION_MOVE");
}else{
Log.v(TAG + "onInterceptTouchEvent:", "ACTION_UP");
}
return true;
}

@Override
public boolean onTouchEvent(MotionEvent event){super.onTouchEvent(event)
if(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG + "onTouchEvent:", "ACTION_DOWN");
}else if(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG + "onTouchEvent:", "ACTION_MOVE");
}else{
Log.v(TAG + "onTouchEvent:", "ACTION_UP");
}

return true;
}
}

此时没有调用super.dispatchTouchEvent(event),所以事件没有机会得到其他的处理。

打印信息:

第一层MyLinearLayoutdispatchTouchEvent:(460): ACTION_DOWN
第一层MyLinearLayoutdispatchTouchEvent:(460): ACTION_UP
如果将上面boolean dispatchTouchEvent(MotionEvent event)的返回值修改为false,那么按照前面说的,MyLinearLayout1在响应了ACTION_DOWN之后,不会再响应本次触屏操作的其他事件。所以此时的打印结果是:
第一层MyLinearLayoutdispatchTouchEvent:(460): ACTION_DOWN

可以看到,ACTION_UP没有被响应,因为本事件被忽略了。

现在,将super.dispatchTouchEvent(event)的注释去掉,注意,现在的boolean dispatchTouchEvent(MotionEvent event)变成下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	@Override
public boolean dispatchTouchEvent(MotionEvent event){
if(MotionEvent.ACTION_DOWN == event.getAction()){
Log.v(TAG + "dispatchTouchEvent:", "ACTION_DOWN");
}else if(MotionEvent.ACTION_MOVE == event.getAction()){
Log.v(TAG + "dispatchTouchEvent:", "ACTION_MOVE");
}else{
Log.v(TAG + "dispatchTouchEvent:", "ACTION_UP");
}

super.dispatchTouchEvent(event);//去掉注释了

return true;
}

打印信息:

第一层MyLinearLayout ACTION_DOWN:(783): ACTION_DOWN
第一层MyLinearLayout onInterceptTouchEvent:(783): ACTION_DOWN
第一层MyLinearLayout onTouchEvent:(783): ACTION_DOWN
第一层MyLinearLayout dispatchTouchEvent:(783): ACTION_UP
第一层MyLinearLayout onTouchEvent:(783): ACTION_UP

具体顺序为下:

ACTION_DOWN:ACTION_DOWN——>onInterceptTouchEvent——>onTouchEvent
ACTION_UP:ACTION_DOWN——>onTouchEvent

哪个HTML5?WHATWG与W3C或分道扬镳

W3C和WHATWG这两个当前负责HTML开发的组织对于标准分裂在一定程度上达成了初步共识,意味着未来将有两个版本的HTM5——“snapshot”版本和“living standard”版本。

WHATWG当初是为了回应W3C在HTML标准上的缓慢进展而成立的。实际上,W3C原本已经或多或少的放弃了HTML,转而集中到XML和XHTML上面来,问题是,大部分用户只是单纯想继续 使用HTML并持续改进。

结果,WHATWG从2004年开始将HTML标准推向前进,2007年左右,W3C将WHATWG的工作成果纳入HTML5标准。两个机构共同维护HTML5标准,但是现在,他们在一些方法的制定上出现了巨大的分歧。

通俗来说就是,当年W3C嫌自己的儿子HTML没出息,就拿出去扔在河边了,WHATWG路过捡回去养,后来HTML长大了,出息了,W3C又找WHATWG来要儿子,WHATWG好歹也养了三年,不是很同意,但是生父终究是生父啊,于是就共同抚养呗。W3C领HTML回去之后,给HTML取个新名字“HTML5”,但是抚养过程中,W3C想要HTML5当公务员,找个稳定的金饭碗,WHATWG想要HTML5去创业,于是分歧越来越大,最终HTML5精神分裂,一半去给W3C当儿子,一半去给WHATWG当儿子。

过去的几年中,这两个组织在方法制定上就分歧不断,趋向分裂,现在这种分裂形式化了而已。

Read More