Skip to content
kata / a language workbench

Result pipeline

Divide a quantity among teams, then among people, while requiring every share to be a nonnegative whole number. Invalid inputs become Res.Err values.

func divide_evenly(total: Int, groups: Int): Res[Int, Str] {
if groups <= 0 { ret Res[Int, Str].Err("group count must be positive") }
if total < 0 { ret Res[Int, Str].Err("total must be nonnegative") }
if total % groups != 0 { ret Res[Int, Str].Err("cannot divide evenly") }
ret Res[Int, Str].Val(total / groups)
}
func per_person(total: Int, teams: Int, people: Int): Res[Int, Str] {
let per_team = divide_evenly(total, teams)?
let share = divide_evenly(per_team, people)?
ret Res[Int, Str].Val(share)
}
func report(result: Res[Int, Str]) {
match result {
Val(amount) -> print("each person gets {amount}"),
Err(reason) -> print("cannot share: {reason}"),
}
}
report(per_person(120, 3, 4))
report(per_person(120, 0, 4))
report(per_person(100, 3, 4))
report(per_person(120, 3, 0))
Original example: checked output and syntax tree

These records belong to the original downloadable program. Run the editor above to see results for your changes.

each person gets 10
cannot share: group count must be positive
cannot share: cannot divide evenly
cannot share: group count must be positive
Original AST
[
  {
    "node": {
      "FuncDef": {
        "name": {
          "node": "divide_evenly",
          "span": [
            5,
            18
          ]
        },
        "params": [
          {
            "name": {
              "node": "total",
              "span": [
                19,
                24
              ]
            },
            "type_ann": {
              "node": {
                "Name": "Int"
              },
              "span": [
                26,
                29
              ]
            }
          },
          {
            "name": {
              "node": "groups",
              "span": [
                31,
                37
              ]
            },
            "type_ann": {
              "node": {
                "Name": "Int"
              },
              "span": [
                39,
                42
              ]
            }
          }
        ],
        "ret_type": {
          "node": {
            "Item": {
              "object": {
                "node": {
                  "Name": "Res"
                },
                "span": [
                  45,
                  48
                ]
              },
              "args": [
                {
                  "node": {
                    "Name": "Int"
                  },
                  "span": [
                    49,
                    52
                  ]
                },
                {
                  "node": {
                    "Name": "Str"
                  },
                  "span": [
                    54,
                    57
                  ]
                }
              ]
            }
          },
          "span": [
            45,
            58
          ]
        },
        "body": [
          {
            "node": {
              "Expr": {
                "node": {
                  "If": {
                    "cond": {
                      "node": {
                        "BinOp": {
                          "op": "Le",
                          "left": {
                            "node": {
                              "Name": "groups"
                            },
                            "span": [
                              68,
                              74
                            ]
                          },
                          "right": {
                            "node": {
                              "Int": "0"
                            },
                            "span": [
                              78,
                              79
                            ]
                          }
                        }
                      },
                      "span": [
                        68,
                        79
                      ]
                    },
                    "then_body": [
                      {
                        "node": {
                          "Ret": {
                            "keyword": [
                              82,
                              85
                            ],
                            "value": {
                              "node": {
                                "Call": {
                                  "callee": {
                                    "node": {
                                      "Attr": {
                                        "object": {
                                          "node": {
                                            "Item": {
                                              "object": {
                                                "node": {
                                                  "Name": "Res"
                                                },
                                                "span": [
                                                  86,
                                                  89
                                                ]
                                              },
                                              "args": [
                                                {
                                                  "node": {
                                                    "Name": "Int"
                                                  },
                                                  "span": [
                                                    90,
                                                    93
                                                  ]
                                                },
                                                {
                                                  "node": {
                                                    "Name": "Str"
                                                  },
                                                  "span": [
                                                    95,
                                                    98
                                                  ]
                                                }
                                              ]
                                            }
                                          },
                                          "span": [
                                            86,
                                            99
                                          ]
                                        },
                                        "name": "Err",
                                        "name_span": [
                                          100,
                                          103
                                        ]
                                      }
                                    },
                                    "span": [
                                      86,
                                      103
                                    ]
                                  },
                                  "args": [
                                    {
                                      "node": {
                                        "Str": "group count must be positive"
                                      },
                                      "span": [
                                        104,
                                        134
                                      ]
                                    }
                                  ],
                                  "args_span": [
                                    103,
                                    135
                                  ]
                                }
                              },
                              "span": [
                                86,
                                135
                              ]
                            }
                          }
                        },
                        "span": [
                          82,
                          135
                        ]
                      }
                    ],
                    "else_body": null
                  }
                },
                "span": [
                  65,
                  137
                ]
              }
            },
            "span": [
              65,
              137
            ]
          },
          {
            "node": {
              "Expr": {
                "node": {
                  "If": {
                    "cond": {
                      "node": {
                        "BinOp": {
                          "op": "Lt",
                          "left": {
                            "node": {
                              "Name": "total"
                            },
                            "span": [
                              145,
                              150
                            ]
                          },
                          "right": {
                            "node": {
                              "Int": "0"
                            },
                            "span": [
                              153,
                              154
                            ]
                          }
                        }
                      },
                      "span": [
                        145,
                        154
                      ]
                    },
                    "then_body": [
                      {
                        "node": {
                          "Ret": {
                            "keyword": [
                              157,
                              160
                            ],
                            "value": {
                              "node": {
                                "Call": {
                                  "callee": {
                                    "node": {
                                      "Attr": {
                                        "object": {
                                          "node": {
                                            "Item": {
                                              "object": {
                                                "node": {
                                                  "Name": "Res"
                                                },
                                                "span": [
                                                  161,
                                                  164
                                                ]
                                              },
                                              "args": [
                                                {
                                                  "node": {
                                                    "Name": "Int"
                                                  },
                                                  "span": [
                                                    165,
                                                    168
                                                  ]
                                                },
                                                {
                                                  "node": {
                                                    "Name": "Str"
                                                  },
                                                  "span": [
                                                    170,
                                                    173
                                                  ]
                                                }
                                              ]
                                            }
                                          },
                                          "span": [
                                            161,
                                            174
                                          ]
                                        },
                                        "name": "Err",
                                        "name_span": [
                                          175,
                                          178
                                        ]
                                      }
                                    },
                                    "span": [
                                      161,
                                      178
                                    ]
                                  },
                                  "args": [
                                    {
                                      "node": {
                                        "Str": "total must be nonnegative"
                                      },
                                      "span": [
                                        179,
                                        206
                                      ]
                                    }
                                  ],
                                  "args_span": [
                                    178,
                                    207
                                  ]
                                }
                              },
                              "span": [
                                161,
                                207
                              ]
                            }
                          }
                        },
                        "span": [
                          157,
                          207
                        ]
                      }
                    ],
                    "else_body": null
                  }
                },
                "span": [
                  142,
                  209
                ]
              }
            },
            "span": [
              142,
              209
            ]
          },
          {
            "node": {
              "Expr": {
                "node": {
                  "If": {
                    "cond": {
                      "node": {
                        "BinOp": {
                          "op": "Ne",
                          "left": {
                            "node": {
                              "BinOp": {
                                "op": "Mod",
                                "left": {
                                  "node": {
                                    "Name": "total"
                                  },
                                  "span": [
                                    217,
                                    222
                                  ]
                                },
                                "right": {
                                  "node": {
                                    "Name": "groups"
                                  },
                                  "span": [
                                    225,
                                    231
                                  ]
                                }
                              }
                            },
                            "span": [
                              217,
                              231
                            ]
                          },
                          "right": {
                            "node": {
                              "Int": "0"
                            },
                            "span": [
                              235,
                              236
                            ]
                          }
                        }
                      },
                      "span": [
                        217,
                        236
                      ]
                    },
                    "then_body": [
                      {
                        "node": {
                          "Ret": {
                            "keyword": [
                              239,
                              242
                            ],
                            "value": {
                              "node": {
                                "Call": {
                                  "callee": {
                                    "node": {
                                      "Attr": {
                                        "object": {
                                          "node": {
                                            "Item": {
                                              "object": {
                                                "node": {
                                                  "Name": "Res"
                                                },
                                                "span": [
                                                  243,
                                                  246
                                                ]
                                              },
                                              "args": [
                                                {
                                                  "node": {
                                                    "Name": "Int"
                                                  },
                                                  "span": [
                                                    247,
                                                    250
                                                  ]
                                                },
                                                {
                                                  "node": {
                                                    "Name": "Str"
                                                  },
                                                  "span": [
                                                    252,
                                                    255
                                                  ]
                                                }
                                              ]
                                            }
                                          },
                                          "span": [
                                            243,
                                            256
                                          ]
                                        },
                                        "name": "Err",
                                        "name_span": [
                                          257,
                                          260
                                        ]
                                      }
                                    },
                                    "span": [
                                      243,
                                      260
                                    ]
                                  },
                                  "args": [
                                    {
                                      "node": {
                                        "Str": "cannot divide evenly"
                                      },
                                      "span": [
                                        261,
                                        283
                                      ]
                                    }
                                  ],
                                  "args_span": [
                                    260,
                                    284
                                  ]
                                }
                              },
                              "span": [
                                243,
                                284
                              ]
                            }
                          }
                        },
                        "span": [
                          239,
                          284
                        ]
                      }
                    ],
                    "else_body": null
                  }
                },
                "span": [
                  214,
                  286
                ]
              }
            },
            "span": [
              214,
              286
            ]
          },
          {
            "node": {
              "Ret": {
                "keyword": [
                  291,
                  294
                ],
                "value": {
                  "node": {
                    "Call": {
                      "callee": {
                        "node": {
                          "Attr": {
                            "object": {
                              "node": {
                                "Item": {
                                  "object": {
                                    "node": {
                                      "Name": "Res"
                                    },
                                    "span": [
                                      295,
                                      298
                                    ]
                                  },
                                  "args": [
                                    {
                                      "node": {
                                        "Name": "Int"
                                      },
                                      "span": [
                                        299,
                                        302
                                      ]
                                    },
                                    {
                                      "node": {
                                        "Name": "Str"
                                      },
                                      "span": [
                                        304,
                                        307
                                      ]
                                    }
                                  ]
                                }
                              },
                              "span": [
                                295,
                                308
                              ]
                            },
                            "name": "Val",
                            "name_span": [
                              309,
                              312
                            ]
                          }
                        },
                        "span": [
                          295,
                          312
                        ]
                      },
                      "args": [
                        {
                          "node": {
                            "BinOp": {
                              "op": "Div",
                              "left": {
                                "node": {
                                  "Name": "total"
                                },
                                "span": [
                                  313,
                                  318
                                ]
                              },
                              "right": {
                                "node": {
                                  "Name": "groups"
                                },
                                "span": [
                                  321,
                                  327
                                ]
                              }
                            }
                          },
                          "span": [
                            313,
                            327
                          ]
                        }
                      ],
                      "args_span": [
                        312,
                        328
                      ]
                    }
                  },
                  "span": [
                    295,
                    328
                  ]
                }
              }
            },
            "span": [
              291,
              328
            ]
          }
        ]
      }
    },
    "span": [
      0,
      330
    ]
  },
  {
    "node": {
      "FuncDef": {
        "name": {
          "node": "per_person",
          "span": [
            336,
            346
          ]
        },
        "params": [
          {
            "name": {
              "node": "total",
              "span": [
                347,
                352
              ]
            },
            "type_ann": {
              "node": {
                "Name": "Int"
              },
              "span": [
                354,
                357
              ]
            }
          },
          {
            "name": {
              "node": "teams",
              "span": [
                359,
                364
              ]
            },
            "type_ann": {
              "node": {
                "Name": "Int"
              },
              "span": [
                366,
                369
              ]
            }
          },
          {
            "name": {
              "node": "people",
              "span": [
                371,
                377
              ]
            },
            "type_ann": {
              "node": {
                "Name": "Int"
              },
              "span": [
                379,
                382
              ]
            }
          }
        ],
        "ret_type": {
          "node": {
            "Item": {
              "object": {
                "node": {
                  "Name": "Res"
                },
                "span": [
                  385,
                  388
                ]
              },
              "args": [
                {
                  "node": {
                    "Name": "Int"
                  },
                  "span": [
                    389,
                    392
                  ]
                },
                {
                  "node": {
                    "Name": "Str"
                  },
                  "span": [
                    394,
                    397
                  ]
                }
              ]
            }
          },
          "span": [
            385,
            398
          ]
        },
        "body": [
          {
            "node": {
              "Let": {
                "pattern": {
                  "node": {
                    "Binding": {
                      "node": "per_team",
                      "span": [
                        409,
                        417
                      ]
                    }
                  },
                  "span": [
                    409,
                    417
                  ]
                },
                "type_ann": null,
                "value": {
                  "node": {
                    "Ques": {
                      "node": {
                        "Call": {
                          "callee": {
                            "node": {
                              "Name": "divide_evenly"
                            },
                            "span": [
                              420,
                              433
                            ]
                          },
                          "args": [
                            {
                              "node": {
                                "Name": "total"
                              },
                              "span": [
                                434,
                                439
                              ]
                            },
                            {
                              "node": {
                                "Name": "teams"
                              },
                              "span": [
                                441,
                                446
                              ]
                            }
                          ],
                          "args_span": [
                            433,
                            447
                          ]
                        }
                      },
                      "span": [
                        420,
                        447
                      ]
                    }
                  },
                  "span": [
                    420,
                    448
                  ]
                }
              }
            },
            "span": [
              405,
              448
            ]
          },
          {
            "node": {
              "Let": {
                "pattern": {
                  "node": {
                    "Binding": {
                      "node": "share",
                      "span": [
                        457,
                        462
                      ]
                    }
                  },
                  "span": [
                    457,
                    462
                  ]
                },
                "type_ann": null,
                "value": {
                  "node": {
                    "Ques": {
                      "node": {
                        "Call": {
                          "callee": {
                            "node": {
                              "Name": "divide_evenly"
                            },
                            "span": [
                              465,
                              478
                            ]
                          },
                          "args": [
                            {
                              "node": {
                                "Name": "per_team"
                              },
                              "span": [
                                479,
                                487
                              ]
                            },
                            {
                              "node": {
                                "Name": "people"
                              },
                              "span": [
                                489,
                                495
                              ]
                            }
                          ],
                          "args_span": [
                            478,
                            496
                          ]
                        }
                      },
                      "span": [
                        465,
                        496
                      ]
                    }
                  },
                  "span": [
                    465,
                    497
                  ]
                }
              }
            },
            "span": [
              453,
              497
            ]
          },
          {
            "node": {
              "Ret": {
                "keyword": [
                  502,
                  505
                ],
                "value": {
                  "node": {
                    "Call": {
                      "callee": {
                        "node": {
                          "Attr": {
                            "object": {
                              "node": {
                                "Item": {
                                  "object": {
                                    "node": {
                                      "Name": "Res"
                                    },
                                    "span": [
                                      506,
                                      509
                                    ]
                                  },
                                  "args": [
                                    {
                                      "node": {
                                        "Name": "Int"
                                      },
                                      "span": [
                                        510,
                                        513
                                      ]
                                    },
                                    {
                                      "node": {
                                        "Name": "Str"
                                      },
                                      "span": [
                                        515,
                                        518
                                      ]
                                    }
                                  ]
                                }
                              },
                              "span": [
                                506,
                                519
                              ]
                            },
                            "name": "Val",
                            "name_span": [
                              520,
                              523
                            ]
                          }
                        },
                        "span": [
                          506,
                          523
                        ]
                      },
                      "args": [
                        {
                          "node": {
                            "Name": "share"
                          },
                          "span": [
                            524,
                            529
                          ]
                        }
                      ],
                      "args_span": [
                        523,
                        530
                      ]
                    }
                  },
                  "span": [
                    506,
                    530
                  ]
                }
              }
            },
            "span": [
              502,
              530
            ]
          }
        ]
      }
    },
    "span": [
      331,
      532
    ]
  },
  {
    "node": {
      "FuncDef": {
        "name": {
          "node": "report",
          "span": [
            538,
            544
          ]
        },
        "params": [
          {
            "name": {
              "node": "result",
              "span": [
                545,
                551
              ]
            },
            "type_ann": {
              "node": {
                "Item": {
                  "object": {
                    "node": {
                      "Name": "Res"
                    },
                    "span": [
                      553,
                      556
                    ]
                  },
                  "args": [
                    {
                      "node": {
                        "Name": "Int"
                      },
                      "span": [
                        557,
                        560
                      ]
                    },
                    {
                      "node": {
                        "Name": "Str"
                      },
                      "span": [
                        562,
                        565
                      ]
                    }
                  ]
                }
              },
              "span": [
                553,
                566
              ]
            }
          }
        ],
        "ret_type": null,
        "body": [
          {
            "node": {
              "Expr": {
                "node": {
                  "Match": {
                    "keyword": [
                      574,
                      579
                    ],
                    "subject": {
                      "node": {
                        "Name": "result"
                      },
                      "span": [
                        580,
                        586
                      ]
                    },
                    "arms": [
                      {
                        "pattern": {
                          "node": {
                            "Variant": {
                              "name": {
                                "node": "Val",
                                "span": [
                                  597,
                                  600
                                ]
                              },
                              "bindings": [
                                {
                                  "node": {
                                    "Binding": {
                                      "node": "amount",
                                      "span": [
                                        601,
                                        607
                                      ]
                                    }
                                  },
                                  "span": [
                                    601,
                                    607
                                  ]
                                }
                              ]
                            }
                          },
                          "span": [
                            597,
                            608
                          ]
                        },
                        "body": [
                          {
                            "node": {
                              "Expr": {
                                "node": {
                                  "Call": {
                                    "callee": {
                                      "node": {
                                        "Name": "print"
                                      },
                                      "span": [
                                        612,
                                        617
                                      ]
                                    },
                                    "args": [
                                      {
                                        "node": {
                                          "Interp": {
                                            "parts": [
                                              {
                                                "Lit": "each person gets "
                                              },
                                              {
                                                "Expr": {
                                                  "node": {
                                                    "Name": "amount"
                                                  },
                                                  "span": [
                                                    637,
                                                    643
                                                  ]
                                                }
                                              }
                                            ]
                                          }
                                        },
                                        "span": [
                                          618,
                                          645
                                        ]
                                      }
                                    ],
                                    "args_span": [
                                      617,
                                      646
                                    ]
                                  }
                                },
                                "span": [
                                  612,
                                  646
                                ]
                              }
                            },
                            "span": [
                              612,
                              646
                            ]
                          }
                        ]
                      },
                      {
                        "pattern": {
                          "node": {
                            "Variant": {
                              "name": {
                                "node": "Err",
                                "span": [
                                  656,
                                  659
                                ]
                              },
                              "bindings": [
                                {
                                  "node": {
                                    "Binding": {
                                      "node": "reason",
                                      "span": [
                                        660,
                                        666
                                      ]
                                    }
                                  },
                                  "span": [
                                    660,
                                    666
                                  ]
                                }
                              ]
                            }
                          },
                          "span": [
                            656,
                            667
                          ]
                        },
                        "body": [
                          {
                            "node": {
                              "Expr": {
                                "node": {
                                  "Call": {
                                    "callee": {
                                      "node": {
                                        "Name": "print"
                                      },
                                      "span": [
                                        671,
                                        676
                                      ]
                                    },
                                    "args": [
                                      {
                                        "node": {
                                          "Interp": {
                                            "parts": [
                                              {
                                                "Lit": "cannot share: "
                                              },
                                              {
                                                "Expr": {
                                                  "node": {
                                                    "Name": "reason"
                                                  },
                                                  "span": [
                                                    693,
                                                    699
                                                  ]
                                                }
                                              }
                                            ]
                                          }
                                        },
                                        "span": [
                                          677,
                                          701
                                        ]
                                      }
                                    ],
                                    "args_span": [
                                      676,
                                      702
                                    ]
                                  }
                                },
                                "span": [
                                  671,
                                  702
                                ]
                              }
                            },
                            "span": [
                              671,
                              702
                            ]
                          }
                        ]
                      }
                    ]
                  }
                },
                "span": [
                  574,
                  709
                ]
              }
            },
            "span": [
              574,
              709
            ]
          }
        ]
      }
    },
    "span": [
      533,
      711
    ]
  },
  {
    "node": {
      "Expr": {
        "node": {
          "Call": {
            "callee": {
              "node": {
                "Name": "report"
              },
              "span": [
                712,
                718
              ]
            },
            "args": [
              {
                "node": {
                  "Call": {
                    "callee": {
                      "node": {
                        "Name": "per_person"
                      },
                      "span": [
                        719,
                        729
                      ]
                    },
                    "args": [
                      {
                        "node": {
                          "Int": "120"
                        },
                        "span": [
                          730,
                          733
                        ]
                      },
                      {
                        "node": {
                          "Int": "3"
                        },
                        "span": [
                          735,
                          736
                        ]
                      },
                      {
                        "node": {
                          "Int": "4"
                        },
                        "span": [
                          738,
                          739
                        ]
                      }
                    ],
                    "args_span": [
                      729,
                      740
                    ]
                  }
                },
                "span": [
                  719,
                  740
                ]
              }
            ],
            "args_span": [
              718,
              741
            ]
          }
        },
        "span": [
          712,
          741
        ]
      }
    },
    "span": [
      712,
      741
    ]
  },
  {
    "node": {
      "Expr": {
        "node": {
          "Call": {
            "callee": {
              "node": {
                "Name": "report"
              },
              "span": [
                742,
                748
              ]
            },
            "args": [
              {
                "node": {
                  "Call": {
                    "callee": {
                      "node": {
                        "Name": "per_person"
                      },
                      "span": [
                        749,
                        759
                      ]
                    },
                    "args": [
                      {
                        "node": {
                          "Int": "120"
                        },
                        "span": [
                          760,
                          763
                        ]
                      },
                      {
                        "node": {
                          "Int": "0"
                        },
                        "span": [
                          765,
                          766
                        ]
                      },
                      {
                        "node": {
                          "Int": "4"
                        },
                        "span": [
                          768,
                          769
                        ]
                      }
                    ],
                    "args_span": [
                      759,
                      770
                    ]
                  }
                },
                "span": [
                  749,
                  770
                ]
              }
            ],
            "args_span": [
              748,
              771
            ]
          }
        },
        "span": [
          742,
          771
        ]
      }
    },
    "span": [
      742,
      771
    ]
  },
  {
    "node": {
      "Expr": {
        "node": {
          "Call": {
            "callee": {
              "node": {
                "Name": "report"
              },
              "span": [
                772,
                778
              ]
            },
            "args": [
              {
                "node": {
                  "Call": {
                    "callee": {
                      "node": {
                        "Name": "per_person"
                      },
                      "span": [
                        779,
                        789
                      ]
                    },
                    "args": [
                      {
                        "node": {
                          "Int": "100"
                        },
                        "span": [
                          790,
                          793
                        ]
                      },
                      {
                        "node": {
                          "Int": "3"
                        },
                        "span": [
                          795,
                          796
                        ]
                      },
                      {
                        "node": {
                          "Int": "4"
                        },
                        "span": [
                          798,
                          799
                        ]
                      }
                    ],
                    "args_span": [
                      789,
                      800
                    ]
                  }
                },
                "span": [
                  779,
                  800
                ]
              }
            ],
            "args_span": [
              778,
              801
            ]
          }
        },
        "span": [
          772,
          801
        ]
      }
    },
    "span": [
      772,
      801
    ]
  },
  {
    "node": {
      "Expr": {
        "node": {
          "Call": {
            "callee": {
              "node": {
                "Name": "report"
              },
              "span": [
                802,
                808
              ]
            },
            "args": [
              {
                "node": {
                  "Call": {
                    "callee": {
                      "node": {
                        "Name": "per_person"
                      },
                      "span": [
                        809,
                        819
                      ]
                    },
                    "args": [
                      {
                        "node": {
                          "Int": "120"
                        },
                        "span": [
                          820,
                          823
                        ]
                      },
                      {
                        "node": {
                          "Int": "3"
                        },
                        "span": [
                          825,
                          826
                        ]
                      },
                      {
                        "node": {
                          "Int": "0"
                        },
                        "span": [
                          828,
                          829
                        ]
                      }
                    ],
                    "args_span": [
                      819,
                      830
                    ]
                  }
                },
                "span": [
                  809,
                  830
                ]
              }
            ],
            "args_span": [
              808,
              831
            ]
          }
        },
        "span": [
          802,
          831
        ]
      }
    },
    "span": [
      802,
      831
    ]
  }
]
Download original result-pipeline.ks ↓

divide_evenly owns the arithmetic contract. It rejects invalid divisors and totals before using division, then rejects any nonzero remainder.

per_person owns composition. Each ? either extracts the successful share or returns the failure unchanged. Both stages use Res[Int, Str], so propagation fits the enclosing function’s return type.

report owns presentation. Its match prints success and failure without asking arithmetic code to decide how an error should be shown.

The result tutorial walks through the contract and suggests boundary cases you can test.