### CPPS脚本是一个开源的脚本语言 [![star](https://gitee.com/cppsscript/cpps/badge/star.svg?theme=dark)](https://gitee.com/cppsscript/cpps/stargazers)[![Github stars](https://img.shields.io/github/stars/johnsonyl/cpps.svg?style=plastic&logo=appveyor)](https://github.com/johnsonyl/cpps)
作者QQ:88481106
邮箱:88481106@qq.com
QQ群:282081601
github:
-
https://github.com/johnsonyl/cpps
2020-12-11 更新
-
1.增加一个基于cpps的MVC框架.目录 bin/webbase
2020-12-10 更新
-
1. 修复[]偶发找不到变量的BUG.
2. 修复#include 对应文件与行号不一致的BUG
3. 更新socket::httpserver path都以小写来检测
4. 增加http模块 downloader类
5. cppsc 支持部分命令 可以查看-h 或 -help , 例子 cppsc -h
6. linux walk支持.
7. mysql模块 增加affected_rows 获取最后一次执行影响行数
8. 取消cppsc 可继续执行语句功能.
9. 修改cppsc默认当前目录main.cpp
10. 修改cppsc 为建立软连接模式
2020-12-9 更新
-
1.增加compress库
1.1 支持 zlib gzip 解压与压缩
1.2 增加 zip ,tar, tar,gz 的文件压缩与解压缩.
注: bz2 lzma 暂时未支持.后续更新.
```
system("chcp 65001"); //use utf8 string
#import "compress"
var srcstr = "123456789";
//zlib
var tarstr = zlib.compress(srcstr);
println(string.length(tarstr));
var srcstr2 = zlib.decompress(tarstr);
println(srcstr2);
println(zlib.adler32(srcstr2));
println(zlib.crc32(srcstr2));
println(zlib.ZLIB_VERSION);
println(zlib.ZLIB_RUNTIME_VERSION());
//gzip
//
var tarstr = gzip.compress(srcstr);
println(string.length(tarstr));
var srcstr2 = gzip.decompress(tarstr);
println(srcstr2);
// //zipfile
var file = zipfile.open("test.zip");
file.extractall();
//输出个别需要文件
foreach(var info: file.infolist()){
if(!info.is_dir()){
var buffer = file.read(info.filename());
if(buffer){
var filename = io.getfilename(info.filename());
println(filename);
var file = io.fopen(filename,"wb+");
if(file){
println("save ok");
io.fwrite(file,buffer);
io.fclose(file);
}
}
}
}
//zip 追加文件
var file = zipfile.open("test2.zip","","a");
file.write("client.cpp");
file.close();
//tarfile
//tar解压缩
var file = tarfile.open("test.tar","r",10240000);
file.extractall();
//tar.gz 解压缩
var file = tarfile.open("test.tar.gz","r:gz",10240000);
file.extractall();
//tar.gz 写入
var file = tarfile.open("test2.tar.gz","x:gz",10240000);
var fileinfo = file.gettarinfo("server.cpp");
file.addfile(fileinfo);
file.close();
```
2020-12-6 更新
-
1.增加协程内置模块 asyncio
```
//无需import asyncio...
async var test()
{
println("do test function");
await asyncio.sleep(2000);
println("do test function done");
return "test";
}
async var test1()
{
println("do test1 function");
await asyncio.sleep(1000);
println("do test1 function done");
return "test1";
}
var test_call_back(var task,var context)
{
println(task.get_name());
println(context);
}
async var main(){
var task1 = asyncio.create_task(test());
task1.set_name("自定义名字用于区分");
task1.add_done_callback(test_call_back,"自定义context内容");
var task2 = asyncio.create_task(test1());
var ret = await asyncio.wait(task1);
if(ret.timeout())
{
println("task1 was timeouted.");
}
println("state:{ret.state()}");
println(ret.result());
println(await task2);
task1.cleanup();// asyncio.wait or asyncio.wait_for need cleanup.
//task2.cleanup(); // crash here.. await will cleanup it.
}
asyncio.run(main());
```
2020-12-5 更新
-
1.增加lambda闭包.类似js.解决了内存泄露问题.
2. 优化cpps运行速度.cpps_value减少一个8字节指针,理论又提速了.
```
var outer() {
var result = [];
result.resize(10);
for (var i = 0; i<10;i++){
result[i] = [](var num){
return [](){
println(num); // 此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样
};
}(i);
}
return result;
}
var l = outer();
foreach(var n : l)
{
n();
}
```
2020-12-2 更新
-
1.增加logging模块
1.1 支持 logging.StreamHandler logging.FileHandler logging.handlers.RotatingFileHandler logging.handlers.TimedRotatingFileHandler
2.修复已知BUG
*** 基础版
```
#import "logging"
logging.create({level:logging.DEBUG,
format:'[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s',
filename:'log/myapp.log',
filemode:'ab+'});
var logger = logging.getlogger('');
var streamhandler = new logging::StreamHandler();
streamhandler.setlevel(logging.DEBUG);
streamhandler.setformatter('[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s');
streamhandler.setcolor([1,2,3,4,5]);
logger.addhandler(streamhandler);
logger.debug("debug");
logger.info("info");
logger.warning("warning");
logger.error("error");
logger.critical("critical");
```
*** 旗舰版(配置版)
```
#import "logging"
var simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s';
var standard_format = '[%(asctime)s][task_id:%(name)s][%(filename)s:%(lineno)d][%(levelname)s][%(message)s]';
var LOGGING_CONFIG = {
version: 1, // 版本号
disable_existing_loggers: false, // 固定写法
formatters: {
standard: {
format: standard_format
},
simple: {
format: simple_format
},
},
filters: {},
handlers: {
//打印到终端的日志
sh: {
level: 'DEBUG',
class: 'logging.StreamHandler', // 打印到屏幕
color: [5,4,3,2,1] , // DEBUG,INFO,WARNING,ERROR,CRITICAL 颜色
formatter: 'simple'
},
fh: {
level: 'DEBUG',
class: 'logging.handlers.TimedRotatingFileHandler', // 打印到屏幕
formatter: 'standard',
filename: "log/log.txt",
mode: "ab+",
backupCount:5, //保留5个
when:"S", //秒
interval:5 //5秒
},
},
loggers: {
root: { //root 为默认
handlers: ['sh','fh'], //这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
level: 'DEBUG',
propagate: true, // 向上(更高level的logger)传递
},
},
}
logging.create_with_config(LOGGING_CONFIG);
while(true){
logging.debug("debug");
logging.info("info");
logging.warning("warning");
logging.error("error");
logging.critical("critical");
sleep(2000);
}
```
2020-12-1 更新
-
1.修复更新的BUG.
2.增加console基础库
3.增加读取传入参数
4.增加文本地址读取顺序.
2020-11-30 更新
-
1.增加foreach xrange.
2.优化cpps速度
```
foreach(var i : xrange(0,999))
{
println(i);
}
foreach(var i : nrange(0,999,3)) //每次递增3
{
println(i);
}
```
2020-11-29 更新
-
1.花了几天的时间优化cpps. 提升运行速度几十倍. 不过优化的还是不够. 大概速度和python 差不多. 目标是lua的速度.以前瞧不起lua,真正运行起来才知道lua的速度不是盖的.没有使用JIT就可以达到这样的速度.优化是真的NB.但是这次更新估计会有很多BUG.特此记录一下.
2020-11-24 更新
-
1.增加hashlib库 md5 sha1 sha224 sha256 sha384 sha512
2.http模块增加urlencode,urldecode
3.增加字符串encoding gbk<->utf8
```
system("chcp 65001"); //use utf8 string
import "hashlib";
var md5 = new hashlib::md5();
md5.update("123456");
println(md5.hexdigest()); //e10adc3949ba59abbe56e057f20f883e
var sha1 = new hashlib::sha1();
sha1.update("123456");
println(sha1.hexdigest()); //7c4a8d09ca3762af61e59520943dc26494f8941b
var sha224 = new hashlib::sha224();
sha224.update("123456");
println(sha224.hexdigest());//f8cdb04495ded47615258f9dc6a3f4707fd2405434fefc3cbf4ef4e6
var sha256 = new hashlib::sha256();
sha256.update("123456");
println(sha256.hexdigest()); //8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
var sha384 = new hashlib::sha384();
sha384.update("123456");
println(sha384.hexdigest());//0a989ebc4a77b56a6e2bb7b19d995d185ce44090c13e2984b7ecc6d446d4b61ea9991b76a4c2f04b1b4d244841449454
var sha512 = new hashlib::sha512();
sha512.update("123456");
println(sha512.hexdigest());//ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413
```
```
//windows default GBK
//system("chcp 65001"); //use utf8 string
import ["encoding"];
var s = "我是中文";
println(s); //鎴戞槸涓枃
var utf8 = encoding.encode(s,encoding.UTF8);
println(utf8); //鎴戞槸涓枃
var gbk = encoding.encode(s,encoding.GBK);
println(gbk);//我是中文
utf8 = encoding.encode(gbk,encoding.UTF8);
println(utf8);//鎴戞槸涓枃
s = encoding.encode(utf8,encoding.GBK);
println(s);//我是中文
```
2020-11-23 更新
-
1.增加base64模块
2.增加mysql模块
3.优化cpps
4.修复字符串format 调用函数找不到变量的BUG.
```
//base64例子
system("chcp 65001"); //use utf8 string
import ["base64"];
var s = "abc";
println("source:{s}");
var encode_s = base64.encode(s);
println("encode_s:{encode_s}");
var deocde_s = base64.decode(encode_s);
println("deocde_s:{deocde_s}");
```
```
//mysql例子
import ["mysql"];
var option = new MysqlOption()
{
db = "dbname",
host = "127.0.0.1",
user = "root",
passwd = "*******",
prot = 3306,
isreconnect = true
}
var conn = mysql.connect(option);
if(conn == null)
{
println("connect error");
exit(0);
}
var results = conn.call("selectuser",["john"])
println(conn.error());
foreach(var result : results)
{
foreach(var record : result.records())
{
println("----------------------------------------");
foreach(var field: record.fields())
{
println("{field.first()}:{field.second()}");
}
}
}
var results = conn.execute("select * from users where username = 'john';")
println(conn.error());
foreach(var result : results)
{
foreach(var record : result.records())
{
println("id:"..record.get("id"));
println("username:"..record.get("username"));
println("userpwd:"..record.get("userpwd"));
}
}
```
2020-11-22 更新2
-
1.增加http模块 httprequest类
```
system("chcp 65001"); //use utf8 string
import ["http"];
var request = new http::httprequest();
request.setcookiesfile("cookies.txt");
//request.setproxy(httpproxy.SOCK5,"192.168.1.166:25455");
//request.setproxyaccount("johnsonyl","mima");
request.addheaders({User-Agent:"cppsrequest/1.1.0"});
var ret = request.get("http://192.168.1.166:8080/Home/test?kkk=100");
println("-------------------GET-------------------------");
println("get:{ret}");
var cookies = request.getcookies();
println("cookies:{cookies}");
var headers = request.getheaders();
println("headers:{headers}");
println("-------------------POST-------------------------");
ret = request.post("http://192.168.1.166:8080/Home/test","kkk=100");
println("post:{ret}");
var cookies = request.getcookies();
println("cookies:{cookies}");
var headers = request.getheaders();
println("headers:{headers}");
println("-------------------END-------------------------");
```
2020-11-22 更新
-
1.增加httpserver
2.增加cpps 一些对外函数
3.修复一些已知BUG
```
system("chcp 65001"); //use utf8 string
import ["socket"];
class Home
{
var name;
Home()
{
name = "I'm John ,32 years old."
}
//http://127.0.0.1:8080 or http://127.0.0.1:8080/Home or http://127.0.0.1:8080/Home/Index
var Index(var request)
{
println("Home/Index..");
println(name);
request.addheader({
Server:"John Server",
Content-Type:"text/plain; charset=UTF-8",
Connection:"close"
});
request.append(name.."\n");
request.send(200,"OK");
}
}
class Student
{
var name;
var age;
Student()
{
name = "xiaoming";
age = 18;
}
//http://127.0.0.1:8080/Student/ or http://127.0.0.1:8080/Student/Index
var Index(var request)
{
request.addheader({
Server:"John Server",
Content-Type:"text/plain; charset=UTF-8",
Connection:"close"
});
request.append("i'm {name}, {age} years old.");
request.send(200,"OK");
}
//http://127.0.0.1:8080/Student/Name
var Name(var request)
{
request.addheader({
Server:"John Server",
Content-Type:"text/plain; charset=UTF-8",
Connection:"close"
});
request.append(name);
request.send(200,"OK");
}
//http://127.0.0.1:8080/Student/Age
var Age(var request)
{
request.addheader({
Server:"John Server",
Content-Type:"text/plain; charset=UTF-8",
Connection:"close"
});
request.append(age);
request.send(200,"OK");
}
}
//http://127.0.0.1:8080/Home/test?kkk=100
var test(var request)
{
request.addheader({
Server:"John Server",
Content-Type:"text/plain; charset=UTF-8",
Connection:"close"
});
request.append("test page.\n");
request.append("path:"..request.getpath().."\n");
request.append("uri:"..request.geturi().."\n");
request.append("kkk:"..request.getparam("kkk").."\n");
request.append("User-Agent header:"..request.getheader("User-Agent").."\n");
request.append("getbuffer():"..request.getbuffer().."\n");
request.send(200,"OK");
}
var option = new HttpServerOption()
{
exceptionfunc = [](var request,var errmsg)
{
println(errmsg);
request.addheader({
Server:"John Server",
Content-Type:"text/plain; charset=UTF-8",
Connection:"close"
});
request.append(errmsg);
request.send(500,"SERVER ERROR");
},
notfoundfunc = [](var request)
{
request.addheader({
Server:"John Server",
Content-Type:"text/plain; charset=UTF-8",
Connection:"close"
});
request.append("there's nothing here.");
request.send(404,"Not Found");
}
}
var http = new socket::httpserver().setoption(option).listen(8080);
http.register_controller_default(Home);
http.register_controller(Student);
http.register_handlefunc("/Home/test",test);
while (true){
http.run();
}
```
2020-11-20 更新
-
1.修改项目结构
2.修改编译为cmake方式
2020-11-19 更新
-
1.增加第一版socket库基于libevent.
2.修复一些BUG
```
system("chcp 65001"); //use utf8 string
import ["socket"];
/*
//服务端部分
var socket_accept(var socketIndex)
{
println("检测到有一个连接:"..socketIndex);
}
var socket_data(var socketIndex,var buffer)
{
var s = buffer.tostring();
println(s);
if(s == "e")
{
srv.closesocket(socketIndex);
}
var writer = new Buffer();
writer.writeString(buffer.tostring());
srv.send(socketIndex, writer);
}
var socket_close(var socketIndex,var err,var errstr)
{
println("检测到有一个关闭:{socketIndex},err:{err},errstr:{errstr}");
}
var socket_parser(var headerbuffer)
{
}
println("start server");
var srv = new socket::server().setoption(new ServerOption(){
ip = "0.0.0.0",
accept = socket_accept,
data = socket_data,
close = socket_close
}).listen(4060);
// var srv = new socket::server().setOption(new ServerOption(){
// ip = "0.0.0.0",
// headersize = 8,//字节
// accept = socket_accept,
// data = socket_data,
// close = socket_close,
// parser = socket_parser
// }).listen(4060);
println("start over");
while (true)
srv.run();
*/
//客户端部分
var socket_connected()
{
println("连接成功啦");
var writer = new Buffer();
writer.writeString("这是一个乒乓消息");
client.send(writer);
}
var socket_data(var buffer)
{
var s = buffer.tostring();
println(s);
Sleep(5000);
var writer = new Buffer();
writer.writeString(buffer.tostring());
client.send(writer);
}
var socket_close(var err,var errstr)
{
println("检测到有一个关闭:err:{err},errstr:{errstr}");
}
var client = new socket::client();
client.setoption(new ClientOption(){
connected = socket_connected,
data = socket_data,
close = socket_close
});
var b = client.connect("192.168.1.166",4060);
while (true)
{
client.run();
}
```
2020-11-16 更新
-
添加curl支持库
```
import ["json","demo","curl"];
//or
//import "json";
//import "demo";
var url = curl.curl_easy_init();
curl.curl_easy_setopt(url, curl.CURLOPT_URL, "http://blog.chinaunix.net");
curl.curl_easy_setopt(url, curl.CURLOPT_VERBOSE, 0);
var res = curl.curl_easy_perform(url);
println(res);
println(url.getdata());
curl.curl_easy_cleanup(url);
```
2020-11-15 更新
-
添加json支持库
简化json.encode默认支持为utf8格式
增加 import 导入支持库功能
```
import ["json", "demo"];
//or
//import "json";
//import "demo";
var arr = [1, 2, 3, 4, 5, 6, 7];
var obj = { a : "我是开发者", b : "hehe" };
println(arr);
println(obj);
var arr2 = json.encode(arr);
var obj2 = json.encode(obj);
println(arr2);
println(obj2);
println(json.decode(arr2));
println(json.decode(obj2));
```
2020-11-14 更新
-
1.增加linux 动态库功能
详情见demo/demo目录
脚本中使用方法
~~~
loadlibrary("demo");
demotest();
freelibrary("demo");
~~~
2.增加demo/hello world 对linux的编译支持
3.修改cpps make时编译文件目录到bin文件夹
2020-11-12 更新
-
1.支持类似py,php的字符串format处理功能
话不多说,上代码
~~~
class A
{
var name = "john";
var age = 32;
}
var a = new A();
var s = "my name is {a.name} , i'm {a.age} years old.";
println(s);
输出:
[Cpps 1.2.0 Copyright (C) 2015-2020 By Johnson, Pub-test]
my name is john , i'm 32 years old.
>
值得注意: { 与 } 需要使用 \{ 与 \} 来特殊处理了。
~~~
2020-11-10 更新2
-
1.修复父类构造函数执行顺序
2.增加调用父类虚函数的功能
3.增加父类对名空间的支持
4.foreach 还是修改成C++ 方式。 并且 : 后为表达式
~~~
foreach(var item : [1,2])
{
println(item);
foreach(var item2 : [3,4])
{
println(item2);
}
}
foreach(var item : {a:1,b:"2"})
{
println(item.first());
println(item.second());
}
var b = {a:1,b:"2"};
foreach(var item : b)
{
println(item.first());
println(item.second());
}
~~~
~~~
namespace cpps
{
class C
{
C()
{
println("C class");
}
var test()
{
println("C->test()");
}
}
}
class A : cpps::C
{
var name;
A(int a){
println("A class:"..name);
}
var test()
{
println("A->test()");
println(name);
}
}
class B:A
{
var age;
B(){
A::constructor(10); //如果构造函数非0参数时,需要手动调用,否则不会调用
println("B class");
}
var test()
{
println("B->test()");
println(age);
cpps::C::test();
}
}
var b = new B(){
name = "john",
age = 32
};
b.test();
输出:
[Cpps 1.2.0 Copyright (C) 2015-2020 By Johnson, Pub-test]
C class
A class:john
B class
B->test()
32
C->test()
>
~~~
2020-11-10 更新
-
重写foreach
老版本使用lambda 方式,很不好。
修改成
见上方新方法
增加 new 时设置变量功能类似c#
~~~
class A
{
var name;
var age;
}
var a = new A(){
name = "john",
age = 32
}
~~~
2020-1-28 更新
-
新年快乐~~ happy new year!
1.今天恢复了对linux gcc++ 的编译支持。
对linux实在不太熟悉。一堆警告。很糟心。
2.增加make lib 与 make install指令
3.cpps 默认工作目录为指定文件目录。
2020-1-21 更新
-
解决了&&与|| 未按照顺序执行导致逻辑错误的BUG。
2020-1-20 更新
-
增加const的支持。
const var abc = "10"; //不可修改。
2020-1-19 更新
-
1.增加调用函数参数支持到11个
2.增加支持构造函数。 c++ 部分需要注册一个名为constructor的函数当构造函数
3.并且修复多层名空间有错误的BUG。
4.增加类似js 当创建出匿名函数后并且调用的方法 例子:
~~~
[](var a){
println(a);
}(123);
~~~
2019-12-7 更新
-
之前老版本是在函数结束后才调用GC,那么如果想在主函数写一个死循环执行逻辑就会造成内存永不会被GC释放,现在会在符合内存大小等限制情况下调用GC释放内存了。具体大小见CPPS\_GEN0\_CHECKSIZE ,等宏定义。
2019-11-01
-
foreach 增加break操作
这2年其实也更新了好多东西 没有同步而已。可以在代码中自行查阅
2017-8-31
-
1.新增CPPS内部函数resume() 在内部抛出thorw异常的时候使用resume可解决GC异常问题
2.新增assert函数
3.新增部分数学库
4.新增CPPS定义库变量 类似math.pi
5.修复vector变量[] 括号内不能使用公式的BUG
6.新增string.format字符串格式化功能
7.修复三元表达式与namespace在某些情况下冲突的问题
8.增加16进制变量值
9.增加svn服务器下载
- 引言
- 目录
- Get Started
- libcurl编译-windows-x64-opensll-zlib
- 基础语法
- if&else
- for&foreach
- while
- function
- 变量
- new
- class
- lambda
- ..字符串拼接
- import
- base
- printf
- printfln
- println
- exit
- sleep&Sleep
- tonumber
- toint
- system
- SetConsoleTitle
- dostring
- dofile
- assert
- _VERSION
- loadlibrary
- freelibrary
- math
- abs
- srand
- rand
- random
- acos
- asin
- atan
- ceil
- cos
- exp
- floor
- fmod
- huge
- log
- max
- maxinteger
- min
- mininteger
- pi
- sin
- sqrt
- tan
- io
- getc
- fopen
- fsize
- fread
- fwrite
- fseek
- fclose
- fflush
- remove
- rename
- getfileext
- getfilepath
- getfilename
- getfilenamenotext
- mkdir
- time
- gettime
- gettimestr
- maketime
- gettickcount
- time2str
- str2time
- issomeday
- getyear
- getmon
- getday
- gethour
- getmin
- getsec
- getyday
- addmonths
- adddays
- addyears
- addweeks
- addhours
- addminutes
- addseconds
- strftime
- string
- find
- rfind
- length
- strlen
- replace
- split
- strcut
- empty
- substr
- npos
- at
- format
- GC
- Collect
- CollectAll
- debug
- open
- close
- breakpoint
- Buffer类
- read
- write
- tostring
- tointerger
- tonumber
- readInt8
- readInt16
- readInt32
- readInt
- readNumber
- readString
- readBool
- writeInt8
- writeInt16
- writeInt32
- writeInt
- writeNumber
- writeString
- writeBool
- seek
- length
- vector类
- push_back
- push_front
- pop_back
- pop_front
- insert
- at
- erase
- pop
- begin
- end
- next
- it
- resize
- clear
- size
- map类
- insert
- find
- erase
- clear
- size
- unordered_map类
- insert
- find
- erase
- pop
- begin
- end
- next
- it
- key
- clear
- size
- 支持库-模块
- json
- Get Started
- encode
- encodeT
- decode
- curl
- Get Started
- CURL
- getdata
- getheader
- append
- curl_easy_init
- curl_easy_cleanup
- curl_easy_setopt
- curl_easy_getinfo
- curl_easy_perform
- curl_version
- socket
- server
- setoption
- listen
- run
- send
- closesocket
- stop
- isrunning
- client
- setoption
- run
- connect
- send
- isconnect
- closesocket
- httpserver
- setoption
- listen
- run
- register_handlefunc
- register_controller
- register_controller_default
- stop
- isrunning
- httpserver_request
- addheader
- append
- send
- getparam
- getheader
- geturi
- getpath
- getbuffer
- ServerOption
- ClientOption
- HttpServerOption
- http
- httprequest
- setcookiesfile
- setproxy
- setproxyaccount
- addheaders
- post
- get
- call
- getcookies
- getheaders
- settimeout
- followlocation
- encoding
- encode
- UTF8
- GBK
- hashlib
- md5
- sha1
- sha224
- sha256
- sha384
- sha512
- mysql
- connect
- mysql类
- call
- execute
- error
- isconnect
- clear
- close
- mysql_result
- records
- mysql_record
- fields
- get
- base64
- encode
- decode