arql 0.3.28 → 0.3.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README-zh_CN.org +1096 -0
- data/README.org +1170 -0
- data/auto-set-id-before-save-zh_CN.org +35 -0
- data/auto-set-id-before-save.org +33 -0
- data/custom-configurations-zh_CN.org +50 -0
- data/custom-configurations.org +54 -0
- data/define-associations-zh_CN.org +38 -0
- data/define-associations.org +37 -0
- data/fuzzy-field-query-zh_CN.org +165 -0
- data/fuzzy-field-query.org +165 -0
- data/helper-for-datetime-range-query-zh_CN.org +216 -0
- data/helper-for-datetime-range-query.org +218 -0
- data/initializer-structure-zh_CN.org +33 -0
- data/initializer-structure.org +31 -0
- data/lib/arql/cli.rb +1 -1
- data/lib/arql/definition.rb +15 -3
- data/lib/arql/version.rb +1 -1
- data/oss-files-zh_CN.org +161 -0
- data/oss-files.org +163 -0
- data/sql-log-zh_CN.org +55 -0
- data/sql-log.org +55 -0
- metadata +20 -3
- data/README.md +0 -456
data/oss-files-zh_CN.org
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
* OSS 数据下载和查看
|
2
|
+
|
3
|
+
有的系统使用云存储服务来存储系统中的文件数据,并在数据库中存储文件在 OSS 上的 Key。我们希望可以在 Arql 中直接下载和查看这些文件。
|
4
|
+
|
5
|
+
** 首先需要安装和配置 =rclone= 工具
|
6
|
+
|
7
|
+
macOS 示例:
|
8
|
+
|
9
|
+
#+BEGIN_EXAMPLE
|
10
|
+
brew install rclone
|
11
|
+
#+END_EXAMPLE
|
12
|
+
|
13
|
+
|
14
|
+
** 配置 rclone
|
15
|
+
|
16
|
+
在 =~/.config/rclone/rclone.conf= 文件中添加系统所使用的 OSS 配置,例如:
|
17
|
+
|
18
|
+
#+BEGIN_EXAMPLE
|
19
|
+
[my_system]
|
20
|
+
type = s3
|
21
|
+
provider = Alibaba
|
22
|
+
env_auth = false
|
23
|
+
access_key_id = LTAxuiwqsayuuyea
|
24
|
+
secret_access_key = sauiqwYUwqhjsdayuwehjkwehjwehj
|
25
|
+
endpoint = oss-cn-beijing.aliyuncs.com
|
26
|
+
acl = private
|
27
|
+
storage_class = STANDARD
|
28
|
+
#+END_EXAMPLE
|
29
|
+
|
30
|
+
|
31
|
+
** 在 =~/.arql.d/init.yaml= 中添加配置
|
32
|
+
|
33
|
+
#+BEGIN_SRC yaml
|
34
|
+
dev:
|
35
|
+
created_at: ["create_time", "gmt_created"]
|
36
|
+
updated_at: ["update_time", "gmt_modified"]
|
37
|
+
host: db.dev.com
|
38
|
+
port: 3306
|
39
|
+
username: admin
|
40
|
+
password: 123456
|
41
|
+
database: dev_db
|
42
|
+
rclone_name: "my_system"
|
43
|
+
oss_bucket: "my_system_dev_bucket"
|
44
|
+
|
45
|
+
prod:
|
46
|
+
created_at: ["create_time", "gmt_created"]
|
47
|
+
updated_at: ["update_time", "gmt_modified"]
|
48
|
+
host: db.prod.com
|
49
|
+
port: 3306
|
50
|
+
username: admin
|
51
|
+
password: 123456
|
52
|
+
database: prod_db
|
53
|
+
rclone_name: "my_system"
|
54
|
+
oss_bucket: "my_system_prod_bucket"
|
55
|
+
#+END_SRC
|
56
|
+
|
57
|
+
|
58
|
+
** 创建一个文件 =~/.arql.d/oss.rb=
|
59
|
+
|
60
|
+
#+BEGIN_SRC ruby
|
61
|
+
class OSS
|
62
|
+
def pry_source_location; end
|
63
|
+
|
64
|
+
attr_accessor :path, :bucket
|
65
|
+
|
66
|
+
def initialize(path, bucket: nil)
|
67
|
+
@path = path
|
68
|
+
unless bucket
|
69
|
+
bucket = Arql::App.config['oss_bucket']
|
70
|
+
end
|
71
|
+
@bucket = bucket
|
72
|
+
end
|
73
|
+
|
74
|
+
def rclone_name
|
75
|
+
Arql::App.config['rclone_name']
|
76
|
+
end
|
77
|
+
|
78
|
+
def info
|
79
|
+
`rclone lsl #{rclone_name}:#{bucket}/#{path}`
|
80
|
+
end
|
81
|
+
|
82
|
+
def download(dir = nil, keep_structure = false)
|
83
|
+
dir = File.expand_path(dir) if dir
|
84
|
+
dir ||= Dir.mktmpdir('arql-attachment-')
|
85
|
+
if keep_structure
|
86
|
+
dest_dir = dir + '/' + File.dirname(path)
|
87
|
+
FileUtils.mkdir_p(dest_dir)
|
88
|
+
system <<~EOF
|
89
|
+
rclone copy #{rclone_name}:#{bucket}/#{path} #{dest_dir}/
|
90
|
+
EOF
|
91
|
+
dest_dir + '/' + File.basename(path)
|
92
|
+
else
|
93
|
+
system <<~EOF
|
94
|
+
rclone copy #{rclone_name}:#{bucket}/#{path} #{dir}/
|
95
|
+
EOF
|
96
|
+
dir + '/' + File.basename(path)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def copy(dest_name, dest_bucket)
|
101
|
+
path_prefix = File.dirname(path)
|
102
|
+
system "rclone copy -P #{rclone_name}:#{bucket}/#{path} #{dest_name}:#{dest_bucket}/#{path_prefix}/"
|
103
|
+
end
|
104
|
+
|
105
|
+
def cat
|
106
|
+
`rclone cat #{rclone_name}:#{bucket}/#{path}`
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_rclone_url
|
110
|
+
"#{rclone_name}:#{bucket}/#{path}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def open
|
114
|
+
file = download
|
115
|
+
system <<~EOF
|
116
|
+
open #{file}
|
117
|
+
EOF
|
118
|
+
file
|
119
|
+
end
|
120
|
+
|
121
|
+
def preview
|
122
|
+
file = download
|
123
|
+
system <<~EOF
|
124
|
+
qlmanage -p #{file} &> /dev/null
|
125
|
+
EOF
|
126
|
+
file
|
127
|
+
end
|
128
|
+
|
129
|
+
def emacs_open
|
130
|
+
file = download
|
131
|
+
system <<~EOF
|
132
|
+
emacsclient -q --eval "(switch-to-buffer-other-window (current-buffer))" &> /dev/null
|
133
|
+
emacsclient -n '#{file}'
|
134
|
+
EOF
|
135
|
+
file
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class String
|
140
|
+
def oss(bucket: nil)
|
141
|
+
OSS.new(self, bucket: bucket)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
#+END_SRC
|
145
|
+
|
146
|
+
** 在 =~/.arql.d/init.rb= 中引入这个文件
|
147
|
+
|
148
|
+
#+BEGIN_SRC ruby
|
149
|
+
load(File.absolute_path(File.dirname(__FILE__) + "/oss.rb"))
|
150
|
+
#+END_SRC
|
151
|
+
|
152
|
+
** 用法
|
153
|
+
|
154
|
+
假设 user 表中有一个 avatar 字段存储了用户头像在 OSS 上的 Key,我们可以这样查看和下载头像:
|
155
|
+
|
156
|
+
#+BEGIN_SRC ruby
|
157
|
+
User.first.avatar.oss.preview # 使用 macOS Quick Look 预览
|
158
|
+
User.first.avatar.oss.download # 下载到临时目录,并返回文件路径
|
159
|
+
User.first.avatar.oss.open # 下载到临时目录,并使用系统(macOS)默认程序打开
|
160
|
+
User.first.avatar.oss.cat # 直接输出文件内容
|
161
|
+
#+END_SRC
|
data/oss-files.org
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
* Download and Preview Files in OSS
|
2
|
+
|
3
|
+
Some systems use cloud storage services to store file data in the system and store the key of the file on OSS in the database. We hope to be able to download and view these files directly in Arql.
|
4
|
+
|
5
|
+
** First you need to install and configure =rclone= tool
|
6
|
+
|
7
|
+
macOS example:
|
8
|
+
|
9
|
+
#+BEGIN_EXAMPLE
|
10
|
+
brew install rclone
|
11
|
+
#+END_EXAMPLE
|
12
|
+
|
13
|
+
|
14
|
+
** Configure rclone
|
15
|
+
|
16
|
+
Add the OSS configuration used by the system to the =~/.config/rclone/rclone.conf= file, for example:
|
17
|
+
|
18
|
+
#+BEGIN_EXAMPLE
|
19
|
+
[my_system]
|
20
|
+
type = s3
|
21
|
+
provider = Alibaba
|
22
|
+
env_auth = false
|
23
|
+
access_key_id = LTAxuiwqsayuuyea
|
24
|
+
secret_access_key = sauiqwYUwqhjsdayuwehjkwehjwehj
|
25
|
+
endpoint = oss-cn-beijing.aliyuncs.com
|
26
|
+
acl = private
|
27
|
+
storage_class = STANDARD
|
28
|
+
#+END_EXAMPLE
|
29
|
+
|
30
|
+
|
31
|
+
** Add configuration in =~/.arql.d/init.yaml=
|
32
|
+
|
33
|
+
#+BEGIN_SRC yaml
|
34
|
+
dev:
|
35
|
+
created_at: ["create_time", "gmt_created"]
|
36
|
+
updated_at: ["update_time", "gmt_modified"]
|
37
|
+
host: db.dev.com
|
38
|
+
port: 3306
|
39
|
+
username: admin
|
40
|
+
password: 123456
|
41
|
+
database: dev_db
|
42
|
+
rclone_name: "my_system"
|
43
|
+
oss_bucket: "my_system_dev_bucket"
|
44
|
+
|
45
|
+
prod:
|
46
|
+
created_at: ["create_time", "gmt_created"]
|
47
|
+
updated_at: ["update_time", "gmt_modified"]
|
48
|
+
host: db.prod.com
|
49
|
+
port: 3306
|
50
|
+
username: admin
|
51
|
+
password: 123456
|
52
|
+
database: prod_db
|
53
|
+
rclone_name: "my_system"
|
54
|
+
oss_bucket: "my_system_prod_bucket"
|
55
|
+
#+END_SRC
|
56
|
+
|
57
|
+
|
58
|
+
** Create a file =~/.arql.d/oss.rb=
|
59
|
+
|
60
|
+
#+BEGIN_SRC ruby
|
61
|
+
class OSS
|
62
|
+
def pry_source_location; end
|
63
|
+
|
64
|
+
attr_accessor :path, :bucket
|
65
|
+
|
66
|
+
def initialize(path, bucket: nil)
|
67
|
+
@path = path
|
68
|
+
unless bucket
|
69
|
+
bucket = Arql::App.config['oss_bucket']
|
70
|
+
end
|
71
|
+
@bucket = bucket
|
72
|
+
end
|
73
|
+
|
74
|
+
def rclone_name
|
75
|
+
Arql::App.config['rclone_name']
|
76
|
+
end
|
77
|
+
|
78
|
+
def info
|
79
|
+
`rclone lsl #{rclone_name}:#{bucket}/#{path}`
|
80
|
+
end
|
81
|
+
|
82
|
+
def download(dir = nil, keep_structure = false)
|
83
|
+
dir = File.expand_path(dir) if dir
|
84
|
+
dir ||= Dir.mktmpdir('arql-attachment-')
|
85
|
+
if keep_structure
|
86
|
+
dest_dir = dir + '/' + File.dirname(path)
|
87
|
+
FileUtils.mkdir_p(dest_dir)
|
88
|
+
system <<~EOF
|
89
|
+
rclone copy #{rclone_name}:#{bucket}/#{path} #{dest_dir}/
|
90
|
+
EOF
|
91
|
+
dest_dir + '/' + File.basename(path)
|
92
|
+
else
|
93
|
+
system <<~EOF
|
94
|
+
rclone copy #{rclone_name}:#{bucket}/#{path} #{dir}/
|
95
|
+
EOF
|
96
|
+
dir + '/' + File.basename(path)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def copy(dest_name, dest_bucket)
|
101
|
+
path_prefix = File.dirname(path)
|
102
|
+
system "rclone copy -P #{rclone_name}:#{bucket}/#{path} #{dest_name}:#{dest_bucket}/#{path_prefix}/"
|
103
|
+
end
|
104
|
+
|
105
|
+
def cat
|
106
|
+
`rclone cat #{rclone_name}:#{bucket}/#{path}`
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_rclone_url
|
110
|
+
"#{rclone_name}:#{bucket}/#{path}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def open
|
114
|
+
file = download
|
115
|
+
system <<~EOF
|
116
|
+
open #{file}
|
117
|
+
EOF
|
118
|
+
file
|
119
|
+
end
|
120
|
+
|
121
|
+
def preview
|
122
|
+
file = download
|
123
|
+
system <<~EOF
|
124
|
+
qlmanage -p #{file} &> /dev/null
|
125
|
+
EOF
|
126
|
+
file
|
127
|
+
end
|
128
|
+
|
129
|
+
def emacs_open
|
130
|
+
file = download
|
131
|
+
system <<~EOF
|
132
|
+
emacsclient -q --eval "(switch-to-buffer-other-window (current-buffer))" &> /dev/null
|
133
|
+
emacsclient -n '#{file}'
|
134
|
+
EOF
|
135
|
+
file
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class String
|
140
|
+
def oss(bucket: nil)
|
141
|
+
OSS.new(self, bucket: bucket)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
#+END_SRC
|
145
|
+
|
146
|
+
|
147
|
+
** Import this file in =~/.arql.d/init.rb=
|
148
|
+
|
149
|
+
#+BEGIN_SRC ruby
|
150
|
+
load(File.absolute_path(File.dirname(__FILE__) + "/oss.rb"))
|
151
|
+
#+END_SRC
|
152
|
+
|
153
|
+
** Usage
|
154
|
+
|
155
|
+
|
156
|
+
Assuming that the user table has an avatar field that stores the key of the user's avatar on OSS, we can view and download the avatar like this:
|
157
|
+
|
158
|
+
#+BEGIN_SRC ruby
|
159
|
+
User.first.avatar.oss.preview # Preview using macOS Quick Look
|
160
|
+
User.first.avatar.oss.download # Download to a temporary directory and return the file path
|
161
|
+
User.first.avatar.oss.open # Download to a temporary directory and open with the system (macOS) default program
|
162
|
+
User.first.avatar.oss.cat # Output file content directly
|
163
|
+
#+END_SRC
|
data/sql-log-zh_CN.org
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
* 自动记录 SQL 日志和 REPL 输入历史
|
2
|
+
|
3
|
+
如果希望 Arql 可以自动记录 SQL 日志和 REPL 输入历史,可以:
|
4
|
+
|
5
|
+
创建目录 =~/.arql.d/logs=
|
6
|
+
|
7
|
+
创建一个文件 =~/.arql.d/sql_log.rb= ,内容如下:
|
8
|
+
|
9
|
+
#+BEGIN_SRC ruby
|
10
|
+
unless Arql::App.config[:append_sql]
|
11
|
+
log_root_dir = File.expand_path('~/.arql.d/logs')
|
12
|
+
log_dir = "#{log_root_dir}/%s" % Arql::App.env
|
13
|
+
FileUtils.mkdir_p(log_dir)
|
14
|
+
now = Time.now
|
15
|
+
log_file = "#{log_dir}/%s.%s.%s.log" % [Time.now.strftime('%Y_%m%d_%H%M%S'), `hostname -s`.chomp.downcase, Process.pid]
|
16
|
+
Arql::App.config[:append_sql] = log_file
|
17
|
+
|
18
|
+
lfile = File.new(log_file, 'a')
|
19
|
+
lfile.sync = true
|
20
|
+
InputLogger = Logger.new(lfile)
|
21
|
+
|
22
|
+
module Readline
|
23
|
+
class << self
|
24
|
+
alias_method :original_readline, :readline
|
25
|
+
def readline(*args)
|
26
|
+
Readline.original_readline(*args).tap do |user_input|
|
27
|
+
InputLogger.info(user_input)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
#+END_SRC
|
34
|
+
|
35
|
+
|
36
|
+
然后在 =~/.arql.d/init.rb= 中引入这个文件:
|
37
|
+
|
38
|
+
#+BEGIN_SRC ruby
|
39
|
+
load(File.absolute_path(File.dirname(__FILE__) + "/sql_log.rb"))
|
40
|
+
#+END_SRC
|
41
|
+
|
42
|
+
这样就可以在 =~/.arql.d/logs= 目录下看到 SQL 日志和 REPL 输入历史了。
|
43
|
+
|
44
|
+
示例:
|
45
|
+
|
46
|
+
#+BEGIN_EXAMPLE
|
47
|
+
I, [2024-04-07T17:12:00.530341 #20440] INFO -- : P.count
|
48
|
+
D, [2024-04-07T17:12:00.577305 #20440] DEBUG -- : Post Count (22.6ms) SELECT COUNT(*) FROM `post`
|
49
|
+
I, [2024-04-07T17:12:02.879312 #20440] INFO -- : P.all.t
|
50
|
+
D, [2024-04-07T17:12:02.960014 #20440] DEBUG -- : Post Load (64.1ms) SELECT `post`.* FROM `post`
|
51
|
+
I, [2024-04-07T17:12:54.721861 #20440] INFO -- : P.pluck(:gender)
|
52
|
+
D, [2024-04-07T17:12:54.756435 #20440] DEBUG -- : Post Pluck (28.0ms) SELECT `post`.`gender` FROM `post`
|
53
|
+
#+END_EXAMPLE
|
54
|
+
|
55
|
+
|
data/sql-log.org
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
* Save SQL logs and REPL history automatically
|
2
|
+
|
3
|
+
If you want Arql to automatically save SQL logs and REPL history, you can:
|
4
|
+
|
5
|
+
Create a directory =~/.arql.d/logs=
|
6
|
+
|
7
|
+
Create a file =~/.arql.d/sql_log.rb= with the following content:
|
8
|
+
|
9
|
+
#+BEGIN_SRC ruby
|
10
|
+
unless Arql::App.config[:append_sql]
|
11
|
+
log_root_dir = File.expand_path('~/.arql.d/logs')
|
12
|
+
log_dir = "#{log_root_dir}/%s" % Arql::App.env
|
13
|
+
FileUtils.mkdir_p(log_dir)
|
14
|
+
now = Time.now
|
15
|
+
log_file = "#{log_dir}/%s.%s.%s.log" % [Time.now.strftime('%Y_%m%d_%H%M%S'), `hostname -s`.chomp.downcase, Process.pid]
|
16
|
+
Arql::App.config[:append_sql] = log_file
|
17
|
+
|
18
|
+
lfile = File.new(log_file, 'a')
|
19
|
+
lfile.sync = true
|
20
|
+
InputLogger = Logger.new(lfile)
|
21
|
+
|
22
|
+
module Readline
|
23
|
+
class << self
|
24
|
+
alias_method :original_readline, :readline
|
25
|
+
def readline(*args)
|
26
|
+
Readline.original_readline(*args).tap do |user_input|
|
27
|
+
InputLogger.info(user_input)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
#+END_SRC
|
34
|
+
|
35
|
+
Then include this file in =~/.arql.d/init.rb=:
|
36
|
+
|
37
|
+
#+BEGIN_SRC ruby
|
38
|
+
load(File.absolute_path(File.dirname(__FILE__) + "/sql_log.rb"))
|
39
|
+
#+END_SRC
|
40
|
+
|
41
|
+
This way you can see SQL logs and REPL history in the =~/.arql.d/logs= directory.
|
42
|
+
|
43
|
+
Example:
|
44
|
+
|
45
|
+
#+BEGIN_EXAMPLE
|
46
|
+
I, [2024-04-07T17:12:00.530341 #20440] INFO -- : P.count
|
47
|
+
D, [2024-04-07T17:12:00.577305 #20440] DEBUG -- : Post Count (22.6ms) SELECT COUNT(*) FROM `post`
|
48
|
+
I, [2024-04-07T17:12:02.879312 #20440] INFO -- : P.all.t
|
49
|
+
D, [2024-04-07T17:12:02.960014 #20440] DEBUG -- : Post Load (64.1ms) SELECT `post`.* FROM `post`
|
50
|
+
I, [2024-04-07T17:12:54.721861 #20440] INFO -- : P.pluck
|
51
|
+
D, [2024-04-07T17:12:54.756435 #20440] DEBUG -- : Post Pluck (28.0ms) SELECT `post`.`gender` FROM `post`
|
52
|
+
#+END_EXAMPLE
|
53
|
+
|
54
|
+
|
55
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.30
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Liu Xiang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mysql2
|
@@ -304,13 +304,26 @@ files:
|
|
304
304
|
- Gemfile
|
305
305
|
- Gemfile.lock
|
306
306
|
- LICENSE.txt
|
307
|
-
- README.
|
307
|
+
- README-zh_CN.org
|
308
|
+
- README.org
|
308
309
|
- Rakefile
|
309
310
|
- arql.gemspec
|
311
|
+
- auto-set-id-before-save-zh_CN.org
|
312
|
+
- auto-set-id-before-save.org
|
310
313
|
- bin/console
|
311
314
|
- bin/setup
|
315
|
+
- custom-configurations-zh_CN.org
|
316
|
+
- custom-configurations.org
|
317
|
+
- define-associations-zh_CN.org
|
318
|
+
- define-associations.org
|
312
319
|
- exe/arql
|
313
320
|
- exe/arql_setsid_wrapper
|
321
|
+
- fuzzy-field-query-zh_CN.org
|
322
|
+
- fuzzy-field-query.org
|
323
|
+
- helper-for-datetime-range-query-zh_CN.org
|
324
|
+
- helper-for-datetime-range-query.org
|
325
|
+
- initializer-structure-zh_CN.org
|
326
|
+
- initializer-structure.org
|
314
327
|
- lib/arql.rb
|
315
328
|
- lib/arql/app.rb
|
316
329
|
- lib/arql/cli.rb
|
@@ -345,6 +358,10 @@ files:
|
|
345
358
|
- lib/arql/ssh_proxy_patch.rb
|
346
359
|
- lib/arql/vd.rb
|
347
360
|
- lib/arql/version.rb
|
361
|
+
- oss-files-zh_CN.org
|
362
|
+
- oss-files.org
|
363
|
+
- sql-log-zh_CN.org
|
364
|
+
- sql-log.org
|
348
365
|
homepage: https://github.com/lululau/arql
|
349
366
|
licenses:
|
350
367
|
- MIT
|