### CPPS腳本是一個開源的腳本語言 [](https://gitee.com/cppsscript/cpps/stargazers)[](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