// facade actions:design(9) + surrogate(5) + stats(3) + highLight/bizData(视图)
// ═══ 流程设计(需扩展仓储)═══
///|
fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::ext(self : Facade[R, E]) -> E raise @error.JeeflowError {
self.ext_repo
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_page(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let page_num = arg_i64_or(args, "pageNum", 1L)
let page_size = arg_i64_or(args, "pageSize", 20L)
let filters = facade_parse_m_filters(args)
let page = (self.ext()).page_designs(@model.PageQuery::new(page_num, page_size))
finalize_page(page, design_to_json, filters, page_num, page_size)
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_detail(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let id = match arg_i64(args, "id") {
Some(v) => v
None => raise @error.Business("缺少id参数")
}
let design = match (self.ext()).find_design_by_id(id) {
Some(d) => d
None => raise @error.Business("流程设计不存在")
}
let his = (self.ext()).list_design_his(id)
let json_object : Json? = if his.is_empty() {
None
} else {
parse_graph(his[0].content)
}
// issues/07:jsonObject 缺基本信息时从设计表补齐
let o = @json.empty_object()
@json.obj_set(o, "id", i64_json(design.id))
@json.obj_set(o, "name", @json.string_of(design.name))
@json.obj_set(o, "displayName", @json.string_of(design.display_name))
@json.obj_set(o, "type", @json.string_of(design.design_type))
@json.obj_set(o, "icon", opt_json(design.icon))
@json.obj_set(o, "isDeployed", num_json(design.is_deployed))
@json.obj_set(o, "remark", opt_json(design.remark))
let job = match json_object {
Some(j) => j
None => @json.empty_object()
}
if @json.get_str(job, "name") is None {
@json.obj_set(job, "name", @json.string_of(design.name))
}
if @json.get_str(job, "displayName") is None {
@json.obj_set(job, "displayName", @json.string_of(design.display_name))
}
if @json.get_str(job, "type") is None {
@json.obj_set(job, "type", @json.string_of(design.design_type))
}
if @json.get_i64(job, "processDesignId") is None {
@json.obj_set(job, "processDesignId", i64_json(design.id))
}
@json.obj_set(o, "jsonObject", job)
let his_arr = @json.empty_array()
for h in his {
@json.arr_push(his_arr, design_his_to_json(h))
}
@json.obj_set(o, "his", his_arr)
o
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_save(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let operator = arg_str_or(args, "operator", "user1")
let id = arg_i64(args, "id")
let design : @model.ProcessDesign = match id {
None => {
let d : @model.ProcessDesign = {
id: 0L,
name: arg_str(args, "name").unwrap_or(""),
display_name: arg_str(args, "displayName").unwrap_or(""),
design_type: arg_str_or(args, "type", "approval"),
icon: arg_str(args, "icon"),
is_deployed: 0,
remark: arg_str(args, "remark"),
create_time: Some(@model.current_time_str()),
create_user: Some(operator),
update_time: None,
update_user: Some(operator),
}
d
}
Some(i) => {
let d = match ext.find_design_by_id(i) {
Some(x) => x
None => raise @error.Business("流程设计不存在")
}
match arg_str(args, "displayName") {
Some(v) => d.display_name = v
None => ()
}
match arg_str(args, "type") {
Some(v) => d.design_type = v
None => ()
}
match arg_str(args, "icon") {
Some(v) => d.icon = Some(v)
None => ()
}
match arg_str(args, "remark") {
Some(v) => d.remark = Some(v)
None => ()
}
d.update_user = Some(operator)
// 内容快照变更 → 置为未部署(issues/08)
if content_bytes(args) is Some(_) {
d.is_deployed = 0
}
d
}
}
if id is None {
ext.save_design(design)
} else {
ext.update_design(design)
}
// 内容快照存历史表
match content_bytes(args) {
Some(content) => {
let his : @model.ProcessDesignHis = {
id: 0L,
process_design_id: design.id,
content,
create_time: Some(@model.current_time_str()),
create_user: Some(operator),
}
ext.save_design_his(his)
}
None => ()
}
let o = @json.empty_object()
@json.obj_set(o, "id", i64_json(design.id))
o
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_update(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let id = match arg_i64(args, "id") {
Some(v) => v
None => raise @error.Business("缺少id参数")
}
let design = match ext.find_design_by_id(id) {
Some(d) => d
None => raise @error.Business("流程设计不存在")
}
match arg_str(args, "name") {
Some(v) => design.name = v
None => ()
}
match arg_str(args, "displayName") {
Some(v) => design.display_name = v
None => ()
}
match arg_str(args, "type") {
Some(v) => design.design_type = v
None => ()
}
match arg_str(args, "icon") {
Some(v) => design.icon = Some(v)
None => ()
}
match arg_str(args, "remark") {
Some(v) => design.remark = Some(v)
None => ()
}
design.update_user = Some(arg_str_or(args, "operator", "system"))
ext.update_design(design)
@json.null_json()
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_update_define(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let design_id = match arg_i64(args, "processDesignId") {
Some(v) => v
None => raise @error.Business("processDesignId 缺失")
}
let design = match ext.find_design_by_id(design_id) {
Some(d) => d
None => raise @error.Business("流程设计不存在")
}
let content = match content_bytes(args) {
Some(c) => c
None => raise @error.Business("content 缺失")
}
// 与最新快照相同则不重复入库(java 同款)
let his = ext.list_design_his(design_id)
let same = if his.is_empty() {
false
} else {
his[0].content == content
}
if !same {
let h : @model.ProcessDesignHis = {
id: 0L,
process_design_id: design_id,
content,
create_time: Some(@model.current_time_str()),
create_user: Some(arg_str_or(args, "operator", "system")),
}
ext.save_design_his(h)
}
// 同步基本信息 + 置未部署
let outcome = try? @parser.parse_model(content)
match outcome {
Ok(model) => {
design.name = model.name
design.display_name = model.display_name
design.design_type = model.model_type
}
Err(_) => ()
}
design.is_deployed = 0
design.update_user = Some(arg_str_or(args, "operator", "system"))
ext.update_design(design)
@json.null_json()
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_remove(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
for id in arg_ids(args) {
(self.ext()).remove_design(id)
}
@json.null_json()
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_deploy(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let design_id = match arg_i64(args, "id") {
Some(v) => v
None => raise @error.Business("缺少id参数")
}
let design = match ext.find_design_by_id(design_id) {
Some(d) => d
None => raise @error.Business("流程设计不存在")
}
let his = ext.list_design_his(design_id)
if his.is_empty() {
raise @error.Business("流程设计没有内容,无法发布")
}
let content = his[0].content
let model = @parser.parse_model(content)
let define_id = self.save_deployed_define(model, content)
design.is_deployed = 1
design.update_user = Some(arg_str_or(args, "operator", "system"))
ext.update_design(design)
let o = @json.empty_object()
@json.obj_set(o, "processDefineId", i64_json(define_id))
o
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_redeploy(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let design_id = match arg_i64(args, "id") {
Some(v) => v
None => raise @error.Business("缺少id参数")
}
let design = match ext.find_design_by_id(design_id) {
Some(d) => d
None => raise @error.Business("流程设计不存在")
}
let his = ext.list_design_his(design_id)
if his.is_empty() {
raise @error.Business("流程设计没有内容,无法发布")
}
let content = his[0].content
let model = @parser.parse_model(content)
// 按 name 最新 define:有则替换(继承原 version,C29/issues/59)无则新建
let query = @model.PageQuery::new(1L, 1L)
query.add_filter(@model.QueryFilter::make("t", @model.Eq, "name", model.name))
let page = (self.repo).page_defines(query)
let define_id : Int64 = if page.rows().is_empty() {
self.save_deployed_define(model, content)
} else {
let last = page.rows()[0]
let define = (self.repo).find_define_by_id(last.id).unwrap()
let updated : @model.ProcessDefine = { ..define,
name: model.name,
display_name: model.display_name,
define_type: model.model_type,
content,
// 保留原 version(禁 null→1 漂移,C29/issues/59)
version: last.version,
update_user: Some(arg_str_or(args, "operator", "system")),
}
(self.repo).update_define(updated)
last.id
}
design.is_deployed = 1
design.update_user = Some(arg_str_or(args, "operator", "system"))
ext.update_design(design)
let o = @json.empty_object()
@json.obj_set(o, "processDefineId", i64_json(define_id))
o
}
///|
/// deploy 版本管理:按 name 最新 version+1 插入 state=1(java saveDeployedDefine)
async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::save_deployed_define(self : Facade[R, E], model : @parser.ProcessModel, content : String) -> Int64 raise @error.JeeflowError {
let query = @model.PageQuery::new(1L, 1L)
query.add_filter(@model.QueryFilter::make("t", @model.Eq, "name", model.name))
let page = (self.repo).page_defines(query)
let version = if page.rows().is_empty() {
0
} else {
page.rows()[0].version + 1
}
let define : @model.ProcessDefine = {
id: 0L,
name: model.name,
display_name: model.display_name,
define_type: model.model_type,
state: 1,
content,
version,
create_time: Some(@model.current_time_str()),
create_user: Some("system"),
update_time: None,
update_user: None,
}
(self.repo).save_define(define)
define.id
}
///|
/// listByType:发起页数据契约(issues/28;分组契约 C14)
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::design_list_by_type(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let query = @model.PageQuery::new(1L, 2147483646L)
let design_page = ext.page_designs(query)
let def_query = @model.PageQuery::new(1L, 2147483646L)
let def_page = (self.repo).page_defines(def_query)
// 每 name 最新 define(version 最大)
let latest : Map[String, @model.DefineRow] = Map::new()
for row in def_page.rows() {
match latest.get(row.name) {
Some(prev) => if row.version > prev.version { latest[row.name] = row }
None => latest[row.name] = row
}
}
let groups : Map[String, Json] = Map::new()
for d in design_page.rows() {
let dtype = d.design_type
let items = match groups.get(dtype) {
Some(arr) => arr
None => {
let arr = @json.empty_array()
groups[dtype] = arr
arr
}
}
let item = @json.empty_object()
@json.obj_set(item, "processDesignId", i64_json(d.id))
@json.obj_set(item, "name", @json.string_of(d.name))
@json.obj_set(item, "displayName", @json.string_of(d.display_name))
@json.obj_set(item, "icon", opt_json(d.icon))
@json.obj_set(item, "remark", opt_json(d.remark))
match latest.get(d.name) {
Some(l) => {
@json.obj_set(item, "processDefineId", i64_json(l.id))
@json.obj_set(item, "processDefineState", num_json(l.state))
}
None => {
@json.obj_set(item, "processDefineId", @json.null_json())
@json.obj_set(item, "processDefineState", @json.null_json())
}
}
let his = ext.list_design_his(d.id)
if !his.is_empty() {
@json.obj_set(item, "jsonObject", opt_json_wrap(parse_graph(his[0].content)))
}
@json.arr_push(items, item)
}
obj_json(groups)
}
// ═══ 委托代理 ═══
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::surrogate_page(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let page_num = arg_i64_or(args, "pageNum", 1L)
let page_size = arg_i64_or(args, "pageSize", 20L)
let filters = facade_parse_m_filters(args)
let page = (self.ext()).page_surrogates(@model.PageQuery::new(page_num, page_size))
finalize_page(page, surrogate_to_json, filters, page_num, page_size)
}
///|
/// 时间窗双格式解析(C26:空格 / ISO T)
fn parse_surrogate_time(s : String?) -> String? {
match s {
Some(raw) => {
let t = raw.trim(chars=" \t\r\n").to_string()
if t.is_empty() {
return None
}
if t.length() >= 19 {
let bytes = t.to_array()
if bytes[10] == 'T' {
return Some(t.substring(start=0, end=10).to_string() + " " + t.substring(start=11, end=19).to_string())
}
return Some(t.substring(start=0, end=19).to_string())
}
Some(t)
}
None => None
}
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::surrogate_save(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let operator = arg_str_or(args, "operator", "user1")
let id = arg_i64(args, "id")
let surrogate : @model.ProcessSurrogate = match id {
None => {
let s : @model.ProcessSurrogate = {
id: 0L,
process_name: arg_str(args, "processName").unwrap_or(""),
operator,
surrogate: arg_str(args, "surrogate").unwrap_or(""),
start_time: parse_surrogate_time(arg_str(args, "startTime")),
end_time: parse_surrogate_time(arg_str(args, "endTime")),
enabled: arg_i64_or(args, "enabled", 1L) |> _.to_int(),
create_time: Some(@model.current_time_str()),
create_user: Some(operator),
update_time: None,
update_user: Some(operator),
}
s
}
Some(i) => {
let s = match ext.find_surrogate_by_id(i) {
Some(x) => x
None => raise @error.Business("委托记录不存在")
}
self.apply_surrogate_fields(s, args, operator)
s
}
}
if id is None {
ext.save_surrogate(surrogate)
} else {
ext.update_surrogate(surrogate)
}
let o = @json.empty_object()
@json.obj_set(o, "id", i64_json(surrogate.id))
o
}
///|
fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::apply_surrogate_fields(self : Facade[R, E], s : @model.ProcessSurrogate, args : Map[String, Json], operator : String) -> Unit raise @error.JeeflowError {
let _ = self
match arg_str(args, "processName") {
Some(v) => s.process_name = v
None => ()
}
// 授权人仅显式传入时覆盖(issues/77 不清空原授权人)
match arg_str(args, "operator") {
Some(v) => s.operator = v
None => ()
}
match arg_str(args, "surrogate") {
Some(v) => s.surrogate = v
None => ()
}
s.start_time = parse_surrogate_time(arg_str(args, "startTime"))
s.end_time = parse_surrogate_time(arg_str(args, "endTime"))
// C26:enabled=0 不得折叠成 1
match arg_i64(args, "enabled") {
Some(v) => s.enabled = v.to_int()
None => s.enabled = 1
}
s.update_user = Some(operator)
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::surrogate_update(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let ext = self.ext()
let operator = arg_str_or(args, "operator", "user1")
let id = match arg_i64(args, "id") {
Some(v) => v
None => raise @error.Business("id 缺失")
}
let surrogate = match ext.find_surrogate_by_id(id) {
Some(s) => s
None => raise @error.Business("委托记录不存在")
}
self.apply_surrogate_fields(surrogate, args, operator)
ext.update_surrogate(surrogate)
let o = @json.empty_object()
@json.obj_set(o, "id", i64_json(surrogate.id))
o
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::surrogate_detail(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let id = match arg_i64(args, "id") {
Some(v) => v
None => raise @error.Business("缺少id参数")
}
match (self.ext()).find_surrogate_by_id(id) {
Some(s) => surrogate_to_json(s)
None => raise @error.Business("委托记录不存在")
}
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::surrogate_remove(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
for id in arg_ids(args) {
(self.ext()).remove_surrogate(id)
}
@json.null_json()
}
// ═══ 视图:bizData / highLight ═══
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::biz_data(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let instance_id = match arg_id(args, ["processInstanceId", "id"]) {
Some(v) => v
None => raise @error.Business("processInstanceId 缺失")
}
let inst = match (self.repo).find_instance_by_id(instance_id) {
Some(i) => i
None => raise @error.InstanceNotFound(instance_id)
}
let define = match (self.repo).find_define_by_id(inst.define_id) {
Some(d) => d
None => raise @error.DefineNotFound(inst.define_id)
}
// relTableName 从 content 顶层解析(回落 name)
let table = match rel_table_name_of(define.content) {
Some(t) => t
None => raise @error.Business("流程定义未配置 relTableName")
}
// metaTableReader 未注册显式报错(issues/28)
match self.engine.context().biz_data_reader {
Some(reader) => {
let outcome = try? (reader)(table, instance_id)
match outcome {
Ok(rows) => match rows {
Some(row) => obj_json(row)
None => @json.null_json()
}
Err(e) => raise @error.Business("业务数据读取失败: \{e.message()}")
}
}
None => raise @error.Business("业务数据读取器未注册(ServiceContext.put(\"metaTableReader\", ...),需引入 jeeflow-persist)")
}
}
///|
fn rel_table_name_of(content : String) -> String? {
match parse_graph(content) {
Some(meta) => {
let t = @json.get_str(meta, "relTableName")
match t {
Some(s) => if !s.trim(chars=" \t\r\n").is_empty() { Some(s.trim(chars=" \t\r\n").to_string()) } else { rel_fallback_name(meta) }
None => rel_fallback_name(meta)
}
}
None => None
}
}
///|
fn rel_fallback_name(meta : Json) -> String? {
match @json.get_str(meta, "name") {
Some(s) => if !s.trim(chars=" \t\r\n").is_empty() { Some(s.trim(chars=" \t\r\n").to_string()) } else { None }
None => None
}
}
///|
pub async fn[R : @spi.ProcessRepository, E : @spi.ProcessExtRepository] Facade::high_light(self : Facade[R, E], args : Map[String, Json]) -> Json raise @error.JeeflowError {
let id = match arg_i64(args, "id") {
Some(v) => v
None => raise @error.Business("缺少id参数")
}
let inst = match (self.repo).find_instance_by_id(id) {
Some(i) => i
None => raise @error.InstanceNotFound(id)
}
let active : Array[String] = []
let doing = (self.repo).find_doing_tasks(id, [])
for t in doing {
if !active.contains(t.task_name) {
active.push(t.task_name)
}
}
let history = (self.repo).find_history_tasks(id)
let history_nodes : Array[String] = []
for t in history {
if !active.contains(t.task_name) && !history_nodes.contains(t.task_name) {
history_nodes.push(t.task_name)
}
}
let define = (self.repo).find_define_by_id(inst.define_id)
let node_progress = @json.empty_object()
let edges : Array[String] = []
match define {
Some(d) => {
let outcome = try? @parser.parse_model(d.content)
match outcome {
Ok(model) => {
build_node_progress(model, history, node_progress)
collect_path(model, model.get_start(), active, history_nodes, edges, inst.variables, history)
}
Err(_) => ()
}
}
None => ()
}
let o = @json.empty_object()
let active_arr = @json.empty_array()
for n in active {
@json.arr_push(active_arr, @json.string_of(n))
}
@json.obj_set(o, "activeNodeNames", active_arr)
let hist_arr = @json.empty_array()
for n in history_nodes {
@json.arr_push(hist_arr, @json.string_of(n))
}
@json.obj_set(o, "historyNodeNames", hist_arr)
let edge_arr = @json.empty_array()
for n in edges {
@json.arr_push(edge_arr, @json.string_of(n))
}
@json.obj_set(o, "historyEdgeNames", edge_arr)
@json.obj_set(o, "nodeProgress", node_progress)
o
}
///|
fn build_node_progress(
model : @parser.ProcessModel,
history : Array[@model.ProcessTask],
out : Json
) -> Unit {
// 节点顺序(history 首现序)
let names : Array[String] = []
let seen : Map[String, Unit] = Map::new()
for t in history {
if seen.get(t.task_name) is None {
seen[t.task_name] = ()
names.push(t.task_name)
}
}
for name in names {
let ts : Array[@model.ProcessTask] = []
for t in history {
if t.task_name == name {
ts.push(t)
}
}
if ts.is_empty() {
continue
}
// 会签全量办理人:任务变量 operatorList_{node} 优先(C9/issues/93),否则 actorIds 并集
let mut members : Array[String] = []
let op_key = "csv_\{name}_operatorList"
for t in ts {
match t.variables.get_str(op_key) {
Some(list) => {
members = split_comma(list)
break
}
None => ()
}
}
if members.is_empty() {
for t in ts {
for a in t.actor_ids {
if !members.contains(a) {
members.push(a)
}
}
}
}
if members.is_empty() {
continue
}
// 会签判定 + 类型
var is_cs = false
var cs_type = ""
match model.get_node(name) {
Some(node) => {
is_cs = node.is_countersign()
cs_type = node.countersign_type()
}
None => ()
}
let member_list = @json.empty_array()
for id in members {
let m = @json.empty_object()
@json.obj_set(m, "id", @json.string_of(id))
// name 解析由调用方注入 user provider 前�先空串(前端降级显示 id)
@json.obj_set(m, "name", @json.string_of(""))
var done = false
for t in ts {
if t.task_state == 20 && t.actor_ids.contains(id) {
done = true
}
}
if done {
@json.obj_set(m, "done", @json.bool_of(true))
} else {
for t in ts {
if t.task_state == 10 && !t.actor_ids.is_empty() && t.actor_ids[0] == id {
@json.obj_set(m, "active", @json.bool_of(true))
}
}
}
@json.arr_push(member_list, m)
}
let item = @json.empty_object()
@json.obj_set(item, "members", member_list)
if is_cs && !cs_type.is_empty() {
@json.obj_set(item, "type", @json.string_of(cs_type))
}
@json.obj_set(out, name, item)
}
}
///|
/// 路径补全:start 沿 outputs 递归,遇活跃节点停止;决策节点表达式求值只收 true 边(C14)
fn collect_path(
model : @parser.ProcessModel,
node : @parser.NodeModel?,
active : Array[String],
history : Array[String],
edges : Array[String],
instance_vars : @json.FlowData,
history_tasks : Array[@model.ProcessTask]
) -> Unit {
match node {
Some(n) => {
for tm in model.get_output_edges(n.id) {
let edge_name = match tm.label {
Some(l) => Some(l)
None => Some(tm.id)
}
match edge_name {
Some(en) => if !edges.contains(en) { edges.push(en) }
None => ()
}
let next = model.get_target_node(tm)
match next {
Some(nx) => {
if !active.contains(nx.id) && !history.contains(nx.id) {
history.push(nx.id)
}
if !active.contains(nx.id) {
collect_path(model, Some(nx), active, history, edges, instance_vars, history_tasks)
}
}
None => ()
}
}
}
None => ()
}
}