diff --git a/README.md b/README.md
deleted file mode 100644
index 393a0de4..00000000
--- a/README.md
+++ /dev/null
@@ -1,1066 +0,0 @@
-## context
-
-context是一种新的编程语言与应用框架,通过模块化、集群化、自动化,实现软件的快速开发,快速共享,快速使用。
-
-context是以群聊的形式,进行资源的共享。
-用户可以创建任意的群聊,把相关人员聚集在一起,每个人可以将自己的设备,共享到群聊中,供组员使用,从而实现资源的最大利用。
-每个设备上有一堆命令,用户可以将任意设备上任意命令,添加到自定义的应用界面中,按照自己的需求去组合,从面实现场景化与个性化的定制。
-所以每个群聊中会有各种各样自定义的应用,所有的命令都是以群聊作为场景,进行权限的检查与分配。
-这些应用,可以像文本与图片一样,在群聊里自由的流动,可以被更快分享出去,再次收藏与组合形成新的应用组件,还可以在聊天记录中直接使用。
-
-context是以分布式的方式,进行程序的开发。
-开发者,可以用脚本语言开发应用,随时随地的在自己任意设备上加载脚本,然后将动态域名分享出去,应用就可以被用户在群聊中任意的传播。
-所有的代码与数据,都在自己设备上,可以进行任意的实时控制。
-消灭所有中间环节,让几行代码的小函数,就可以成为独立的应用,从而实现软件的快速开发与快速传播,将任意一行代码的价值,放大成千上万倍。
-
-## 下载安装
-在Linux或Mac上,可以直接用脚本下载,
-在Windows上,可以先安装[GitBash](https://www.git-scm.com/download/),然后在GitBash中执行命令下载。
-```
-$ curl https://shylinux.com/publish/boot.sh | bash -s install context
-```
-
-install后面的参数context,就是指定的下载目录,
-进入下载目录,可以看到的有八个文件。
-
-在bin目录下,就是各种执行文件
-
-- bin/bench,context的执行程序
-- bin/boot.sh,context的启动脚本
-- bin/zone.sh,启动区域节点
-- bin/user.sh,启动用户节点
-- bin/node.sh,启动工作节点
-
-context内部实现了语法解析,通过自定义的脚本语言,实现功能的灵活控制。
-
-在etc目录下,就是context执行过程中用到的脚本。
-
-- etc/init.shy,启动时加载的脚本
-- etc/exit.shy,结束时运行的脚本
-- etc/common.shy,init.shy调用到的脚本
-
-## 创建集群
-context是一种分布式框架,可以运行在任意设备上,并且实现了自动组网、自动路由、自动认证。
-远程命令与本地命令,无差别的运行,从而实现无限扩容的分布式计算。
-
-context每个启动的进程都是一个独立的节点,根据网络框架中的功能作用,可以分为区域节点、用户节点、工作节点、分机节点。
-这几种节点,除了网络框架中的作用外,其它的功能模块与命令都完全一样,没有差别。
-
-个人使用,可以创建一个区域节点,下挂多个工作节点。
-
-团队使用,需要创建一个区域节点,多个用户节点,每个用户节点下,可以挂多个工作节点。
-
-如果用户节点或工作节点过多,可以创建分机节点,通过增加层级来降低单机负载。
-
-### 个人使用
-#### 启动区域节点
-打开终端,进入context目录,执行如下命令,
-```
-$ bin/zone.sh
-0[13:26:27]nfs>
-```
-
-#### 启动工作节点
-再打开终端,进入context目录,执行如下命令,
-```
-$ bin/node.sh create app/hello
-
-0[13:26:27]nfs> remote
-create_time pod type
-2019-07-30 13:26:27 com master
-```
-启动context后,调用remote命令,可以查看到有一个上级节点。
-
-#### 启动工作节点
-再打开终端,进入context目录,执行如下命令,
-```
-$ bin/node.sh create app/world
-
-0[13:26:27]nfs> remote
-create_time pod type
-2019-07-30 13:26:27 com master
-```
-
-#### 分布式命令
-启动两种节点节点后,就可以在任意节点上调用命令,也可以调用远程节点的命令。
-如在区域节点上调用remote,就可以看到两个工作节点。
-```
-4[13:27:26]nfs> remote
-create_time pod type
-2019-07-30 13:26:27 hello worker
-2019-07-30 13:26:30 world worker
-```
-
-查看当前路径
-```
-3[13:39:29]nfs> pwd
-D:\context/var
-4[13:40:03]nfs>
-```
-
-查看当时目录
-```
-4[13:40:03]nfs> dir
-time size line path
-2019-07-23 21:36:36 387 4 var/hi.png
-2019-07-27 13:41:56 4096 4 var/log/
-2019-06-15 10:58:03 0 1 var/run/
-2019-07-30 12:55:19 4096 8 var/tmp/
-5[13:40:20]nfs>
-```
-
-执行远程命令,只需要在命令前加上节点名与冒号。
-```
-6[13:41:28]nfs> hello:pwd
-D:\context\hello/var
-6[13:41:28]nfs> world:pwd
-D:\context\world/var
-```
-
-在任意随机节点上执行命令,用百分号作节点名。
-```
-5[13:40:20]nfs> %:pwd
-D:\context\hello/var
-5[13:40:20]nfs> %:pwd
-D:\context\world/var
-```
-
-在所有节点上执行命令,用星号作节点名。
-```
-7[13:41:36]nfs> *:pwd
-D:\context\hello/var D:\context\hello/var
-```
-
-## 团队使用
-context也可以支持团队协作使用,这时候就需要将区域节点部署到公共主机上。
-区域节点的作用就是生成动态域名,分发路由,解决命名冲突,与权限分配等功能。
-
-### 启动用户节点
-在公共主机上启动区域节点后,每个组员就可以在自己主机上启动用户节点,但需要指定区域节点的地址。
-如下命令,ip换成自己的公共主机,9095端口保留,这是context默认的web端口。
-```
-$ ctx_dev=http://192.168.88.102:9095 bin/user.sh
-```
-
-### 启动工作节点
-同样每个用户都可以启动多用工作节点。
-```
-$ bin/node.sh create world
-```
-
-### 启动团队协作
-当有多个用户连接到公共节点后,用户与用户之间就可以相互访问对方的所有节点。
-但是默认启用了节点认证,所有命令都没有权限。所以调用对应节点上的命令,需要对方开启命令权限。
-
-每个用户随时都可以在自己节点上,为其它用户设置任意角色,给每个角色分配任意命令。
-从而实现安全快速的资源共享。
-
-
-## 启动分机节点
-当区域的用户节点过多,就可以启动分机节点。
-启动分机节点,只需要指定上级节点即可。
-用户在连接公共节点时,指定这个新节点的ip即可。
-context会自动生成新的网络路由。
-
-```
-$ ctx_dev=http://192.168.88.102:9095 bin/boot.sh
-```
-
-## 创建群聊
-除了命令行的使用的方式之外,context还有自己的前端框架。
-不仅降低了使用难度,还提供更加场景化、自动化的应用界面。
-
-用户可以访问区域节点或是任意用户节点的网页服务。
-
-http://127.0.0.29:9095
-
-输入用户名与初始密码,即可登录,如果用户与主机上的用户名相同,则是管理员权限,如果不同,则是普通用户,只有最小的功能权限。
-
-所以任意节点都支持多用户共享使用,但只有管理用户有所有权限,进行资源的管理与分配。
-
-打开应用界面,就可以看到context以办公聊天软件的形式提供各种丰富的功能。
-
-左边框是用户群组列表,用户可以选择群聊或是创建新的群聊。
-中间就是聊天记录与输入框,用户可以自由的聊天收发消息。
-
-与其它聊天软件不同的是,context提供了自定义的功能列表。
-右边框中,就是此群组的功能列表。
-每个用户都可以将自己设备上的命令添加到这个群组的功能列表中,分享给本组员使用。
-每个组员都可以根据自己的需求组合这些命令,生成自己的应用界面。
-
-以每个群聊作为场景,进行资源的共享与应用的开发,从而实现更加场景化与个性化应用。
-
-通过这种精细化的应用场景,进行工具化、标准化、流程化。提高各行各业的工作效率。
-
-## 应用开发
-
-网络框架与应用界面,已经实现了标准化与自动化,剩下就是应用的开发了。
-
-开发者,可以在任意机器上开发自己的应用。以模块与函数为单位进行开发与上线。
-一个函数,即使只有几行代码,也是一个独立完整的应用,可以随时上线,被任意用户使用。
-
-用户还可以在任意群聊中转发此应用,更自由的传播出去。
-从而将软件开发的速度提升成千上万倍,将代码的使用效率提升成千上万倍。
-
-### 创建项目
-在任意节点上,执行project命令,指定项目名,即可创建应用目录。
-```
-$ bin/user.sh
-8[13:41:41]nfs> project hello
-time line hash path
-2019-07-30 14:27:09 35 eba8eda2 src/plugin/hello/index.go
-2019-07-30 14:27:09 1 b858cb28 src/plugin/hello/index.shy
-2019-07-30 14:27:09 1 b858cb28 src/plugin/hello/local.shy
-2019-07-30 14:27:09 4 407265b6 src/plugin/hello/index.js
-9[14:27:09]nfs>
-```
-每个项目,都可以用go语言开发低层应用,用js开发前端交互。
-除此,context有自己的通用语法解析器,开者完全可以随时自定义语法,定制自己的解析器。
-用自己喜欢的语法开发应用。
-
-默认的shy语法,提供了一个完整的前后端应用框架。创建项目时,自动创建的模块如下。
-```
-fun hello world "" "" \
- public \
- text "" \
- button "执行"
- copy pwd
-end
-```
-
-这个模板就是一个完整的应用,fun关键字开关,end关键字结束。
-前四行就是定义应用界面,剩下代码就是后端脚本。
-public代表,这个应用是公共的,所以有人都可以访问。也可以是private,只有管理用户可以访问。
-
-text与button,就是需要前端展示的控件。用户在前端点击此button,就会将请求发送到后端,执行此脚本。
-然后将执行结果返回给前端界面。
-
-### 加载项目
-切换到cli模块,使用upgrade命令,加载新的项目应用。
-```
-8[13:41:41]nfs> ~cli
-8[13:41:41]cli> upgrade plugin hello
-3[15:55:53]cli> ~
-names ctx msg status stream helps
-ctx 0 start stdio 模块中心
-cli ctx 4 begin 管理中心
-hello cli 5958 start shy
-4[15:57:00]cli>
-```
-
-切换到hello模块,使用command命令,可以查看到hello模块下的命令列表,然后就可以调用hello命令。
-```
-8[13:41:41]cli> ~hello
-6[15:58:42]hello> command
-key name
-hello hello world public text button 执行
-7[20:27:32]nice> hello
-D:\context/var
-```
-
-同时在前端界面上添加功能,即可看到此函数。
-
-context内部实现了很多功能模块,每个模块下有很多命令,每条命令就是一种应用。
-
-context的使用方式有很多种,
-
-- 可以直接调用,像Shell一样,去解析一条命令
-- 可以启动cli服务,像MySQL一样,交互式使用格式化命令
-- 可以启动web服务,像LabView一样,可以自定义各种图形界面
-- 可以自动组网,将任意台设备组合在一起,实现分布式应用
-- 可以自动建群,在群聊场景中,实现多用户、多会话、多任务、多设备的使用
-
-### 命令模式
-如果只是使用一条命令,或是写在脚本文件中,可以使用这种方式。
-
-例如,dir命令就是查看目录,
-```
-$ bin/bench dir
-time size line filename
-2019-06-16 10:35:18 324 11 common.shy
-2019-06-16 10:35:18 201 9 exit.shy
-2019-06-16 10:35:18 261 13 init.shy
-```
-
-还可以加更多参数,dir_deep递归查询目录,dir_type文件类型过滤,dir_sort输出表排序。
-```
-$ bin/bench dir ../ dir_deep dir_type file dir_sort line int_r
-time size line filename
-2019-06-16 10:22:52 13256968 91314 bench
-2019-06-16 11:10:16 1535 66 boot.sh
-2019-06-16 11:10:16 613 31 node.sh
-2019-06-16 11:10:16 261 13 init.shy
-2019-06-16 11:10:16 324 11 common.shy
-2019-06-16 11:10:16 201 9 exit.shy
-
-```
-
-### 交互模式
-
-启动服务,可以提供更丰富的命令与环境。
-```
-$ bin/bench
-0[11:35:46]ssh> dir
-time size line filename
-2019-06-16 11:35:06 160 3 log/
-2019-06-16 11:35:06 96 1 run/
-2019-06-16 11:35:44 192 4 tmp/
-1[11:35:46]ssh>
-```
-
-如果集中管理,命令越多,系统只会越复杂,学习成本越高,使用越低效,开发越困难。
-
-所以通过模块化,分而治之,更高效的管理丰富的命令。
-
-context命令就是用来管理模块,没有参数时,直接查看当前模块的信息。
-
-如下,第二行是当前模块,第一行是当前模块的父模块,其它行都是当前模块的子模块。
-
-```
-1[11:39:01]ssh> context
-names ctx msg status stream helps
-ctx 0 start shy 模块中心
-ssh ctx 10 begin ctx.nfs.file3 集群中心
-```
-
-context第一个参数,可以指定当前模块,
-如下,切换到nfs模块,然后查看各种IO模块,
-切换到ctx根模块,查看所有模块。
-```
-2[11:43:57]ssh> context nfs
-
-3[11:43:58]nfs> context
-names ctx msg status stream helps
-ctx 0 start shy 模块中心
-nfs ctx 9 begin 存储中心
-stdio nfs 1174 start stdio scan stdio
-
-4[11:44:22]ssh> context ctx
-
-5[11:45:17]ctx> context
-names ctx msg status stream helps
-ctx 0 start shy 模块中心
-aaa ctx 3 begin 认证中心
-cli ctx 4 begin 管理中心
-gdb ctx 232 start 调试中心
-lex ctx 6 begin 词法中心
-log ctx 31 start bench 日志中心
-mdb ctx 8 begin 数据中心
-nfs ctx 9 begin 存储中心
-ssh ctx 10 begin 集群中心
-tcp ctx 11 begin 网络中心
-web ctx 1094 start :9094 应用中心
-yac ctx 13 begin 35,14,23 语法中心
-shy cli 1171 start engine shell
-matrix1 lex 34 start 76,28,2 matrix
-stdio nfs 1174 start stdio scan stdio
-chat web 14 begin 会议中心
-code web 15 begin 代码中心
-wiki web 16 begin 文档中心
-engine yac 1173 start stdio parse
-
-```
-
-command命令,就是用来管理当前模块的命令,
-```
-17[11:52:02]nfs> context nfs
-
-17[11:52:02]nfs> command
-key name
-_init _init
-action action cmd
-copy copy to from
-dir dir [path [fields...]]
-export export filename
-git git sum
-hash hash filename
-import import filename [index]
-json json str
-load load file [buf_size [pos]]
-open open file
-path path filename
-printf printf arg
-prompt prompt arg
-pwd pwd [all] | [[index] path]
-read read [buf_size [pos]]
-remote remote listen|dial args...
-save save file string...
-scan scan file name
-send send [file] args...
-temp temp data
-term term action args...
-trash trash file
-write write string [pos]
-
-```
-
-help子命令,查看命令帮助信息。
-```
-18[11:59:19]nfs> command help dir
-dir: dir [path [fields...]]
- 查看目录, path: 路径, fields...: 查询字段, time|type|full|path|tree|filename|size|line|hash
- dir_deep: 递归查询
- dir_type both|file|dir|all: 文件类型
- dir_reg reg: 正则表达式
- dir_sort field order: 排序
-```
-
-
-### 集群模式
-
-context提供自动化集群的功能,可以自动组网、自动认证。从而快速实现多台设备的协同工作。
-
-#### 启动服务节点
-```
-$ bin/boot.sh
-0[11:35:12]ssh>
-```
-
-#### 启动工作节点
-
-新打开一个终端,启动工作节点,执行remote命令,查看上级节点,
-```
-$ bin/boot.sh create app/demo
-0[15:15:30]ssh> remote
-key type module create_time
-mac master ctx.nfs.file3 2019-06-16 15:15:23
-```
-
-回到服务节点终端,执行remote命令,可以查看到所有远程节点。
-```
-2[15:15:31]ssh> remote
-key type module create_time
-com master ctx.nfs.file4 2019-06-16 14:25:10
-demo worker ctx.nfs.file7 2019-06-16 15:15:23
-```
-
-默认配置中,子节点信任父,所以父节点可以调用子节点的命令。还有更复杂的认证机制,可以灵活配置。
-
-远程命令和本地命令一样,没有任何区别。如下调用demo节点的pwd命令。还支持更复杂的多节点命令,可以更快速的同时管理多台设备。
-```
-2[15:15:31]ssh> remote demo pwd
-/Users/shaoying/context/app/demo/var
-```
-
-#### 启动分机节点
-
-在服务节点的终端,查看服务地址
-```
-3[15:49:00]ssh> web.brow
-index site
-0 http://192.168.199.139:9094
-```
-
-同样,在另一台设备上下载context,然后启动服务节点。
-通过环境变量ctx_dev指定上级节点。
-```
-$ ctx_dev="http://192.168.199.139:9094" bin/boot.sh
-0[15:49:00]ssh> remote
-key type module create_time
-mac master ctx.nfs.file3 2019-06-16 15:15:23
-```
-
-回到服务节点终端,执行remote命令,可以查看到新添加了一个服务子节点。
-```
-2[15:15:31]ssh> remote
-key type module create_time
-com master ctx.nfs.file4 2019-06-16 14:25:10
-demo worker ctx.nfs.file7 2019-06-16 15:15:23
-sub server ctx.nfs.file8 2019-06-16 16:15:23
-```
-
-同样可以远程调用命令。
-```
-2[15:15:31]ssh> remote sub pwd
-/Users/shaoying/context/app/sub/var
-```
-
-#### 文件管理
-调用本地命令,查看当前目录下的文件列表,
-```
-0[10:53:25]ssh> ls
-total 0
-drwxr-xr-x 5 shaoying staff 160 May 10 03:57 bin
-drwxr-xr-x 5 shaoying staff 160 May 10 03:30 etc
-drwxr-xr-x 2 shaoying staff 64 May 10 03:30 usr
-drwxr-xr-x 8 shaoying staff 256 May 10 03:36 var
-```
-
-调用内部命令,查看文件列表,如下dir与ls命令用途相似,但提供了更丰富的功能,如统计文件行数
-```
-5[10:56:24]ssh> dir etc
-time size line filename
-2019-04-14 21:29:21 316 10 common.shy
-2019-04-29 21:12:28 130 7 exit.shy
-2019-04-29 21:12:12 191 12 init.shy
-```
-
-"%"是一个内部命令,可以对前一步命令结果进行各种处理。如下按字段line排序
-```
-5[10:56:24]ssh> dir etc % order line
-time size line filename
-2019-04-29 21:12:12 191 12 init.shy
-2019-04-14 21:29:21 316 10 common.shy
-2019-04-29 21:12:28 130 7 exit.shy
-```
-
-如下按字段""聚合,即可得到汇总结果,所有文件的总字节数、总行数、总文件数
-```
-16[11:04:30]ssh> dir etc % group ""
-time size line filename count
-2019-04-14 21:29:21 637 29 common.shy 3
-```
-
-#### 时间管理
-查看当前时间戳
-```
-18[11:11:01]ssh> time
-1557457862000
-```
-将时间戳转换成日期
-```
-19[11:11:14]ssh> time 1557457862000
-2019-05-10 11:11:02
-```
-将日期转换成时间戳
-```
-20[11:11:25]ssh> time "2019-05-10 11:11:02"
-1557457862000
-```
-
-#### 网卡管理
-```
-2[10:53:25]ssh> ifconfig
-index name ip mask hard
-5 en0 192.168.0.106 24 c4:b3:01:cf:0b:51
-```
-
-### 完整版
-命令行模式,只是context最基本的功能。context还提供了一个前端框架,
-让用户可以自由的组合功能列表,满足自己的需求。
-
-使用更丰富的功能,可以直接下载源码,
-```
-$ git clone https://github.com/shylinux/context.git
-```
-下载完源码后,如果安装了golang,就可以对源码直接进行编译,
-如果没有可以去官网下载安装golang()。
-第一次make时,会自动下载各种依赖库,所以会慢一些。
-```
-$ cd context && make
-```
-
-#### 启动服务
-bin目录下是各种可执行文件,如启动脚本boot.sh与node.sh。
-
-node.sh用来启动单机版context,boot.sh用来启动网络版context。
-
-如下,直接运行脚本,即可启动context。
-
-启动context后,就可以解析执行各种命令,即可是本地的shell命令,也可以是内部模块命令。
-
-```
-$ bin/node.sh
-0[03:58:43]ssh>
-```
-
-#### 网页服务
-
-下载完整版的context,启动的服务节点,就会带有前端网页服务。
-
-#### 知识库
-
-wiki模块提供了知识库管理。
-
-访问:http://localhost:9094/wiki
-
-wiki模块会将usr/wiki目录下的md文件进行解析,生成网页文件,并自动生成目录与索引。
-
-可以创建自己的知识库,如下创建目录与文件。
-
-```
-$ mkdir -p usr/wiki/some
-$ echo "hello world" > usr/wiki/some/hi.md
-```
-
-然后在服务终端上,切换到新建的知识库,
-```
-0[10:53:25]ssh> ~wiki config wiki_level wiki/some
-```
-
-也可以加到启动文件中,
-```
-$ cat etc/local.shy
-~wiki
- config wiki_level wiki/some
-```
-
-#### 用户界面
-
-chat模块提供了完整的功能系统。
-
-在一台公共的设备上启动服务节点,在etc/local.shy的启动脚本中加入如下两行命令。此设备就可以成为公共服务器。
-```
-~ssh
- work serve
-```
-
-在任意其它设备上,每个用户都可以启动自己的节点,在启动脚本etc/local.shy,添加如下两行代码,此设备就可以成为用户的主控节点。
-```
-~ssh
- work create
-```
-
-在启动用户节点时,只要指定服务节点,就可以实现用户注册,自动加入群组。
-```
- ctx_dev=http://172.0.0.172 bin/boot.sh
-```
-
-然后登录 http://172.0.0.172:9095/chat 或 http://127.0.0.127:9095/chat ,
-输入自己的用户名,与初始密码,就可以登录系统。
-
-然后就可以自由的创建群聊、共享设备、实时聊天。
-
-#### 模块开发
-```
-project hello
-compile hello
-publish hello
-```
-
-### 所有目录
-
-#### 一级目录
-
-- src
-- etc
-- bin
-- var
-- usr
-
-#### 源码目录
-
-- src/toolkit
-- src/context
-- src/example
-- src/plugin
-
-#### 配置文件
-
-- etc/init.shy
-- etc/common.shy
-- etc/exit.shy
-
-#### 执行文件
-
-- bin/boot.sh
-- bin/node.sh
-- bin/bench
-
-#### 日志文件
-
-- var/log/boot.log
-- var/log/error.log
-- var/log/right.log
-- var/log/bench.log
-- var/log/debug.log
-- var/run/bench.pid
-- var/run/user/cert.pem
-- var/run/user/key.pem
-- var/run/node/cert.pem
-- var/run/node/key.pem
-- var/tmp/runtime.json
-- var/tmp/auth.json
-
-#### 应用目录
-
-- usr/template
-- usr/librarys
-- usr/upgrade
-- usr/client
-
-## 应用开发
-- Windows
-- Mac
-- pi
-- mp
-- iOS
-- Android
-
-### 应用接口
-
-context的应用模块都是web的子模块,在web模块启动HTTP服务后,会根据模块名与命令名自动生成路由。
-web模块会将所有的HTTP请求转换成context的命令调用,所以HTTP的应用接口和普通命令,除了名字必须以"/"开头,其它没有太大区别。
-
-当web接收到HTTP请求后,可以调用单个命令如 http://shylinux.com/code/consul 就会调用code模块下的/consul命令
-
-可以调用多个命令如 http://shylinux.com/code/?componet_group=login 就会调用web模块下的/render命令,
-根据code的componet下的login组件,依次调用每个接口的命令,然后将执行结果与参数一起,调用golang的template,渲染生成HTML。
-
-所有命令都解析完成后就可以生成一个完整的网页。当然如果Accept是application/json,则会跳过模块渲染,直接返回多条命令的执行结果。
-所以componet就是接口的集合,统一提供参数配置、权限检查、命令执行、模板渲染,前端展示样式,前端初始化函数,降低内部命令与外部应用的耦合性,但又将前后端完全融合在一起。
-
-如下,是web.code模块的应用接口定义。配置componet下定义了多个组件,每个组件下定义了多个接口。
-
-login就是登录页面,下面定义了三个接口code、login、tail,
-其中code,使用模板head生成网页头,会包括一些配置,如favicon可以指定图标文件,styles指定引用模式表。
-其中tail,使用模板tail生成网页尾,会包括一些配置,如scripts指定引用脚本文件。
-login就是网页组件了,生成一个网页登录的输入表单,并接收表单请求调用aaa模块的auth命令,进行用户身份的验证。
-其中arguments指定了Form表单字段的列表。
-```
-...
-var Index = &ctx.Context{Name: "code", Help: "代码中心",
- Caches: map[string]*ctx.Cache{},
- Configs: map[string]*ctx.Config{
- "skip_login": &ctx.Config{Name: "skip_login", Value: map[string]interface{}{"/consul": "true"}, Help: "免密登录"},
- "componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{
- "login": []interface{}{
- map[string]interface{}{"componet_name": "code", "componet_tmpl": "head", "metas": []interface{}{
- map[string]interface{}{"name": "viewport", "content": "width=device-width, initial-scale=0.7, user-scalable=no"},
- }, "favicon": "favicon.ico", "styles": []interface{}{"example.css", "code.css"}},
-
- map[string]interface{}{"componet_name": "login", "componet_help": "login", "componet_tmpl": "componet",
- "componet_ctx": "aaa", "componet_cmd": "auth", "componet_args": []interface{}{"@sessid", "ship", "username", "@username", "password", "@password"}, "inputs": []interface{}{
- map[string]interface{}{"type": "text", "name": "username", "value": "", "label": "username"},
- map[string]interface{}{"type": "password", "name": "password", "value": "", "label": "password"},
- map[string]interface{}{"type": "button", "value": "login"},
- },
- "display_append": "", "display_result": "",
- },
-
- map[string]interface{}{"componet_name": "tail", "componet_tmpl": "tail",
- "scripts": []interface{}{"toolkit.js", "context.js", "example.js", "code.js"},
- },
- },
-...
-```
-### 网页开发
-
-#### 模板
-
-usr/template 存放了网页的模板文件,context会调用golang的template接口进行后端渲染,生成html文件。
-不同的应用模块都会有自己的模板目录,也有公共模板库。
-
-- usr/template/common.tmpl 公共模板
-- usr/template/code/ code模块的模板
-- usr/template/wiki/ wiki模块的模板
-- usr/template/chat/ chat模块的模板
-
-#### 样式
-
-所有的css都存放usr/librarys
-
-- example.css
-- code.css
-- wiki.css
-- chat.css
-
-#### 脚本
-
-所有的js都存放usr/librarys
-
-- toolkit.js 工具库,主要是网页相关的操作,如AppendChild
-- context.js 通信库,主要是用来与后端context进行通信
-- example.js 框架库,统一定义了网页的框架,每个应用网页都会继承
-- code.js 工具链应用的网页
-- wiki.js 知识库应用的网页
-- chat.js 信息流应用的网页
-
-### 小程序
-### 开发板
-
-## 接口开发
-### componet
-### python
-### java
-### c
-
-## 模块开发
-### 应用模块
-#### 简单模块
-#### 复杂模块
-#### 脚本模块
-### 插件模块
-#### 独立插件
-#### 扩展插件
-### 核心模块
-#### 模块中心ctx
-#### 命令中心cli
-#### 认证中心aaa
-#### 应用中心web
-#### 网络中心tcp
-#### 存储中心nfs
-#### 集群中心ssh
-#### 数据中心mdb
-
-## 系统架构
-
-| |数据流|命令流|权限流|应用流|
-|---|---|---|---|---|
-|应用层|ctx|cli|aaa|web|
-|控制层|lex|yac|log|gdb|
-|数据层|tcp|nfs|ssh|mdb|
-
-### 应用框架
-#### 模块
-
-context内部使用模块组织功能,每个模块都可以独立编译,独立运行。
-解除了代码之间的包依赖、库依赖、引用依赖、调用依赖。
-通过map查找模块,通过map查找命令,通过map查找配置,从而实现完全自由的模块。
-
-**模块定义:**
-```
-type Context struct { // src/contexts/ctx/ctx.go
- Name string
- Help string
-
- Caches map[string]*Cache
- Configs map[string]*Config
- Commands map[string]*Command
-
- ...
-
- contexts map[string]*Context
- context *Context
- root *Context
-
- ...
- Server
-}
-
-```
-Name:模块名称,Help:模块帮助。
-模糊搜索搜索时,会根据Name与Help进行匹配。
-
-每个模块会有命令集合Commands,配置集合Configs,缓存集合Caches。通过这种形式提供功能集合。
-
-contexts:所有子模块,context:指向父模块,root:指向根模块。
-从而组成一个模块树,所以可以通过路由查找模块,
-如ctx.web.code,code的父模块是web,web的父模块是ctx,ctx是根模块。
-所以可以通过命令,查看到当前程序所有模块的信息。
-
-**缓存定义:**
-```
-type Cache struct {
- Value string
- Name string
- Help string
- Hand func(m *Message, x *Cache, arg ...string) string
-}
-```
-Value:存放的数据,Name:变量名称,Help:变量帮助,Hand读写函数。
-
-缓存数量是一种数据接口,用来存放一些状态量,向外部显示程序进行状态,对外部来说一般是只读的。对内部来说可读可写。
-所以可以通过命令,查看到当前程序任意模块的状态数据。
-
-如下,ncontext当前有多少个模块。nserver有多少个模块运行了守护协程。
-
-```
-"nserver": &Cache{Name: "nserver", Value: "0", Help: "服务数量"},
-"ncontext": &Cache{Name: "ncontext", Value: "0", Help: "模块数量"},
-```
-
-**缓存读写:**
-```
-func (m *Message) Cap(key string, arg ...interface{}) string {}
-func (m *Message) Capi(key string, arg ...interface{}) int {}
-func (m *Message) Caps(key string, arg ...interface{}) bool {}
-```
-定义了缓存数据的三种读写接口。
-
-m.Cap()只有一个参数时,会从当前模块查询缓存变量,如果查到则返回Value,如果没有,则依次查询父模块。
-如果查找到根模块还没有查到找,变返回空字符串。
-
-m.Cap()有两个参数时,同样会从当前模块依次查询父模块,直到查到变量,然后设置其值。
-
-m.Capi()是对m.Cap()封装了一下,在int与str相互转换,从而实现用str存储int。
-所有转换失败的数据,都会返回0。
-
-m.Caps(),实现了str存储bool。返回false的值有"", "0", "false", "off", "no", "error: ",其它都返回true。
-
-**配置定义:**
-```
-type Config struct {
- Value interface{}
- Name string
- Help string
- Hand func(m *Message, x *Cache, arg ...string) string
-}
-```
-Value:存放的数据,Name:变量名称,Help:变量帮助,Hand读写函数。
-与Cache相似,只是Value的类型不再是String而是interface{},所以可以用来存放更复杂的数据。
-
-一般用来存放配置数据,是外部控制内部数据接口。
-所以可以通过命令,实时修改当前程序任意模块的配置数据。
-避免只是修改某个配置变量,就要重启整个进程,从而实现高效灵活的配置。
-把每个进程当成一个生命来对待,不要轻易杀死任何一个进程。有问题可以用微创手术解决。
-
-**配置读写:**
-```
-func (m *Message) Conf(key string, args ...interface{}) string {}
-func (m *Message) Confi(key string, arg ...interface{}) int {}
-func (m *Message) Confs(key string, arg ...interface{}) bool {}
-func (m *Message) Confx(key string, args ...interface{}) string {}
-func (m *Message) Confv(key string, args ...interface{}) interface{} {}
-func (m *Message) Confm(key string, args ...interface{}) map[string]interface{} {}
-```
-与Cache相似,也定义了各种读写的接口。
-
-因为interface{}可以是任意复合类型,所以数据嵌套很深时,查询会涉及各种类型转换,非常麻烦。
-Conf()定义了键值链。内部去处理类型转换与嵌套的深入。
-如m.Conf("runtime", "user.node")、m.Conf("runtime", []string{"user", "node"})、m.Conf("runtime", []interface{}{"user", "node"})
-都会查询配置runtime下的user下的node的值。
-
-m.Confx()内部进行选择,如果m.Option(key)中取到了值,则直接返回m.Option(key),否则返回m.Conf(key)。
-把配置当成一个备用的默认值,如果命令参数设置了此参数,则用命令中的参数。
-
-m.Confv()直接读写原始数据。
-m.Confm()则定义了更丰富的接口,m就是map意思,直接返回map[string]interface{}
-m另外一个意思就是magic,可以传入各种回调函数。
-如下配置node类型是map[string]interface{},m.Confm()会遍历此map,查到value也是map[string]interface{}的键值,调用回调函数。
-```
- ...
- m.Confm("node", func(name string, node map[string]interface{}) {
- if kit.Format(node["type"]) != "master" {
- ps = append(ps, kit.Format(node["module"]))
- }
- })
- ...
-```
-
-**命令定义:**
-```
-type Command struct {
- Form map[string]int
- Name string
- Help interface{}
- Auto func(m *Message, c *Context, key string, arg ...string) (ok bool)
- Hand func(m *Message, c *Context, key string, arg ...string) (e error)
-}
-```
-Name:命令语法,Help:命令帮助。
-
-Hand:命令处理函数,m是调用消息,c是当前模块,key是命令名,arg是命令参数。
-
-在命令解析时,会根据Form将[key value...]形式的参数,取出存放到m.Option中,方便用key直接查找参数。
-所以arg中只剩下序列参数,通过index序号查找参数。
-
-Auto:终端自动补全函数。在使用终端每输入一个单词时,就调用此函数输出提示信息。所以在命令执行前,这个函数会被调用多次。
-
-如下定义了trans命令
-```
- ...
- "trans": &Command{Name: "trans option [type|data|json] limit 10 [index...]", Help: "数据转换",
- Form: map[string]int{"format": 1, "fields": -1},
- Hand: func(m *Message, c *Context, key string, arg ...string) (e error) {
- ...
- }}
- ...
-```
-
-**命令调用:**
-```
-func (m *Message) Cmd(args ...interface{}) *Message {}
-func (m *Message) Cmdx(args ...interface{}) string {}
-func (m *Message) Cmds(args ...interface{}) bool {}
-func (m *Message) Cmdy(args ...interface{}) *Message {}
-func (m *Message) Cmdm(args ...interface{}) *Message {}
-```
-m.Cmd()根据第一个参数去当前查找命令,如果没有查找到,则去父模块查找。如果没有查找,则不会执行。
-剩下的参数会根据Form定义来解析,存放到m.Option中。
-
-m.Cmds()当返回值转换成bool规则同m.Caps()与m.Confs()。
-m.Cmdx()当返回值转换成str。 m.Cmdy()将结果复制到当前Message。
-
-m.Cmdm(),m同样是magic,会根据当前会话,自动定向到远程某主机某模块,远程调用其命令,当然也可能定向到本机。
-
-#### 协程
-#### 消息
-
-context内部调用都是
-
-
-### 解析引擎
-#### 文件扫描
-#### 词法解析
-#### 语法解析
-#### 执行命令
-### 通信框架
-#### 节点路由
-每个节点在启动时,自动向上级注册,生成一个动态域名,作为本节点的地址。
-如com.mac.led,led的上级节点是mac,mac的上级节点是com。
-其它节点,就可以通过个这个地址查找到此节点。
-
-在调用远程命令时,通信模块根据远程地址的第一个字段,查找子节点,查取成功后,会将剩余的地址与命令发送给查到的子节点。
-子节点收到地址与命令后,继续查找子节点,直到目标节点收到命令,然后将执行结果原路返回。
-
-在查找的过程中,如果没有查找到子节点,则会传给上级节点重新处理。
-
-#### 节点认证
-
-**节点加密**
-每个节点都有证书与密钥。每个节点在发送命令时,都会用自己的密钥签名,目标节点都会用它的证书验签。以此保证命令来源的可靠性。
-
-**节点类型**
-
-- 初始节点,没有归属的节点
-- 主控节点,有用户证书与密钥的节点
-- 从属节点,有用户证书的节点
-
-- 代理节点,主控节点指定的代理节点
-- 共享节点,允许多个用户控制的节点
-- 认证节点,专门用来存放与查询用户证书的节点
-
-用户在某一设备上添加自己的证书与密钥,此节点即为主控节点。 在其它节点上绑定自己的证书,此即为从属节点。
-
-主控节点就可任意控制从属节点,从属节点不能控制主控节点,从属节点之间也不能相互控制。
-
-主控节点可以指定代理节点,代理节点可以代替主控节点控制从属节点。
-
-共享节点,会有多个用户,可能产生冲突,所以需要认证节点协调。
-
-访问共享节点前,需要向认证节点注册,共享节点会从认证节点取出访问用户的信息。
-
-#### 节点权限
-
-***角色***
-
-每个访问用户,都会指定一个角色。
-主控节点的用户默认有root权限。即拥有设备的所有控制权限。
-
-认证节点的用户默认有tech权限。一般是部分功能。
-
-其它节点的用户默认有void权限。即拥有最小集合的权限,一般是只读的命令。
-
-***组件***
-
-组件是功能的集合,远程访问至少要有remote与source组件的权限才可以执行命令。
-
-每个角色下都会有多个组件的权限。
-
-***命令***
-
-命令就节点向外提供功能的最小单元。
-
-每个组件下都会有多条命令。
-
-***规则***
-
-每条命令内部可以用组件与命令的权限机制自定义权限检查。
-
-权限的分配完全由主控节点与从属节点自己配置,其它节点不许配置。
-
-***示例***
-
-如下配置,用户shy的角色是tech,角色tech下有两个组件remote与source,每个组件下都有命令pwd与dir,所以用户shy就可以远程调用命令dir与pwd
-```
-role tech user shy
-role tech componet remote command pwd dir
-role tech componet source command pwd dir
-```
-
-### 存储引擎
-#### 配置
-#### 缓存
-#### 数据
-
diff --git a/README.md b/README.md
new file mode 120000
index 00000000..b528deb8
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+usr/local/wiki/自然/编程/index.md
\ No newline at end of file
diff --git a/src/contexts/cli/version.go b/src/contexts/cli/version.go
index ee8b16d3..463466c8 100644
--- a/src/contexts/cli/version.go
+++ b/src/contexts/cli/version.go
@@ -4,5 +4,5 @@ var version = struct {
host string
self int
}{
- "2019-09-12 14:33:20", "centos", 524,
+ "2019-09-12 16:21:30", "centos", 529,
}
diff --git a/src/contexts/nfs/nfs.go b/src/contexts/nfs/nfs.go
index d1c92086..d90d344b 100644
--- a/src/contexts/nfs/nfs.go
+++ b/src/contexts/nfs/nfs.go
@@ -47,10 +47,11 @@ func dir(m *ctx.Message, root string, name string, level int, deep bool, dir_typ
}
p := path.Join(name, f.Name())
- f, e := os.Stat(p)
- if e != nil {
+ if f, e = os.Lstat(p); e != nil {
m.Log("info", "%s", e)
continue
+ } else if (f.Mode() & os.ModeSymlink) != 0 {
+ continue
}
if !(dir_type == "file" && f.IsDir() || dir_type == "dir" && !f.IsDir()) && (dir_reg == nil || dir_reg.MatchString(f.Name())) {
diff --git a/src/contexts/ssh/ssh.go b/src/contexts/ssh/ssh.go
index 0257059d..008ea18e 100644
--- a/src/contexts/ssh/ssh.go
+++ b/src/contexts/ssh/ssh.go
@@ -83,47 +83,47 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
Configs: map[string]*ctx.Config{
"componet": {Name: "componet", Value: map[string]interface{}{
"index": []interface{}{
- map[string]interface{}{"componet_name": "ifconfig", "componet_help": "ifconfig",
- "componet_tmpl": "componet", "componet_view": "", "componet_init": "",
- "componet_type": "private", "componet_ctx": "ssh", "componet_cmd": "_route",
- "componet_args": []interface{}{"_", "tcp.ifconfig"}, "inputs": []interface{}{
+ map[string]interface{}{"name": "ifconfig", "help": "ifconfig",
+ "tmpl": "componet", "view": "", "init": "",
+ "type": "private", "ctx": "ssh", "cmd": "_route",
+ "args": []interface{}{"_", "tcp.ifconfig"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "value": "", "imports": "plugin_pod"},
map[string]interface{}{"type": "button", "value": "查看"},
},
},
- map[string]interface{}{"componet_name": "proc", "componet_help": "proc",
- "componet_tmpl": "componet", "componet_view": "", "componet_init": "",
- "componet_type": "private", "componet_ctx": "ssh", "componet_cmd": "_route",
- "componet_args": []interface{}{"_", "cli.proc"}, "inputs": []interface{}{
+ map[string]interface{}{"name": "proc", "help": "proc",
+ "tmpl": "componet", "view": "", "init": "",
+ "type": "private", "ctx": "ssh", "cmd": "_route",
+ "args": []interface{}{"_", "cli.proc"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "value": "", "imports": "plugin_pod"},
map[string]interface{}{"type": "text", "name": "arg", "value": ""},
map[string]interface{}{"type": "text", "name": "filter", "view": "long"},
map[string]interface{}{"type": "button", "value": "执行"},
},
},
- map[string]interface{}{"componet_name": "spide", "componet_help": "爬虫",
- "componet_tmpl": "componet", "componet_view": "Context", "componet_init": "",
- "componet_type": "private", "componet_ctx": "ssh", "componet_cmd": "_route",
- "componet_args": []interface{}{"_", "context", "web", "spide"}, "inputs": []interface{}{
+ map[string]interface{}{"name": "spide", "help": "爬虫",
+ "tmpl": "componet", "view": "Context", "init": "",
+ "type": "private", "ctx": "ssh", "cmd": "_route",
+ "args": []interface{}{"_", "context", "web", "spide"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "imports": "plugin_pod"},
map[string]interface{}{"type": "button", "value": "执行"},
},
"exports": []interface{}{"site", "key"},
},
- map[string]interface{}{"componet_name": "post", "componet_help": "请求",
- "componet_tmpl": "componet", "componet_view": "Context", "componet_init": "",
- "componet_type": "private", "componet_ctx": "ssh", "componet_cmd": "_route",
- "componet_args": []interface{}{"_", "web.post", "__", "content_type", "application/json", "parse", "json"}, "inputs": []interface{}{
+ map[string]interface{}{"name": "post", "help": "请求",
+ "tmpl": "componet", "view": "Context", "init": "",
+ "type": "private", "ctx": "ssh", "cmd": "_route",
+ "args": []interface{}{"_", "web.post", "__", "content_type", "application/json", "parse", "json"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "imports": "plugin_pod"},
map[string]interface{}{"type": "text", "name": "spide", "value": "dev", "imports": "plugin_site"},
map[string]interface{}{"type": "text", "name": "url", "value": "/", "view": "long"},
map[string]interface{}{"type": "button", "value": "执行"},
},
},
- map[string]interface{}{"componet_name": "get", "componet_help": "请求",
- "componet_tmpl": "componet", "componet_view": "Context", "componet_init": "",
- "componet_type": "private", "componet_ctx": "ssh", "componet_cmd": "_route",
- "componet_args": []interface{}{"_", "web.get", "__", "method", "GET", "parse", "json"}, "inputs": []interface{}{
+ map[string]interface{}{"name": "get", "help": "请求",
+ "tmpl": "componet", "view": "Context", "init": "",
+ "type": "private", "ctx": "ssh", "cmd": "_route",
+ "args": []interface{}{"_", "web.get", "__", "method", "GET", "parse", "json"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "pod", "imports": "plugin_pod"},
map[string]interface{}{"type": "text", "name": "spide", "value": "dev", "imports": "plugin_site"},
map[string]interface{}{"type": "text", "name": "url", "value": "/", "view": "long"},
@@ -303,14 +303,14 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
"tool": {Name: "tool [group index][run group index chatid arg...]", Help: "工具", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
if len(arg) == 0 {
m.Confm("componet", func(key string, index int, value map[string]interface{}) {
- if kit.Format(value["componet_type"]) != "public" && m.Option("userrole") != "root" {
+ if kit.Format(value["type"]) != "public" && m.Option("userrole") != "root" {
return
}
m.Push("key", key)
m.Push("index", index)
- m.Push("name", value["componet_name"])
- m.Push("help", value["componet_help"])
+ m.Push("name", value["name"])
+ m.Push("help", value["help"])
})
m.Table()
return
@@ -321,7 +321,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
m.Option("plugin", arg[1])
tool := m.Confm("componet", []string{arg[1], arg[2]})
if m.Option("userrole") != "root" {
- switch kit.Format(tool["componet_type"]) {
+ switch kit.Format(tool["type"]) {
case "private":
m.Echo("private componet of %s", m.Conf("runtime", "work.name"))
return
@@ -333,7 +333,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
}
}
- msg := m.Find(kit.Format(tool["componet_ctx"]))
+ msg := m.Find(kit.Format(tool["ctx"]))
if option, ok := tool["options"].(map[string]interface{}); ok {
for k, v := range option {
msg.Option(k, v)
@@ -345,7 +345,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
arg = arg[4:]
args := []string{}
- for _, v := range kit.Trans(tool["componet_args"]) {
+ for _, v := range kit.Trans(tool["args"]) {
if strings.HasPrefix(v, "__") {
if len(arg) > 0 {
args, arg = append(args, arg...), nil
@@ -361,31 +361,31 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
}
}
msg.Log("time", "check: %v", m.Format("cost"))
- if msg.Cmd(tool["componet_cmd"], args, arg).CopyTo(m); !msg.Hand {
- msg.Log("warn", "not found %v:%v", tool["componet_ctx"], tool["componet_cmd"])
+ if msg.Cmd(tool["cmd"], args, arg).CopyTo(m); !msg.Hand {
+ msg.Log("warn", "not found %v:%v", tool["ctx"], tool["cmd"])
}
default:
m.Confm("componet", arg[0:], func(value map[string]interface{}) {
- if kit.Format(value["componet_type"]) == "private" && m.Option("userrole") != "root" {
+ if kit.Format(value["type"]) == "private" && m.Option("userrole") != "root" {
return
}
- m.Push("name", value["componet_name"])
- m.Push("help", value["componet_help"])
- if kit.Right(value["componet_init"]) {
- script := m.Cmdx("nfs.load", path.Join(m.Conf("cli.project", "plugin.path"), arg[0], kit.Format(value["componet_init"])), -1)
+ m.Push("name", value["name"])
+ m.Push("help", value["help"])
+ if kit.Right(value["init"]) {
+ script := m.Cmdx("nfs.load", path.Join(m.Conf("cli.project", "plugin.path"), arg[0], kit.Format(value["init"])), -1)
if script == "" {
- script = m.Cmdx("nfs.load", path.Join("usr/librarys/plugin", kit.Format(value["componet_init"])), -1)
+ script = m.Cmdx("nfs.load", path.Join("usr/librarys/plugin", kit.Format(value["init"])), -1)
}
m.Push("init", script)
} else {
m.Push("init", "")
}
- if kit.Right(value["componet_view"]) {
- script := m.Cmdx("nfs.load", path.Join(m.Conf("cli.project", "plugin.path"), arg[0], kit.Format(value["componet_view"])), -1)
+ if kit.Right(value["view"]) {
+ script := m.Cmdx("nfs.load", path.Join(m.Conf("cli.project", "plugin.path"), arg[0], kit.Format(value["view"])), -1)
if script == "" {
- script = m.Cmdx("nfs.load", path.Join("usr/librarys/plugin", kit.Format(value["componet_view"])), -1)
+ script = m.Cmdx("nfs.load", path.Join("usr/librarys/plugin", kit.Format(value["view"])), -1)
}
m.Push("view", script)
} else {
diff --git a/src/contexts/yac/yac.go b/src/contexts/yac/yac.go
index 81aa5f8a..c76f4862 100644
--- a/src/contexts/yac/yac.go
+++ b/src/contexts/yac/yac.go
@@ -1168,15 +1168,15 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
}
m.Confv("_index", []interface{}{-2}, map[string]interface{}{
- "componet_name": kit.Select("", arg, 1),
- "componet_help": kit.Select("", arg, 2),
- "componet_view": view,
- "componet_init": init,
- "componet_type": right,
+ "name": kit.Select("", arg, 1),
+ "help": kit.Select("", arg, 2),
+ "view": view,
+ "init": init,
+ "type": right,
- "componet_ctx": m.Cap("module"),
- "componet_cmd": cmd,
- "componet_args": args,
+ "ctx": m.Cap("module"),
+ "cmd": cmd,
+ "args": args,
"inputs": inputs,
"exports": exports,
"feature": feature,
diff --git a/src/plugin/mind/index.js b/src/plugin/mind/index.js
index 55d1bd80..7671289d 100644
--- a/src/plugin/mind/index.js
+++ b/src/plugin/mind/index.js
@@ -1,6 +1,6 @@
{init: function(run, field, option, output) {return {
ondaemon: {
- table: function(msg, cb) {if (msg.event.type == "blur") {return}
+ table: function(msg, cb) {if (msg.event && msg.event.type == "blur") {return}
var plugin = field.Plugin
output.innerHTML = "", msg.append && kit.OrderTable(kit.AppendTable(kit.AppendChild(output, "table"), ctx.Table(msg), msg.append), "", function(event, value, name, line, index) {
if (name == "id") {
diff --git a/usr/librarys/example.css b/usr/librarys/example.css
index 2a060ae1..fd3fdbdf 100644
--- a/usr/librarys/example.css
+++ b/usr/librarys/example.css
@@ -28,7 +28,7 @@ legend {
}
fieldset>form.option div {
- margin-right:6px;
+ margin-right:3px;
float:left;
}
fieldset>form.option div.hide {
@@ -38,7 +38,7 @@ fieldset>form.option div.clear {
clear:both;
}
fieldset>form.option label {
- margin-right:6px;
+ margin-right:3px;
}
fieldset>form.option div input.args {
width:80px;
diff --git a/usr/librarys/example.js b/usr/librarys/example.js
index caa932f2..2b960a9b 100644
--- a/usr/librarys/example.js
+++ b/usr/librarys/example.js
@@ -711,10 +711,7 @@ function Plugin(page, pane, field, runs) {
item[k] == undefined && (item[k] = typeof cb == "function"? function(event) {
cb(event, action, item.type, name, item)
}: cb)
- })
-
- var count = kit.Selector(option, ".args").length
- args && count < args.length && (item.value = value||args[count++]||item.value||"");
+ });
(item.title || item.name) && (item.title = item.title || item.name)
item.title && (item.placeholder = item.title)
@@ -736,10 +733,13 @@ function Plugin(page, pane, field, runs) {
case "text":
item.className = "args"
item.autocomplete = "off"
+
+ var count = kit.Selector(option, ".args").length
+ args && count < args.length && (item.value = value||args[count++]||item.value||"");
break
}
- var ui = kit.AppendChild(option, [{view: [item.view||""], data: {title: item.title}, list: [{type: "label", inner: item.label||""}, input]}])
+ var ui = kit.AppendChild(option, [{view: [item.view||""], list: [{type: "label", inner: item.label||""}, input]}])
var action = Meta(ui[name] || {}, item, plugin.onaction, plugin);
(typeof item.imports == "object"? item.imports: typeof item.imports == "string"? [item.imports]: []).forEach(function(imports) {
@@ -993,7 +993,7 @@ function Plugin(page, pane, field, runs) {
page.action.scrollTo(0, field.offsetTop)
break
case "b":
- plugin.Append({className: "args temp"}).focus()
+ plugin.Append({className: "args temp", type: "text"}).focus()
break
case "m":
plugin.Clone().Select()
@@ -1012,6 +1012,6 @@ function Plugin(page, pane, field, runs) {
exports: JSON.parse(meta.exports||'["",""]'),
})
- inputs.map(plugin.Append)
+ inputs.map(function(item) {plugin.Append(item)})
return page[field.id] = pane[field.id] = pane[name] = field, field.Plugin = plugin
}
diff --git a/usr/librarys/toolkit.js b/usr/librarys/toolkit.js
index c5e31459..7073cad3 100644
--- a/usr/librarys/toolkit.js
+++ b/usr/librarys/toolkit.js
@@ -268,7 +268,7 @@ kit = toolkit = {
}
} else if (child.view) {
- child.data["className"] = child.view[0]
+ (child.view.length > 0 && child.view[0]) && (child.data["className"] = child.view[0])
child.type = child.view.length > 1? child.view[1]: "div"
child.view.length > 2 && (child.data["innerHTML"] = child.view[2])
child.view.length > 3 && (child.name = child.view[3])
diff --git a/usr/local/wiki/自然/编程/index.md b/usr/local/wiki/自然/编程/index.md
deleted file mode 120000
index 53e75d4d..00000000
--- a/usr/local/wiki/自然/编程/index.md
+++ /dev/null
@@ -1 +0,0 @@
-终端工具链/context.md
\ No newline at end of file
diff --git a/usr/local/wiki/自然/编程/index.md b/usr/local/wiki/自然/编程/index.md
new file mode 100644
index 00000000..fbb3de4d
--- /dev/null
+++ b/usr/local/wiki/自然/编程/index.md
@@ -0,0 +1,1066 @@
+## context
+
+context是一种新的编程语言与应用框架,通过模块化、集群化、自动化,实现软件的快速开发,快速共享,快速使用。
+
+context是以群聊的形式,进行资源的共享。
+用户可以创建任意的群聊,把相关人员聚集在一起,每个人可以将自己的设备,共享到群聊中,供组员使用,从而实现资源的最大利用。
+每个设备上有一堆命令,用户可以将任意设备上任意命令,添加到自定义的应用界面中,按照自己的需求去组合,从面实现场景化与个性化的定制。
+所以每个群聊中会有各种各样自定义的应用,所有的命令都是以群聊作为场景,进行权限的检查与分配。
+这些应用,可以像文本与图片一样,在群聊里自由的流动,可以被更快分享出去,再次收藏与组合形成新的应用组件,还可以在聊天记录中直接使用。
+
+context是以分布式的方式,进行程序的开发。
+开发者,可以用脚本语言开发应用,随时随地的在自己任意设备上加载脚本,然后将动态域名分享出去,应用就可以被用户在群聊中任意的传播。
+所有的代码与数据,都在自己设备上,可以进行任意的实时控制。
+消灭所有中间环节,让几行代码的小函数,就可以成为独立的应用,从而实现软件的快速开发与快速传播,将任意一行代码的价值,放大成千上万倍。
+
+## 下载安装
+在Linux或Mac上,可以直接用脚本下载,
+在Windows上,可以先安装 [GitBash](https://www.git-scm.com/download/),然后在GitBash中执行命令下载。
+```
+$ curl https://shylinux.com/publish/boot.sh | bash -s install context
+```
+
+install后面的参数context,就是指定的下载目录,
+进入下载目录,可以看到的有八个文件。
+
+在bin目录下,就是各种执行文件
+
+- bin/bench,context的执行程序
+- bin/boot.sh,context的启动脚本
+- bin/zone.sh,启动区域节点
+- bin/user.sh,启动用户节点
+- bin/node.sh,启动工作节点
+
+context内部实现了语法解析,通过自定义的脚本语言,实现功能的灵活控制。
+
+在etc目录下,就是context执行过程中用到的脚本。
+
+- etc/init.shy,启动时加载的脚本
+- etc/exit.shy,结束时运行的脚本
+- etc/common.shy,init.shy调用到的脚本
+
+## 创建集群
+context是一种分布式框架,可以运行在任意设备上,并且实现了自动组网、自动路由、自动认证。
+远程命令与本地命令,无差别的运行,从而实现无限扩容的分布式计算。
+
+context每个启动的进程都是一个独立的节点,根据网络框架中的功能作用,可以分为区域节点、用户节点、工作节点、分机节点。
+这几种节点,除了网络框架中的作用外,其它的功能模块与命令都完全一样,没有差别。
+
+个人使用,可以创建一个区域节点,下挂多个工作节点。
+
+团队使用,需要创建一个区域节点,多个用户节点,每个用户节点下,可以挂多个工作节点。
+
+如果用户节点或工作节点过多,可以创建分机节点,通过增加层级来降低单机负载。
+
+### 个人使用
+#### 启动区域节点
+打开终端,进入context目录,执行如下命令,
+```
+$ bin/zone.sh
+0[13:26:27]nfs>
+```
+
+#### 启动工作节点
+再打开终端,进入context目录,执行如下命令,
+```
+$ bin/node.sh create app/hello
+
+0[13:26:27]nfs> remote
+create_time pod type
+2019-07-30 13:26:27 com master
+```
+启动context后,调用remote命令,可以查看到有一个上级节点。
+
+#### 启动工作节点
+再打开终端,进入context目录,执行如下命令,
+```
+$ bin/node.sh create app/world
+
+0[13:26:27]nfs> remote
+create_time pod type
+2019-07-30 13:26:27 com master
+```
+
+#### 分布式命令
+启动两种节点节点后,就可以在任意节点上调用命令,也可以调用远程节点的命令。
+如在区域节点上调用remote,就可以看到两个工作节点。
+```
+4[13:27:26]nfs> remote
+create_time pod type
+2019-07-30 13:26:27 hello worker
+2019-07-30 13:26:30 world worker
+```
+
+查看当前路径
+```
+3[13:39:29]nfs> pwd
+D:\context/var
+4[13:40:03]nfs>
+```
+
+查看当时目录
+```
+4[13:40:03]nfs> dir
+time size line path
+2019-07-23 21:36:36 387 4 var/hi.png
+2019-07-27 13:41:56 4096 4 var/log/
+2019-06-15 10:58:03 0 1 var/run/
+2019-07-30 12:55:19 4096 8 var/tmp/
+5[13:40:20]nfs>
+```
+
+执行远程命令,只需要在命令前加上节点名与冒号。
+```
+6[13:41:28]nfs> hello:pwd
+D:\context\hello/var
+6[13:41:28]nfs> world:pwd
+D:\context\world/var
+```
+
+在任意随机节点上执行命令,用百分号作节点名。
+```
+5[13:40:20]nfs> %:pwd
+D:\context\hello/var
+5[13:40:20]nfs> %:pwd
+D:\context\world/var
+```
+
+在所有节点上执行命令,用星号作节点名。
+```
+7[13:41:36]nfs> *:pwd
+D:\context\hello/var D:\context\hello/var
+```
+
+## 团队使用
+context也可以支持团队协作使用,这时候就需要将区域节点部署到公共主机上。
+区域节点的作用就是生成动态域名,分发路由,解决命名冲突,与权限分配等功能。
+
+### 启动用户节点
+在公共主机上启动区域节点后,每个组员就可以在自己主机上启动用户节点,但需要指定区域节点的地址。
+如下命令,ip换成自己的公共主机,9095端口保留,这是context默认的web端口。
+```
+$ ctx_dev=http://192.168.88.102:9095 bin/user.sh
+```
+
+### 启动工作节点
+同样每个用户都可以启动多用工作节点。
+```
+$ bin/node.sh create world
+```
+
+### 启动团队协作
+当有多个用户连接到公共节点后,用户与用户之间就可以相互访问对方的所有节点。
+但是默认启用了节点认证,所有命令都没有权限。所以调用对应节点上的命令,需要对方开启命令权限。
+
+每个用户随时都可以在自己节点上,为其它用户设置任意角色,给每个角色分配任意命令。
+从而实现安全快速的资源共享。
+
+
+## 启动分机节点
+当区域的用户节点过多,就可以启动分机节点。
+启动分机节点,只需要指定上级节点即可。
+用户在连接公共节点时,指定这个新节点的ip即可。
+context会自动生成新的网络路由。
+
+```
+$ ctx_dev=http://192.168.88.102:9095 bin/boot.sh
+```
+
+## 创建群聊
+除了命令行的使用的方式之外,context还有自己的前端框架。
+不仅降低了使用难度,还提供更加场景化、自动化的应用界面。
+
+用户可以访问区域节点或是任意用户节点的网页服务。
+
+http://127.0.0.29:9095
+
+输入用户名与初始密码,即可登录,如果用户与主机上的用户名相同,则是管理员权限,如果不同,则是普通用户,只有最小的功能权限。
+
+所以任意节点都支持多用户共享使用,但只有管理用户有所有权限,进行资源的管理与分配。
+
+打开应用界面,就可以看到context以办公聊天软件的形式提供各种丰富的功能。
+
+左边框是用户群组列表,用户可以选择群聊或是创建新的群聊。
+中间就是聊天记录与输入框,用户可以自由的聊天收发消息。
+
+与其它聊天软件不同的是,context提供了自定义的功能列表。
+右边框中,就是此群组的功能列表。
+每个用户都可以将自己设备上的命令添加到这个群组的功能列表中,分享给本组员使用。
+每个组员都可以根据自己的需求组合这些命令,生成自己的应用界面。
+
+以每个群聊作为场景,进行资源的共享与应用的开发,从而实现更加场景化与个性化应用。
+
+通过这种精细化的应用场景,进行工具化、标准化、流程化。提高各行各业的工作效率。
+
+## 应用开发
+
+网络框架与应用界面,已经实现了标准化与自动化,剩下就是应用的开发了。
+
+开发者,可以在任意机器上开发自己的应用。以模块与函数为单位进行开发与上线。
+一个函数,即使只有几行代码,也是一个独立完整的应用,可以随时上线,被任意用户使用。
+
+用户还可以在任意群聊中转发此应用,更自由的传播出去。
+从而将软件开发的速度提升成千上万倍,将代码的使用效率提升成千上万倍。
+
+### 创建项目
+在任意节点上,执行project命令,指定项目名,即可创建应用目录。
+```
+$ bin/user.sh
+8[13:41:41]nfs> project hello
+time line hash path
+2019-07-30 14:27:09 35 eba8eda2 src/plugin/hello/index.go
+2019-07-30 14:27:09 1 b858cb28 src/plugin/hello/index.shy
+2019-07-30 14:27:09 1 b858cb28 src/plugin/hello/local.shy
+2019-07-30 14:27:09 4 407265b6 src/plugin/hello/index.js
+9[14:27:09]nfs>
+```
+每个项目,都可以用go语言开发低层应用,用js开发前端交互。
+除此,context有自己的通用语法解析器,开者完全可以随时自定义语法,定制自己的解析器。
+用自己喜欢的语法开发应用。
+
+默认的shy语法,提供了一个完整的前后端应用框架。创建项目时,自动创建的模块如下。
+```
+fun hello world "" "" \
+ public \
+ text "" \
+ button "执行"
+ copy pwd
+end
+```
+
+这个模板就是一个完整的应用,fun关键字开关,end关键字结束。
+前四行就是定义应用界面,剩下代码就是后端脚本。
+public代表,这个应用是公共的,所以有人都可以访问。也可以是private,只有管理用户可以访问。
+
+text与button,就是需要前端展示的控件。用户在前端点击此button,就会将请求发送到后端,执行此脚本。
+然后将执行结果返回给前端界面。
+
+### 加载项目
+切换到cli模块,使用upgrade命令,加载新的项目应用。
+```
+8[13:41:41]nfs> ~cli
+8[13:41:41]cli> upgrade plugin hello
+3[15:55:53]cli> ~
+names ctx msg status stream helps
+ctx 0 start stdio 模块中心
+cli ctx 4 begin 管理中心
+hello cli 5958 start shy
+4[15:57:00]cli>
+```
+
+切换到hello模块,使用command命令,可以查看到hello模块下的命令列表,然后就可以调用hello命令。
+```
+8[13:41:41]cli> ~hello
+6[15:58:42]hello> command
+key name
+hello hello world public text button 执行
+7[20:27:32]nice> hello
+D:\context/var
+```
+
+同时在前端界面上添加功能,即可看到此函数。
+
+context内部实现了很多功能模块,每个模块下有很多命令,每条命令就是一种应用。
+
+context的使用方式有很多种,
+
+- 可以直接调用,像Shell一样,去解析一条命令
+- 可以启动cli服务,像MySQL一样,交互式使用格式化命令
+- 可以启动web服务,像LabView一样,可以自定义各种图形界面
+- 可以自动组网,将任意台设备组合在一起,实现分布式应用
+- 可以自动建群,在群聊场景中,实现多用户、多会话、多任务、多设备的使用
+
+### 命令模式
+如果只是使用一条命令,或是写在脚本文件中,可以使用这种方式。
+
+例如,dir命令就是查看目录,
+```
+$ bin/bench dir
+time size line filename
+2019-06-16 10:35:18 324 11 common.shy
+2019-06-16 10:35:18 201 9 exit.shy
+2019-06-16 10:35:18 261 13 init.shy
+```
+
+还可以加更多参数,dir_deep递归查询目录,dir_type文件类型过滤,dir_sort输出表排序。
+```
+$ bin/bench dir ../ dir_deep dir_type file dir_sort line int_r
+time size line filename
+2019-06-16 10:22:52 13256968 91314 bench
+2019-06-16 11:10:16 1535 66 boot.sh
+2019-06-16 11:10:16 613 31 node.sh
+2019-06-16 11:10:16 261 13 init.shy
+2019-06-16 11:10:16 324 11 common.shy
+2019-06-16 11:10:16 201 9 exit.shy
+
+```
+
+### 交互模式
+
+启动服务,可以提供更丰富的命令与环境。
+```
+$ bin/bench
+0[11:35:46]ssh> dir
+time size line filename
+2019-06-16 11:35:06 160 3 log/
+2019-06-16 11:35:06 96 1 run/
+2019-06-16 11:35:44 192 4 tmp/
+1[11:35:46]ssh>
+```
+
+如果集中管理,命令越多,系统只会越复杂,学习成本越高,使用越低效,开发越困难。
+
+所以通过模块化,分而治之,更高效的管理丰富的命令。
+
+context命令就是用来管理模块,没有参数时,直接查看当前模块的信息。
+
+如下,第二行是当前模块,第一行是当前模块的父模块,其它行都是当前模块的子模块。
+
+```
+1[11:39:01]ssh> context
+names ctx msg status stream helps
+ctx 0 start shy 模块中心
+ssh ctx 10 begin ctx.nfs.file3 集群中心
+```
+
+context第一个参数,可以指定当前模块,
+如下,切换到nfs模块,然后查看各种IO模块,
+切换到ctx根模块,查看所有模块。
+```
+2[11:43:57]ssh> context nfs
+
+3[11:43:58]nfs> context
+names ctx msg status stream helps
+ctx 0 start shy 模块中心
+nfs ctx 9 begin 存储中心
+stdio nfs 1174 start stdio scan stdio
+
+4[11:44:22]ssh> context ctx
+
+5[11:45:17]ctx> context
+names ctx msg status stream helps
+ctx 0 start shy 模块中心
+aaa ctx 3 begin 认证中心
+cli ctx 4 begin 管理中心
+gdb ctx 232 start 调试中心
+lex ctx 6 begin 词法中心
+log ctx 31 start bench 日志中心
+mdb ctx 8 begin 数据中心
+nfs ctx 9 begin 存储中心
+ssh ctx 10 begin 集群中心
+tcp ctx 11 begin 网络中心
+web ctx 1094 start :9094 应用中心
+yac ctx 13 begin 35,14,23 语法中心
+shy cli 1171 start engine shell
+matrix1 lex 34 start 76,28,2 matrix
+stdio nfs 1174 start stdio scan stdio
+chat web 14 begin 会议中心
+code web 15 begin 代码中心
+wiki web 16 begin 文档中心
+engine yac 1173 start stdio parse
+
+```
+
+command命令,就是用来管理当前模块的命令,
+```
+17[11:52:02]nfs> context nfs
+
+17[11:52:02]nfs> command
+key name
+_init _init
+action action cmd
+copy copy to from
+dir dir [path [fields...]]
+export export filename
+git git sum
+hash hash filename
+import import filename [index]
+json json str
+load load file [buf_size [pos]]
+open open file
+path path filename
+printf printf arg
+prompt prompt arg
+pwd pwd [all] | [[index] path]
+read read [buf_size [pos]]
+remote remote listen|dial args...
+save save file string...
+scan scan file name
+send send [file] args...
+temp temp data
+term term action args...
+trash trash file
+write write string [pos]
+
+```
+
+help子命令,查看命令帮助信息。
+```
+18[11:59:19]nfs> command help dir
+dir: dir [path [fields...]]
+ 查看目录, path: 路径, fields...: 查询字段, time|type|full|path|tree|filename|size|line|hash
+ dir_deep: 递归查询
+ dir_type both|file|dir|all: 文件类型
+ dir_reg reg: 正则表达式
+ dir_sort field order: 排序
+```
+
+
+### 集群模式
+
+context提供自动化集群的功能,可以自动组网、自动认证。从而快速实现多台设备的协同工作。
+
+#### 启动服务节点
+```
+$ bin/boot.sh
+0[11:35:12]ssh>
+```
+
+#### 启动工作节点
+
+新打开一个终端,启动工作节点,执行remote命令,查看上级节点,
+```
+$ bin/boot.sh create app/demo
+0[15:15:30]ssh> remote
+key type module create_time
+mac master ctx.nfs.file3 2019-06-16 15:15:23
+```
+
+回到服务节点终端,执行remote命令,可以查看到所有远程节点。
+```
+2[15:15:31]ssh> remote
+key type module create_time
+com master ctx.nfs.file4 2019-06-16 14:25:10
+demo worker ctx.nfs.file7 2019-06-16 15:15:23
+```
+
+默认配置中,子节点信任父,所以父节点可以调用子节点的命令。还有更复杂的认证机制,可以灵活配置。
+
+远程命令和本地命令一样,没有任何区别。如下调用demo节点的pwd命令。还支持更复杂的多节点命令,可以更快速的同时管理多台设备。
+```
+2[15:15:31]ssh> remote demo pwd
+/Users/shaoying/context/app/demo/var
+```
+
+#### 启动分机节点
+
+在服务节点的终端,查看服务地址
+```
+3[15:49:00]ssh> web.brow
+index site
+0 http://192.168.199.139:9094
+```
+
+同样,在另一台设备上下载context,然后启动服务节点。
+通过环境变量ctx_dev指定上级节点。
+```
+$ ctx_dev="http://192.168.199.139:9094" bin/boot.sh
+0[15:49:00]ssh> remote
+key type module create_time
+mac master ctx.nfs.file3 2019-06-16 15:15:23
+```
+
+回到服务节点终端,执行remote命令,可以查看到新添加了一个服务子节点。
+```
+2[15:15:31]ssh> remote
+key type module create_time
+com master ctx.nfs.file4 2019-06-16 14:25:10
+demo worker ctx.nfs.file7 2019-06-16 15:15:23
+sub server ctx.nfs.file8 2019-06-16 16:15:23
+```
+
+同样可以远程调用命令。
+```
+2[15:15:31]ssh> remote sub pwd
+/Users/shaoying/context/app/sub/var
+```
+
+#### 文件管理
+调用本地命令,查看当前目录下的文件列表,
+```
+0[10:53:25]ssh> ls
+total 0
+drwxr-xr-x 5 shaoying staff 160 May 10 03:57 bin
+drwxr-xr-x 5 shaoying staff 160 May 10 03:30 etc
+drwxr-xr-x 2 shaoying staff 64 May 10 03:30 usr
+drwxr-xr-x 8 shaoying staff 256 May 10 03:36 var
+```
+
+调用内部命令,查看文件列表,如下dir与ls命令用途相似,但提供了更丰富的功能,如统计文件行数
+```
+5[10:56:24]ssh> dir etc
+time size line filename
+2019-04-14 21:29:21 316 10 common.shy
+2019-04-29 21:12:28 130 7 exit.shy
+2019-04-29 21:12:12 191 12 init.shy
+```
+
+"%"是一个内部命令,可以对前一步命令结果进行各种处理。如下按字段line排序
+```
+5[10:56:24]ssh> dir etc % order line
+time size line filename
+2019-04-29 21:12:12 191 12 init.shy
+2019-04-14 21:29:21 316 10 common.shy
+2019-04-29 21:12:28 130 7 exit.shy
+```
+
+如下按字段""聚合,即可得到汇总结果,所有文件的总字节数、总行数、总文件数
+```
+16[11:04:30]ssh> dir etc % group ""
+time size line filename count
+2019-04-14 21:29:21 637 29 common.shy 3
+```
+
+#### 时间管理
+查看当前时间戳
+```
+18[11:11:01]ssh> time
+1557457862000
+```
+将时间戳转换成日期
+```
+19[11:11:14]ssh> time 1557457862000
+2019-05-10 11:11:02
+```
+将日期转换成时间戳
+```
+20[11:11:25]ssh> time "2019-05-10 11:11:02"
+1557457862000
+```
+
+#### 网卡管理
+```
+2[10:53:25]ssh> ifconfig
+index name ip mask hard
+5 en0 192.168.0.106 24 c4:b3:01:cf:0b:51
+```
+
+### 完整版
+命令行模式,只是context最基本的功能。context还提供了一个前端框架,
+让用户可以自由的组合功能列表,满足自己的需求。
+
+使用更丰富的功能,可以直接下载源码,
+```
+$ git clone https://github.com/shylinux/context.git
+```
+下载完源码后,如果安装了golang,就可以对源码直接进行编译,
+如果没有可以去官网下载安装golang()。
+第一次make时,会自动下载各种依赖库,所以会慢一些。
+```
+$ cd context && make
+```
+
+#### 启动服务
+bin目录下是各种可执行文件,如启动脚本boot.sh与node.sh。
+
+node.sh用来启动单机版context,boot.sh用来启动网络版context。
+
+如下,直接运行脚本,即可启动context。
+
+启动context后,就可以解析执行各种命令,即可是本地的shell命令,也可以是内部模块命令。
+
+```
+$ bin/node.sh
+0[03:58:43]ssh>
+```
+
+#### 网页服务
+
+下载完整版的context,启动的服务节点,就会带有前端网页服务。
+
+#### 知识库
+
+wiki模块提供了知识库管理。
+
+访问:http://localhost:9094/wiki
+
+wiki模块会将usr/wiki目录下的md文件进行解析,生成网页文件,并自动生成目录与索引。
+
+可以创建自己的知识库,如下创建目录与文件。
+
+```
+$ mkdir -p usr/wiki/some
+$ echo "hello world" > usr/wiki/some/hi.md
+```
+
+然后在服务终端上,切换到新建的知识库,
+```
+0[10:53:25]ssh> ~wiki config wiki_level wiki/some
+```
+
+也可以加到启动文件中,
+```
+$ cat etc/local.shy
+~wiki
+ config wiki_level wiki/some
+```
+
+#### 用户界面
+
+chat模块提供了完整的功能系统。
+
+在一台公共的设备上启动服务节点,在etc/local.shy的启动脚本中加入如下两行命令。此设备就可以成为公共服务器。
+```
+~ssh
+ work serve
+```
+
+在任意其它设备上,每个用户都可以启动自己的节点,在启动脚本etc/local.shy,添加如下两行代码,此设备就可以成为用户的主控节点。
+```
+~ssh
+ work create
+```
+
+在启动用户节点时,只要指定服务节点,就可以实现用户注册,自动加入群组。
+```
+ ctx_dev=http://172.0.0.172 bin/boot.sh
+```
+
+然后登录 http://172.0.0.172:9095/chat 或 http://127.0.0.127:9095/chat ,
+输入自己的用户名,与初始密码,就可以登录系统。
+
+然后就可以自由的创建群聊、共享设备、实时聊天。
+
+#### 模块开发
+```
+project hello
+compile hello
+publish hello
+```
+
+### 所有目录
+
+#### 一级目录
+
+- src
+- etc
+- bin
+- var
+- usr
+
+#### 源码目录
+
+- src/toolkit
+- src/context
+- src/example
+- src/plugin
+
+#### 配置文件
+
+- etc/init.shy
+- etc/common.shy
+- etc/exit.shy
+
+#### 执行文件
+
+- bin/boot.sh
+- bin/node.sh
+- bin/bench
+
+#### 日志文件
+
+- var/log/boot.log
+- var/log/error.log
+- var/log/right.log
+- var/log/bench.log
+- var/log/debug.log
+- var/run/bench.pid
+- var/run/user/cert.pem
+- var/run/user/key.pem
+- var/run/node/cert.pem
+- var/run/node/key.pem
+- var/tmp/runtime.json
+- var/tmp/auth.json
+
+#### 应用目录
+
+- usr/template
+- usr/librarys
+- usr/upgrade
+- usr/client
+
+## 应用开发
+- Windows
+- Mac
+- pi
+- mp
+- iOS
+- Android
+
+### 应用接口
+
+context的应用模块都是web的子模块,在web模块启动HTTP服务后,会根据模块名与命令名自动生成路由。
+web模块会将所有的HTTP请求转换成context的命令调用,所以HTTP的应用接口和普通命令,除了名字必须以"/"开头,其它没有太大区别。
+
+当web接收到HTTP请求后,可以调用单个命令如 http://shylinux.com/code/consul 就会调用code模块下的/consul命令
+
+可以调用多个命令如 http://shylinux.com/code/?componet_group=login 就会调用web模块下的/render命令,
+根据code的componet下的login组件,依次调用每个接口的命令,然后将执行结果与参数一起,调用golang的template,渲染生成HTML。
+
+所有命令都解析完成后就可以生成一个完整的网页。当然如果Accept是application/json,则会跳过模块渲染,直接返回多条命令的执行结果。
+所以componet就是接口的集合,统一提供参数配置、权限检查、命令执行、模板渲染,前端展示样式,前端初始化函数,降低内部命令与外部应用的耦合性,但又将前后端完全融合在一起。
+
+如下,是web.code模块的应用接口定义。配置componet下定义了多个组件,每个组件下定义了多个接口。
+
+login就是登录页面,下面定义了三个接口code、login、tail,
+其中code,使用模板head生成网页头,会包括一些配置,如favicon可以指定图标文件,styles指定引用模式表。
+其中tail,使用模板tail生成网页尾,会包括一些配置,如scripts指定引用脚本文件。
+login就是网页组件了,生成一个网页登录的输入表单,并接收表单请求调用aaa模块的auth命令,进行用户身份的验证。
+其中arguments指定了Form表单字段的列表。
+```
+...
+var Index = &ctx.Context{Name: "code", Help: "代码中心",
+ Caches: map[string]*ctx.Cache{},
+ Configs: map[string]*ctx.Config{
+ "skip_login": &ctx.Config{Name: "skip_login", Value: map[string]interface{}{"/consul": "true"}, Help: "免密登录"},
+ "componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{
+ "login": []interface{}{
+ map[string]interface{}{"componet_name": "code", "componet_tmpl": "head", "metas": []interface{}{
+ map[string]interface{}{"name": "viewport", "content": "width=device-width, initial-scale=0.7, user-scalable=no"},
+ }, "favicon": "favicon.ico", "styles": []interface{}{"example.css", "code.css"}},
+
+ map[string]interface{}{"componet_name": "login", "componet_help": "login", "componet_tmpl": "componet",
+ "componet_ctx": "aaa", "componet_cmd": "auth", "componet_args": []interface{}{"@sessid", "ship", "username", "@username", "password", "@password"}, "inputs": []interface{}{
+ map[string]interface{}{"type": "text", "name": "username", "value": "", "label": "username"},
+ map[string]interface{}{"type": "password", "name": "password", "value": "", "label": "password"},
+ map[string]interface{}{"type": "button", "value": "login"},
+ },
+ "display_append": "", "display_result": "",
+ },
+
+ map[string]interface{}{"componet_name": "tail", "componet_tmpl": "tail",
+ "scripts": []interface{}{"toolkit.js", "context.js", "example.js", "code.js"},
+ },
+ },
+...
+```
+### 网页开发
+
+#### 模板
+
+usr/template 存放了网页的模板文件,context会调用golang的template接口进行后端渲染,生成html文件。
+不同的应用模块都会有自己的模板目录,也有公共模板库。
+
+- usr/template/common.tmpl 公共模板
+- usr/template/code/ code模块的模板
+- usr/template/wiki/ wiki模块的模板
+- usr/template/chat/ chat模块的模板
+
+#### 样式
+
+所有的css都存放usr/librarys
+
+- example.css
+- code.css
+- wiki.css
+- chat.css
+
+#### 脚本
+
+所有的js都存放usr/librarys
+
+- toolkit.js 工具库,主要是网页相关的操作,如AppendChild
+- context.js 通信库,主要是用来与后端context进行通信
+- example.js 框架库,统一定义了网页的框架,每个应用网页都会继承
+- code.js 工具链应用的网页
+- wiki.js 知识库应用的网页
+- chat.js 信息流应用的网页
+
+### 小程序
+### 开发板
+
+## 接口开发
+### componet
+### python
+### java
+### c
+
+## 模块开发
+### 应用模块
+#### 简单模块
+#### 复杂模块
+#### 脚本模块
+### 插件模块
+#### 独立插件
+#### 扩展插件
+### 核心模块
+#### 模块中心ctx
+#### 命令中心cli
+#### 认证中心aaa
+#### 应用中心web
+#### 网络中心tcp
+#### 存储中心nfs
+#### 集群中心ssh
+#### 数据中心mdb
+
+## 系统架构
+
+| |数据流|命令流|权限流|应用流|
+|---|---|---|---|---|
+|应用层|ctx|cli|aaa|web|
+|控制层|lex|yac|log|gdb|
+|数据层|tcp|nfs|ssh|mdb|
+
+### 应用框架
+#### 模块
+
+context内部使用模块组织功能,每个模块都可以独立编译,独立运行。
+解除了代码之间的包依赖、库依赖、引用依赖、调用依赖。
+通过map查找模块,通过map查找命令,通过map查找配置,从而实现完全自由的模块。
+
+**模块定义:**
+```
+type Context struct { // src/contexts/ctx/ctx.go
+ Name string
+ Help string
+
+ Caches map[string]*Cache
+ Configs map[string]*Config
+ Commands map[string]*Command
+
+ ...
+
+ contexts map[string]*Context
+ context *Context
+ root *Context
+
+ ...
+ Server
+}
+
+```
+Name:模块名称,Help:模块帮助。
+模糊搜索搜索时,会根据Name与Help进行匹配。
+
+每个模块会有命令集合Commands,配置集合Configs,缓存集合Caches。通过这种形式提供功能集合。
+
+contexts:所有子模块,context:指向父模块,root:指向根模块。
+从而组成一个模块树,所以可以通过路由查找模块,
+如ctx.web.code,code的父模块是web,web的父模块是ctx,ctx是根模块。
+所以可以通过命令,查看到当前程序所有模块的信息。
+
+**缓存定义:**
+```
+type Cache struct {
+ Value string
+ Name string
+ Help string
+ Hand func(m *Message, x *Cache, arg ...string) string
+}
+```
+Value:存放的数据,Name:变量名称,Help:变量帮助,Hand读写函数。
+
+缓存数量是一种数据接口,用来存放一些状态量,向外部显示程序进行状态,对外部来说一般是只读的。对内部来说可读可写。
+所以可以通过命令,查看到当前程序任意模块的状态数据。
+
+如下,ncontext当前有多少个模块。nserver有多少个模块运行了守护协程。
+
+```
+"nserver": &Cache{Name: "nserver", Value: "0", Help: "服务数量"},
+"ncontext": &Cache{Name: "ncontext", Value: "0", Help: "模块数量"},
+```
+
+**缓存读写:**
+```
+func (m *Message) Cap(key string, arg ...interface{}) string {}
+func (m *Message) Capi(key string, arg ...interface{}) int {}
+func (m *Message) Caps(key string, arg ...interface{}) bool {}
+```
+定义了缓存数据的三种读写接口。
+
+m.Cap()只有一个参数时,会从当前模块查询缓存变量,如果查到则返回Value,如果没有,则依次查询父模块。
+如果查找到根模块还没有查到找,变返回空字符串。
+
+m.Cap()有两个参数时,同样会从当前模块依次查询父模块,直到查到变量,然后设置其值。
+
+m.Capi()是对m.Cap()封装了一下,在int与str相互转换,从而实现用str存储int。
+所有转换失败的数据,都会返回0。
+
+m.Caps(),实现了str存储bool。返回false的值有"", "0", "false", "off", "no", "error: ",其它都返回true。
+
+**配置定义:**
+```
+type Config struct {
+ Value interface{}
+ Name string
+ Help string
+ Hand func(m *Message, x *Cache, arg ...string) string
+}
+```
+Value:存放的数据,Name:变量名称,Help:变量帮助,Hand读写函数。
+与Cache相似,只是Value的类型不再是String而是interface{},所以可以用来存放更复杂的数据。
+
+一般用来存放配置数据,是外部控制内部数据接口。
+所以可以通过命令,实时修改当前程序任意模块的配置数据。
+避免只是修改某个配置变量,就要重启整个进程,从而实现高效灵活的配置。
+把每个进程当成一个生命来对待,不要轻易杀死任何一个进程。有问题可以用微创手术解决。
+
+**配置读写:**
+```
+func (m *Message) Conf(key string, args ...interface{}) string {}
+func (m *Message) Confi(key string, arg ...interface{}) int {}
+func (m *Message) Confs(key string, arg ...interface{}) bool {}
+func (m *Message) Confx(key string, args ...interface{}) string {}
+func (m *Message) Confv(key string, args ...interface{}) interface{} {}
+func (m *Message) Confm(key string, args ...interface{}) map[string]interface{} {}
+```
+与Cache相似,也定义了各种读写的接口。
+
+因为interface{}可以是任意复合类型,所以数据嵌套很深时,查询会涉及各种类型转换,非常麻烦。
+Conf()定义了键值链。内部去处理类型转换与嵌套的深入。
+如m.Conf("runtime", "user.node")、m.Conf("runtime", []string{"user", "node"})、m.Conf("runtime", []interface{}{"user", "node"})
+都会查询配置runtime下的user下的node的值。
+
+m.Confx()内部进行选择,如果m.Option(key)中取到了值,则直接返回m.Option(key),否则返回m.Conf(key)。
+把配置当成一个备用的默认值,如果命令参数设置了此参数,则用命令中的参数。
+
+m.Confv()直接读写原始数据。
+m.Confm()则定义了更丰富的接口,m就是map意思,直接返回map[string]interface{}
+m另外一个意思就是magic,可以传入各种回调函数。
+如下配置node类型是map[string]interface{},m.Confm()会遍历此map,查到value也是map[string]interface{}的键值,调用回调函数。
+```
+ ...
+ m.Confm("node", func(name string, node map[string]interface{}) {
+ if kit.Format(node["type"]) != "master" {
+ ps = append(ps, kit.Format(node["module"]))
+ }
+ })
+ ...
+```
+
+**命令定义:**
+```
+type Command struct {
+ Form map[string]int
+ Name string
+ Help interface{}
+ Auto func(m *Message, c *Context, key string, arg ...string) (ok bool)
+ Hand func(m *Message, c *Context, key string, arg ...string) (e error)
+}
+```
+Name:命令语法,Help:命令帮助。
+
+Hand:命令处理函数,m是调用消息,c是当前模块,key是命令名,arg是命令参数。
+
+在命令解析时,会根据Form将[key value...]形式的参数,取出存放到m.Option中,方便用key直接查找参数。
+所以arg中只剩下序列参数,通过index序号查找参数。
+
+Auto:终端自动补全函数。在使用终端每输入一个单词时,就调用此函数输出提示信息。所以在命令执行前,这个函数会被调用多次。
+
+如下定义了trans命令
+```
+ ...
+ "trans": &Command{Name: "trans option [type|data|json] limit 10 [index...]", Help: "数据转换",
+ Form: map[string]int{"format": 1, "fields": -1},
+ Hand: func(m *Message, c *Context, key string, arg ...string) (e error) {
+ ...
+ }}
+ ...
+```
+
+**命令调用:**
+```
+func (m *Message) Cmd(args ...interface{}) *Message {}
+func (m *Message) Cmdx(args ...interface{}) string {}
+func (m *Message) Cmds(args ...interface{}) bool {}
+func (m *Message) Cmdy(args ...interface{}) *Message {}
+func (m *Message) Cmdm(args ...interface{}) *Message {}
+```
+m.Cmd()根据第一个参数去当前查找命令,如果没有查找到,则去父模块查找。如果没有查找,则不会执行。
+剩下的参数会根据Form定义来解析,存放到m.Option中。
+
+m.Cmds()当返回值转换成bool规则同m.Caps()与m.Confs()。
+m.Cmdx()当返回值转换成str。 m.Cmdy()将结果复制到当前Message。
+
+m.Cmdm(),m同样是magic,会根据当前会话,自动定向到远程某主机某模块,远程调用其命令,当然也可能定向到本机。
+
+#### 协程
+#### 消息
+
+context内部调用都是
+
+
+### 解析引擎
+#### 文件扫描
+#### 词法解析
+#### 语法解析
+#### 执行命令
+### 通信框架
+#### 节点路由
+每个节点在启动时,自动向上级注册,生成一个动态域名,作为本节点的地址。
+如com.mac.led,led的上级节点是mac,mac的上级节点是com。
+其它节点,就可以通过个这个地址查找到此节点。
+
+在调用远程命令时,通信模块根据远程地址的第一个字段,查找子节点,查取成功后,会将剩余的地址与命令发送给查到的子节点。
+子节点收到地址与命令后,继续查找子节点,直到目标节点收到命令,然后将执行结果原路返回。
+
+在查找的过程中,如果没有查找到子节点,则会传给上级节点重新处理。
+
+#### 节点认证
+
+**节点加密**
+每个节点都有证书与密钥。每个节点在发送命令时,都会用自己的密钥签名,目标节点都会用它的证书验签。以此保证命令来源的可靠性。
+
+**节点类型**
+
+- 初始节点,没有归属的节点
+- 主控节点,有用户证书与密钥的节点
+- 从属节点,有用户证书的节点
+
+- 代理节点,主控节点指定的代理节点
+- 共享节点,允许多个用户控制的节点
+- 认证节点,专门用来存放与查询用户证书的节点
+
+用户在某一设备上添加自己的证书与密钥,此节点即为主控节点。 在其它节点上绑定自己的证书,此即为从属节点。
+
+主控节点就可任意控制从属节点,从属节点不能控制主控节点,从属节点之间也不能相互控制。
+
+主控节点可以指定代理节点,代理节点可以代替主控节点控制从属节点。
+
+共享节点,会有多个用户,可能产生冲突,所以需要认证节点协调。
+
+访问共享节点前,需要向认证节点注册,共享节点会从认证节点取出访问用户的信息。
+
+#### 节点权限
+
+***角色***
+
+每个访问用户,都会指定一个角色。
+主控节点的用户默认有root权限。即拥有设备的所有控制权限。
+
+认证节点的用户默认有tech权限。一般是部分功能。
+
+其它节点的用户默认有void权限。即拥有最小集合的权限,一般是只读的命令。
+
+***组件***
+
+组件是功能的集合,远程访问至少要有remote与source组件的权限才可以执行命令。
+
+每个角色下都会有多个组件的权限。
+
+***命令***
+
+命令就节点向外提供功能的最小单元。
+
+每个组件下都会有多条命令。
+
+***规则***
+
+每条命令内部可以用组件与命令的权限机制自定义权限检查。
+
+权限的分配完全由主控节点与从属节点自己配置,其它节点不许配置。
+
+***示例***
+
+如下配置,用户shy的角色是tech,角色tech下有两个组件remote与source,每个组件下都有命令pwd与dir,所以用户shy就可以远程调用命令dir与pwd
+```
+role tech user shy
+role tech componet remote command pwd dir
+role tech componet source command pwd dir
+```
+
+### 存储引擎
+#### 配置
+#### 缓存
+#### 数据
+