Compare commits

..

42 Commits

Author SHA1 Message Date
dependabot-preview[bot]
5ed4f8795a Bump github.com/gobuffalo/packr/v2 from 2.5.1 to 2.8.0 (#476)
Bumps [github.com/gobuffalo/packr/v2](https://github.com/gobuffalo/packr) from 2.5.1 to 2.8.0.
- [Release notes](https://github.com/gobuffalo/packr/releases)
- [Changelog](https://github.com/gobuffalo/packr/blob/master/.goreleaser.yml)
- [Commits](https://github.com/gobuffalo/packr/compare/v2.5.1...v2.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-11 11:48:19 +08:00
dependabot-preview[bot]
a02e7e66af Bump github.com/urfave/cli from 1.22.2 to 1.22.3 (#477)
Bumps [github.com/urfave/cli](https://github.com/urfave/cli) from 1.22.2 to 1.22.3.
- [Release notes](https://github.com/urfave/cli/releases)
- [Changelog](https://github.com/urfave/cli/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/urfave/cli/compare/v1.22.2...v1.22.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Minghe <h.minghe@gmail.com>
2020-03-11 11:48:02 +08:00
dependabot-preview[bot]
9c1d093bb8 Bump github.com/otiai10/copy from 1.0.2 to 1.1.1 (#474)
Bumps [github.com/otiai10/copy](https://github.com/otiai10/copy) from 1.0.2 to 1.1.1.
- [Release notes](https://github.com/otiai10/copy/releases)
- [Commits](https://github.com/otiai10/copy/compare/v1.0.2...v1.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Minghe <h.minghe@gmail.com>
2020-03-11 09:12:51 +08:00
Minghe
302877d4b4 Fn and deps (#475) 2020-03-11 08:59:47 +08:00
Minghe
871bb29dbe Bundler (#473)
* refactor bundler
* enable unit test
2020-03-10 22:49:14 +08:00
Minghe Huang
3be144f644 clean up no need files 2020-03-10 10:18:07 +08:00
Minghe
2560dc23fc fix the wrong destination of copy issue (#466)
* fix the wrong destination of copy issue
* bump up version
2020-03-01 15:58:45 +08:00
dependabot-preview[bot]
3d6c3d10bf Bump github.com/golang/mock from 1.4.0 to 1.4.1 (#464)
Bumps [github.com/golang/mock](https://github.com/golang/mock) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/golang/mock/releases)
- [Changelog](https://github.com/golang/mock/blob/master/.goreleaser.yml)
- [Commits](https://github.com/golang/mock/compare/v1.4.0...v1.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-28 09:27:02 +08:00
Minghe
5f811693f1 bump up version 2020-02-21 17:28:07 +08:00
Minghe
0068fb92eb support 'format' option in 'fx list' (#462) 2020-02-21 17:26:39 +08:00
dependabot-preview[bot]
71174ead45 Bump github.com/stretchr/testify from 1.4.0 to 1.5.1 (#459)
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.4.0 to 1.5.1.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.4.0...v1.5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-21 15:10:47 +08:00
dependabot-preview[bot]
43c18caceb Bump github.com/briandowns/spinner from 1.7.0 to 1.9.0 (#457)
Bumps [github.com/briandowns/spinner](https://github.com/briandowns/spinner) from 1.7.0 to 1.9.0.
- [Release notes](https://github.com/briandowns/spinner/releases)
- [Commits](https://github.com/briandowns/spinner/compare/v1.7.0...v1.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 11:03:24 +08:00
dependabot-preview[bot]
7b4c9c3154 Bump github.com/spf13/viper from 1.6.1 to 1.6.2 (#451)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.6.1 to 1.6.2.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.6.1...v1.6.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-11 20:46:02 +08:00
dependabot-preview[bot]
9d2649433d Bump github.com/golang/mock from 1.3.1 to 1.4.0 (#452)
Bumps [github.com/golang/mock](https://github.com/golang/mock) from 1.3.1 to 1.4.0.
- [Release notes](https://github.com/golang/mock/releases)
- [Changelog](https://github.com/golang/mock/blob/master/.goreleaser.yml)
- [Commits](https://github.com/golang/mock/compare/1.3.1...v1.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: Minghe <h.minghe@gmail.com>
2020-02-11 20:44:41 +08:00
dependabot-preview[bot]
6353fa7dd3 Bump github.com/apex/log from 1.1.1 to 1.1.2 (#453)
Bumps [github.com/apex/log](https://github.com/apex/log) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/apex/log/releases)
- [Changelog](https://github.com/apex/log/blob/master/History.md)
- [Commits](https://github.com/apex/log/compare/v1.1.1...v1.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: Minghe <h.minghe@gmail.com>
2020-02-11 20:44:01 +08:00
Minghe
bfa837c88d release 0.9.0 (#456) 2020-02-11 20:29:46 +08:00
Minghe
bdc454e7e5 support before_build hook (#455) 2020-02-11 20:26:46 +08:00
dependabot-preview[bot]
9b3e85754c Bump github.com/pkg/errors from 0.9.0 to 0.9.1 (#450)
Bumps [github.com/pkg/errors](https://github.com/pkg/errors) from 0.9.0 to 0.9.1.
- [Release notes](https://github.com/pkg/errors/releases)
- [Commits](https://github.com/pkg/errors/compare/v0.9.0...v0.9.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-15 10:09:44 +08:00
dependabot-preview[bot]
af3dcc5f31 Bump github.com/pkg/errors from 0.8.1 to 0.9.0 (#449)
Bumps [github.com/pkg/errors](https://github.com/pkg/errors) from 0.8.1 to 0.9.0.
- [Release notes](https://github.com/pkg/errors/releases)
- [Commits](https://github.com/pkg/errors/compare/v0.8.1...v0.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-14 08:51:29 +08:00
Minghe
c375fb9eaf check if source file or directory is ready or not (#447) 2020-01-07 15:36:23 +08:00
Minghe
70c314229f add JSON to perl base image (#446) 2020-01-03 09:53:59 +08:00
Minghe
66e23ead00 update docs (#445) 2020-01-02 23:42:43 +08:00
Minghe Huang
2e5666c2b6 Squashed commit of the following:
commit 5a9c2b5942d16b3ff7b4ed7a02dafbf2c5462eae
Author: Minghe Huang <h.minghe@gmail.com>
Date:   Thu Jan 2 17:40:23 2020 +0800

    bump version
2020-01-02 17:40:46 +08:00
Minghe
7675656a54 fix force option when deploy a function on Docker infra (#443)
* fix force option when deploy a function on Docker infra

* fix test
2020-01-02 17:13:10 +08:00
Minghe
3d7f7b0ad1 Configurable auto remove (#440)
* enable autoremove to be configurable

* bump version
2019-12-31 14:29:01 +08:00
Minghe
a1ccbd6cab Add not fetch fx node bas (#439)
* add node-fetch to fx-node-base image, then we can use 'fetch' in
JavaScript/Node function

* bump version
2019-12-31 13:34:48 +08:00
Minghe
33cb4ce63c verify deploy function to Google Kubernetes Engine and update Doc (#435)
* verify deploy function to Google Kubernetes Engine and update Doc
* bump version
2019-12-27 23:08:51 +08:00
Minghe
aefb4497e2 When check a file is handler or not, should take extension account, (#433)
otherewise it might be a directory, not a file
2019-12-26 20:40:57 +08:00
Minghe Huang
0047e66f10 bump version 2019-12-26 20:38:50 +08:00
Minghe Huang
6bae4254af When check a file is handler or not, should take extension account,
otherewise it might be a directory, not a file
2019-12-26 18:47:11 +08:00
Minghe
a9689993b0 Fix packr missing auto release (#431)
* install packr

* install packr

* commit generate packr file

* no need change
2019-12-24 18:30:44 +08:00
Minghe
8c0182b29f move some installation into base image (#427) 2019-12-24 11:13:10 +08:00
Minghe Huang
02d55c7143 bump version 2019-12-23 13:57:31 +08:00
Minghe
f343b537f1 upgrade go-ssh-client pkg (#426)
* upgrade go-ssh-client pkg

* bump version
2019-12-20 10:24:14 +08:00
Minghe
a84e7da65f When there is services deployed via k8s mode on Desktop Docker for Mac (#424)
with kubernetes single node cluster, "fx list" will crash since some
service has no names, but the code trying to access names at index 0

Signed-off-by: Minghe Huang <h.minghe@gmail.com>
2019-12-19 16:05:40 +08:00
Minghe
f3b64387cb dependencies should be field of brew (#423) 2019-12-19 14:28:53 +08:00
Minghe
e132435ff8 add docker to dependency (#422)
* add docker to dependency

Signed-off-by: Minghe Huang <h.minghe@gmail.com>

* bump version
2019-12-19 13:41:26 +08:00
Minghe
fb492fa6f7 Merge pull request #415 from metrue/perl
Perl
2019-12-19 10:14:22 +08:00
Minghe Huang
159714491d add perl support,
fx up func.pl

Signed-off-by: Minghe Huang <h.minghe@gmail.com>
2019-12-18 21:06:56 +08:00
Minghe Huang
64cbbc70bb Squashed commit of the following:
commit f4e3d78e516f889a0256c6ddf922922ec12bc757
Author: Minghe Huang <h.minghe@gmail.com>
Date:   Wed Dec 18 21:02:43 2019 +0800

    check error when walk directory

    Signed-off-by: Minghe Huang <h.minghe@gmail.com>
2019-12-18 21:03:05 +08:00
Minghe
d0559f627e simple and clean code (#420)
Signed-off-by: Minghe Huang <h.minghe@gmail.com>
2019-12-18 20:56:26 +08:00
Minghe
0a6784e270 fix wrong cloud type issue (#419)
Signed-off-by: Minghe Huang <h.minghe@gmail.com>
2019-12-18 20:22:03 +08:00
112 changed files with 3318 additions and 638 deletions

View File

@@ -35,10 +35,10 @@ jobs:
docker build -t metrue/fx-d-base:latest -f ./assets/dockerfiles/base/d/Dockerfile ./assets/dockerfiles/base/d docker build -t metrue/fx-d-base:latest -f ./assets/dockerfiles/base/d/Dockerfile ./assets/dockerfiles/base/d
docker push metrue/fx-d-base:latest docker push metrue/fx-d-base:latest
# - name: build and publish fx java image - name: build and publish fx go image
# run: | run: |
# docker build -t metrue/fx-go-base:latest -f ./assets/dockerfiles/base/java/Dockerfile ./assets/dockerfiles/base/java docker build -t metrue/fx-go-base:latest -f ./assets/dockerfiles/base/go/Dockerfile ./assets/dockerfiles/base/go
# docker push metrue/fx-java-base:latest docker push metrue/fx-go-base:latest
- name: build and publish fx node image - name: build and publish fx node image
if: always() if: always()
@@ -57,11 +57,11 @@ jobs:
run: | run: |
docker push metrue/fx-python-base:latest docker push metrue/fx-python-base:latest
# - name: build and publish fx rust image - name: build and publish fx perl image
# if: always() if: always()
# run: | run: |
# docker build -t metrue/fx-rust-base:latest -f ./assets/dockerfiles/base/rust/Dockerfile ./assets/dockerfiles/base/python docker build -t metrue/fx-perl-base:latest -f ./assets/dockerfiles/base/perl/Dockerfile ./assets/dockerfiles/base/perl
# docker push metrue/fx-rust-base:latest docker push metrue/fx-perl-base:latest
- name: build and publish fx julia image - name: build and publish fx julia image
if: always() if: always()

View File

@@ -1,6 +1,6 @@
run: run:
deadline: 10m deadline: 20m
timeout: 10m timeout: 20m
issues-exit-code: 1 issues-exit-code: 1
tests: true tests: true
skip-dirs: skip-dirs:

View File

@@ -32,3 +32,5 @@ brews:
caveats: "" caveats: ""
homepage: "https://github.com/metrue/fx" homepage: "https://github.com/metrue/fx"
description: "fx, a simple but powerful Function as a Service build tools" description: "fx, a simple but powerful Function as a Service build tools"
dependencies:
- docker

View File

@@ -32,7 +32,7 @@ cli-test-ci:
./scripts/test_cli.sh 'js' ./scripts/test_cli.sh 'js'
cli-test: cli-test:
./scripts/test_cli.sh 'js rb py go php java d rs' ./scripts/test_cli.sh 'js rb py go php java d rs pl'
http-test: http-test:
./scripts/http_test.sh ./scripts/http_test.sh

View File

@@ -37,6 +37,7 @@ Feel free hacking fx to support the languages not listed. Welcome to tweet me [@
| PHP | Supported | [@chlins](https://github.com/chlins)| [/examples/PHP](https://github.com/metrue/fx/tree/master/examples/functions/PHP) | | PHP | Supported | [@chlins](https://github.com/chlins)| [/examples/PHP](https://github.com/metrue/fx/tree/master/examples/functions/PHP) |
| Julia | Supported | [@matbesancon](https://github.com/matbesancon)| [/examples/Julia](https://github.com/metrue/fx/tree/master/examples/functions/Julia) | | Julia | Supported | [@matbesancon](https://github.com/matbesancon)| [/examples/Julia](https://github.com/metrue/fx/tree/master/examples/functions/Julia) |
| D | Supported | [@andre2007](https://github.com/andre2007)| [/examples/D](https://github.com/metrue/fx/tree/master/examples/functions/D) | | D | Supported | [@andre2007](https://github.com/andre2007)| [/examples/D](https://github.com/metrue/fx/tree/master/examples/functions/D) |
| Perl | Supported | fx | [/examples/Perl](https://github.com/metrue/fx/tree/master/examples/functions/Perl) |
| R | Working on [need your help](https://github.com/metrue/fx/issues/31) | || | R | Working on [need your help](https://github.com/metrue/fx/issues/31) | ||
# Installation # Installation
@@ -205,8 +206,26 @@ But we would suggest you run `kubectl config current-context` to check if the cu
* Amazon Elastic Kubernetes Service (EKS) * Amazon Elastic Kubernetes Service (EKS)
TODO TODO
* Google Kubernetes Engine (GKET) * Google Kubernetes Engine (GKE)
TODO
First you should create a Kubernetes cluster in your GKE, then make sure your KUBECONFIG is ready in `~/.kube/config`, if not, you can run following commands,
``` shell
$ gcloud auth login
$ gcloud container clusters get-credentials <your cluster> --zone <zone> --project <project>
```
Then make sure you current context is GKE cluster, you can check it with command,
``` shell
$ kubectl config current-context
```
Then you can deploy your function onto GKE cluster with,
```shell
$ KUBECONFIG=~/.kube/config fx up examples/functions/JavaScript/func.js --name hellojs
```
* Setup your own Kubernetes cluster * Setup your own Kubernetes cluster

4
assets/dockerfiles/base/go/Dockerfile vendored Normal file
View File

@@ -0,0 +1,4 @@
FROM golang:latest
# dependency management
RUN go get github.com/gin-gonic/gin

26
assets/dockerfiles/base/node/package-lock.json generated vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "fx-node-base",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@koa/cors": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@koa/cors/-/cors-2.2.3.tgz",
"integrity": "sha512-tCVVXa39ETsit5kGBtEWWimjLn1sDaeu8+0phgb8kT3GmBDZOykkI3ZO8nMjV2p3MGkJI4K5P+bxR8Ztq0bwsA==",
"requires": {
"vary": "^1.1.2"
}
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
}
}
}

View File

@@ -1,5 +1,5 @@
{ {
"name": "aok", "name": "fx-node-base",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
@@ -10,12 +10,11 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@koa/cors": "^2.2.3",
"get-port": "^3.2.0", "get-port": "^3.2.0",
"is-generator-function": "^1.0.6", "is-generator-function": "^1.0.6",
"koa": "^2.3.0", "koa": "^2.3.0",
"koa-bodyparser": "^4.2.0" "koa-bodyparser": "^4.2.0",
}, "node-fetch": "^2.6.0"
"devDependencies": {
"get-port-cli": "^1.1.0"
} }
} }

10
assets/dockerfiles/base/perl/Dockerfile vendored Normal file
View File

@@ -0,0 +1,10 @@
FROM alpine:3.4
MAINTAINER Mojolicious
ADD . .
COPY cpanfile /
ENV EV_EXTRA_DEFS -DEV_NO_ATFORK
RUN apk update && \
apk add perl perl-io-socket-ssl perl-dbd-pg perl-dev g++ make wget curl && \
curl -L https://cpanmin.us | perl - App::cpanminus && cpanm --installdeps . -M https://cpan.metacpan.org

3
assets/dockerfiles/base/perl/cpanfile vendored Normal file
View File

@@ -0,0 +1,3 @@
requires "EV";
requires "JSON";
requires "Mojolicious::Lite";

View File

@@ -0,0 +1,3 @@
FROM ruby:latest
RUN gem install sinatra

44
bundle/bundle.go Normal file
View File

@@ -0,0 +1,44 @@
package bundle
import (
"fmt"
"github.com/metrue/fx/bundler"
"github.com/metrue/fx/bundler/d"
golang "github.com/metrue/fx/bundler/go"
"github.com/metrue/fx/bundler/java"
"github.com/metrue/fx/bundler/julia"
"github.com/metrue/fx/bundler/node"
"github.com/metrue/fx/bundler/perl"
"github.com/metrue/fx/bundler/python"
"github.com/metrue/fx/bundler/ruby"
"github.com/metrue/fx/bundler/rust"
)
// Bundle function to project
func Bundle(workdir string, language string, fn string, deps ...string) error {
var bundler bundler.Bundler
switch language {
case "d":
bundler = d.New()
case "node":
bundler = node.New()
case "go":
bundler = golang.New()
case "java":
bundler = java.New()
case "julia":
bundler = julia.New()
case "perl":
bundler = perl.New()
case "python":
bundler = python.New()
case "ruby":
bundler = ruby.New()
case "rust":
bundler = rust.New()
default:
return fmt.Errorf("%s not suppported yet", language)
}
return bundler.Bundle(workdir, fn, deps...)
}

117
bundle/bundler_test.go Normal file
View File

@@ -0,0 +1,117 @@
package bundle
import (
"io/ioutil"
"os"
"testing"
)
func createFn(content string, t *testing.T) string {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
return fd.Name()
}
func TestBundle(t *testing.T) {
workdir, err := ioutil.TempDir("", "fx-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(workdir)
cases := []struct {
workdir string
language string
fn string
deps []string
}{
{
workdir: workdir,
language: "d",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
{
workdir: workdir,
language: "go",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
{
workdir: workdir,
language: "java",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
{
workdir: workdir,
language: "julia",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
{
workdir: workdir,
language: "perl",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
{
workdir: workdir,
language: "python",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
{
workdir: workdir,
language: "ruby",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
{
workdir: workdir,
language: "rust",
fn: `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}
`,
},
}
for _, c := range cases {
fn := createFn(c.fn, t)
defer os.Remove(fn)
if err := Bundle(c.workdir, c.language, fn, c.deps...); err != nil {
t.Fatal(err)
}
}
}

88
bundler/bundler.go Normal file
View File

@@ -0,0 +1,88 @@
package bundler
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/gobuffalo/packd"
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/constants"
"github.com/metrue/fx/utils"
)
// Bundler defines interface
type Bundler interface {
Scaffold(output string) error
Bundle(output string, fn string, deps ...string) error
}
// IsHandler check if it's handle file
func IsHandler(name string, lang string) bool {
basename := filepath.Base(name)
nameWithoutExt := strings.TrimSuffix(basename, filepath.Ext(basename))
if constants.ExtLangMapping[filepath.Ext(basename)] != lang {
return false
}
return (nameWithoutExt == "fx" ||
// Fx is for Java
nameWithoutExt == "Fx" ||
// mod.rs is for Rust)
nameWithoutExt == "mod")
}
// Restore directory from packr box
func Restore(box *packr.Box, output string) error {
if err := box.Walk(func(name string, fd packd.File) error {
content, err := box.Find(name)
if err != nil {
return err
}
dest := filepath.Join(output, name)
if err := utils.EnsureFile(dest); err != nil {
return err
}
if err := ioutil.WriteFile(dest, content, 0644); err != nil {
return err
}
return nil
}); err != nil {
return err
}
return nil
}
// Bundle bundle a function
func Bundle(box *packr.Box, output string, language string, fn string, deps ...string) error {
if err := Restore(box, output); err != nil {
return err
}
if err := utils.Merge(output, deps...); err != nil {
return err
}
// Replace the default handler source file with given function source file
if err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if IsHandler(path, language) {
if err := utils.CopyFile(fn, path); err != nil {
return err
}
}
return nil
}); err != nil {
return err
}
return nil
}

51
bundler/bundler_test.go Normal file
View File

@@ -0,0 +1,51 @@
package bundler
import (
"io/ioutil"
"log"
"os"
"testing"
"github.com/gobuffalo/packr/v2"
)
func TestBundler(t *testing.T) {
t.Run("Restore", func(t *testing.T) {
box := packr.New("", "./node/assets")
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(outputDir)
if err := Restore(box, outputDir); err != nil {
t.Fatal(err)
}
})
t.Run("Bundle", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}`
if err = ioutil.WriteFile(fd.Name(), []byte(content), 0666); err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
box := packr.New("", "./node/assets")
if err := Bundle(box, outputDir, "node", fd.Name()); err != nil {
t.Fatal(err)
}
})
}

32
bundler/d/d.go Normal file
View File

@@ -0,0 +1,32 @@
package d
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// D defines d bundler
type D struct {
assets *packr.Box
}
// New a koa bundler
func New() *D {
return &D{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (d *D) Scaffold(output string) error {
return bundler.Restore(d.assets, output)
}
// Bundle a function into a koa project
func (d *D) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(d.assets, output, "d", fn, deps...)
}
var (
_ bundler.Bundler = &D{}
)

View File

@@ -1,11 +1,8 @@
FROM golang:latest FROM metrue/fx-go-base
COPY . /go/src/github.com/metrue/fx COPY . /go/src/github.com/metrue/fx
WORKDIR /go/src/github.com/metrue/fx WORKDIR /go/src/github.com/metrue/fx
# dependency management
RUN go get github.com/gin-gonic/gin
RUN go build -ldflags "-w -s" -o fx fx.go app.go RUN go build -ldflags "-w -s" -o fx fx.go app.go
EXPOSE 3000 EXPOSE 3000

32
bundler/go/go.go Normal file
View File

@@ -0,0 +1,32 @@
package golang
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// Gin defines javascript bundler
type Gin struct {
assets *packr.Box
}
// New a koa bundler
func New() *Gin {
return &Gin{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (g *Gin) Scaffold(output string) error {
return bundler.Restore(g.assets, output)
}
// Bundle a function into a koa project
func (g *Gin) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(g.assets, output, "go", fn, deps...)
}
var (
_ bundler.Bundler = &Gin{}
)

143
bundler/go/go_test.go Normal file
View File

@@ -0,0 +1,143 @@
package golang
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestKoaBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
koa := New()
if err := koa.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
koa := New()
if err := koa.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/fx.go")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/fx.go")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
koa := New()
if err := koa.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

32
bundler/java/java.go Normal file
View File

@@ -0,0 +1,32 @@
package java
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// Java defines javascript bundler
type Java struct {
assets *packr.Box
}
// New a koa bundler
func New() *Java {
return &Java{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (k *Java) Scaffold(output string) error {
return bundler.Restore(k.assets, output)
}
// Bundle a function into a koa project
func (k *Java) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(k.assets, output, "java", fn, deps...)
}
var (
_ bundler.Bundler = &Java{}
)

155
bundler/java/java_test.go Normal file
View File

@@ -0,0 +1,155 @@
package java
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestJavaBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_java")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
java := New()
if err := java.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.java")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `package fx;
import io.javalin.Javalin;
import org.json.JSONObject;
public class app {
public static void main(String[] args) {
Javalin app = Javalin.start(3000);
Fx handler = new Fx();
app.post("/", ctx -> {
JSONObject obj = new JSONObject(ctx.body());
ctx.result(""+handler.handle(obj));
});
}
}
`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_java")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
java := New()
if err := java.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/src/main/java/fx/Fx.java")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/src/main/java/fx/Fx.java")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_java")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
java := New()
if err := java.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

View File

@@ -1,4 +1,3 @@
struct Input struct Input
a::Number a::Number
b::Number b::Number

32
bundler/julia/julia.go Normal file
View File

@@ -0,0 +1,32 @@
package julia
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// Julia defines javascript bundler
type Julia struct {
assets *packr.Box
}
// New a koa bundler
func New() *Julia {
return &Julia{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (k *Julia) Scaffold(output string) error {
return bundler.Restore(k.assets, output)
}
// Bundle a function into a koa project
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(k.assets, output, "julia", fn, deps...)
}
var (
_ bundler.Bundler = &Julia{}
)

148
bundler/julia/julia_test.go Normal file
View File

@@ -0,0 +1,148 @@
package julia
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestJuliaBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.julia")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `struct Input
a::Number
b::Number
end
fx = function(input::Input)
return input.a + input.b
end
`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle function should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/fx.jl")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/fx.jl")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

View File

@@ -1,8 +1,12 @@
const Koa = require('koa'); const Koa = require('koa');
const bodyParser = require('koa-bodyparser'); const bodyParser = require('koa-bodyparser');
const cors = require('@koa/cors');
const fx = require('./fx'); const fx = require('./fx');
const app = new Koa(); const app = new Koa();
app.use(cors({
origin: '*',
}));
app.use(bodyParser()); app.use(bodyParser());
app.use(fx); app.use(fx);

34
bundler/node/node.go Normal file
View File

@@ -0,0 +1,34 @@
package node
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
const language = "node"
// Node defines node bundler
type Node struct {
assets *packr.Box
}
// New a koa bundler
func New() *Node {
return &Node{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (k *Node) Scaffold(output string) error {
return bundler.Restore(k.assets, output)
}
// Bundle a function into a koa project
func (k *Node) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(k.assets, output, language, fn, deps...)
}
var (
_ bundler.Bundler = &Node{}
)

143
bundler/node/node_test.go Normal file
View File

@@ -0,0 +1,143 @@
package node
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestNodeBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
koa := New()
if err := koa.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `
module.exports = (ctx) => {
ctx.body = 'hello fx'
}`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
koa := New()
if err := koa.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/fx.js")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/fx.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_koa")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
koa := New()
if err := koa.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

View File

@@ -0,0 +1,6 @@
FROM metrue/fx-perl-base
ADD . .
EXPOSE 3000
CMD ["perl", "app.pl", "daemon"]

View File

@@ -0,0 +1,17 @@
use Mojolicious::Lite;
require "./fx.pl";
get '/' => sub {
my $ctx = shift;
my $res = fx($ctx);
$ctx->render(json => $res);
};
post '/' => sub {
my $ctx = shift;
my $res = fx($ctx);
$ctx->render(json => $res);
};
app->start;

View File

@@ -0,0 +1,6 @@
sub fx {
my $ctx = shift;
return 'hello fx'
}
1;

32
bundler/perl/perl.go Normal file
View File

@@ -0,0 +1,32 @@
package perl
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// Julia defines javascript bundler
type Julia struct {
assets *packr.Box
}
// New a koa bundler
func New() *Julia {
return &Julia{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (k *Julia) Scaffold(output string) error {
return bundler.Restore(k.assets, output)
}
// Bundle a function into a koa project
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(k.assets, output, "perl", fn, deps...)
}
var (
_ bundler.Bundler = &Julia{}
)

148
bundler/perl/perl_test.go Normal file
View File

@@ -0,0 +1,148 @@
package perl
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestJuliaBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.julia")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `struct Input
a::Number
b::Number
end
fx = function(input::Input)
return input.a + input.b
end
`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle function should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/fx.pl")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/fx.pl")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

32
bundler/python/python.go Normal file
View File

@@ -0,0 +1,32 @@
package python
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// Julia defines javascript bundler
type Julia struct {
assets *packr.Box
}
// New a koa bundler
func New() *Julia {
return &Julia{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (k *Julia) Scaffold(output string) error {
return bundler.Restore(k.assets, output)
}
// Bundle a function into a koa project
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(k.assets, output, "python", fn, deps...)
}
var (
_ bundler.Bundler = &Julia{}
)

View File

@@ -0,0 +1,148 @@
package python
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestJuliaBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.julia")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `struct Input
a::Number
b::Number
end
fx = function(input::Input)
return input.a + input.b
end
`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle function should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/fx.py")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/fx.py")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

View File

@@ -1,6 +1,4 @@
FROM ruby:latest FROM metrue/fx-ruby-base
RUN gem install sinatra
COPY . . COPY . .
EXPOSE 3000 EXPOSE 3000

32
bundler/ruby/ruby.go Normal file
View File

@@ -0,0 +1,32 @@
package ruby
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// Julia defines javascript bundler
type Julia struct {
assets *packr.Box
}
// New a koa bundler
func New() *Julia {
return &Julia{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (k *Julia) Scaffold(output string) error {
return bundler.Restore(k.assets, output)
}
// Bundle a function into a koa project
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(k.assets, output, "ruby", fn, deps...)
}
var (
_ bundler.Bundler = &Julia{}
)

148
bundler/ruby/ruby_test.go Normal file
View File

@@ -0,0 +1,148 @@
package ruby
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestJuliaBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.julia")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `struct Input
a::Number
b::Number
end
fx = function(input::Input)
return input.a + input.b
end
`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle function should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/fx.rb")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/fx.rb")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

32
bundler/rust/rust.go Normal file
View File

@@ -0,0 +1,32 @@
package rust
import (
"github.com/gobuffalo/packr/v2"
"github.com/metrue/fx/bundler"
)
// Julia defines javascript bundler
type Julia struct {
assets *packr.Box
}
// New a koa bundler
func New() *Julia {
return &Julia{
assets: packr.New("", "./assets"),
}
}
// Scaffold a koa app
func (k *Julia) Scaffold(output string) error {
return bundler.Restore(k.assets, output)
}
// Bundle a function into a koa project
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
return bundler.Bundle(k.assets, output, "rust", fn, deps...)
}
var (
_ bundler.Bundler = &Julia{}
)

148
bundler/rust/rust_test.go Normal file
View File

@@ -0,0 +1,148 @@
package rust
import (
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"github.com/metrue/fx/utils"
)
func TestJuliaBundler(t *testing.T) {
t.Run("Scaffold", func(t *testing.T) {
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Scaffold(outputDir); err != nil {
t.Fatal(err)
}
diff, _, _, err := utils.Diff(outputDir, "./assets")
if err != nil {
t.Fatal(err)
}
if diff {
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
}
})
t.Run("BundleSingleFunc", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.julia")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content := `struct Input
a::Number
b::Number
end
fx = function(input::Input)
return input.a + input.b
end
`
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle function should be changed")
}
if !reflect.DeepEqual(cur, []byte(content)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
preHandleFunc, err := ioutil.ReadFile("./assets/src/fns/mod.rs")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pre, preHandleFunc) {
{
}
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
}
})
t.Run("BundleFuncAndDeps", func(t *testing.T) {
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
content, err := ioutil.ReadFile("./assets/src/fns/mod.rs")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(fd.Name(), content, 0666)
if err != nil {
t.Fatal(err)
}
addFunc := `
module.exports = (a, b) => a+b
`
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
if err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
if err != nil {
t.Fatal(err)
}
outputDir, err := ioutil.TempDir("", "fx_julia")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(outputDir)
julia := New()
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
t.Fatal(err)
}
diff, pre, cur, err := utils.Diff("./assets", outputDir)
if err != nil {
t.Fatal(err)
}
if !diff {
t.Fatalf("handle functino should be changed")
}
if !reflect.DeepEqual(cur, []byte(addFunc)) {
t.Fatalf("it should be %s but got %s", content, cur)
}
if pre != nil {
t.Fatal(pre)
}
})
}

14
config/env.go Normal file
View File

@@ -0,0 +1,14 @@
package config
import (
"os"
)
// DisableContainerAutoremove to tell if to run container with --rm
var DisableContainerAutoremove = false
func init() {
if os.Getenv("DISABLE_CONTAINER_AUTOREMOVE") == "true" {
DisableContainerAutoremove = true
}
}

17
config/env_test.go Normal file
View File

@@ -0,0 +1,17 @@
package config
import (
"os"
"testing"
)
var _ = func() (_ struct{}) {
os.Setenv("DISABLE_CONTAINER_AUTOREMOVE", "true")
return
}()
func TestEnvLoad(t *testing.T) {
if !DisableContainerAutoremove {
t.Fatalf("should be true after set")
}
}

15
constants/languages.go Normal file
View File

@@ -0,0 +1,15 @@
package constants
// ExtLangMapping file extension mapping with programming language
var ExtLangMapping = map[string]string{
".js": "node",
".go": "go",
".rb": "ruby",
".py": "python",
".php": "php",
".jl": "julia",
".java": "java",
".d": "d",
".rs": "rust",
".pl": "perl",
}

View File

@@ -23,6 +23,7 @@ import (
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
"github.com/google/uuid" "github.com/google/uuid"
fxConfig "github.com/metrue/fx/config"
containerruntimes "github.com/metrue/fx/container_runtimes" containerruntimes "github.com/metrue/fx/container_runtimes"
"github.com/metrue/fx/types" "github.com/metrue/fx/types"
"github.com/metrue/fx/utils" "github.com/metrue/fx/utils"
@@ -227,19 +228,29 @@ func (api *API) ListContainer(ctx context.Context, name string) ([]types.Service
svs := make(map[string]types.Service) svs := make(map[string]types.Service)
for _, container := range containers { for _, container := range containers {
name := "UNKNOWN"
if len(container.Names) > 0 {
name = container.Names[0]
}
port := -1
ip := "UNKNOWN"
if len(container.Ports) > 0 {
ip = container.Ports[0].IP
port = int(container.Ports[0].PublicPort)
}
// container name have extra forward slash // container name have extra forward slash
// https://github.com/moby/moby/issues/6705 // https://github.com/moby/moby/issues/6705
if strings.HasPrefix(container.Names[0], fmt.Sprintf("/%s", name)) {
svs[container.Image] = types.Service{ svs[container.Image] = types.Service{
Name: container.Names[0], Name: name,
Image: container.Image, Image: container.Image,
ID: container.ID, ID: container.ID,
Host: container.Ports[0].IP, Host: ip,
Port: int(container.Ports[0].PublicPort), Port: port,
State: container.State, State: container.State,
} }
} }
}
services := []types.Service{} services := []types.Service{}
for _, s := range svs { for _, s := range svs {
services = append(services, s) services = append(services, s)
@@ -392,7 +403,7 @@ func (api *API) StartContainer(ctx context.Context, name string, image string, b
} }
hostConfig := &dockerTypesContainer.HostConfig{ hostConfig := &dockerTypesContainer.HostConfig{
AutoRemove: true, AutoRemove: !fxConfig.DisableContainerAutoremove,
PortBindings: portMap, PortBindings: portMap,
} }

View File

@@ -18,6 +18,7 @@ import (
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/google/uuid" "github.com/google/uuid"
fxConfig "github.com/metrue/fx/config"
containerruntimes "github.com/metrue/fx/container_runtimes" containerruntimes "github.com/metrue/fx/container_runtimes"
"github.com/metrue/fx/types" "github.com/metrue/fx/types"
"github.com/metrue/fx/utils" "github.com/metrue/fx/utils"
@@ -161,7 +162,7 @@ func (d *Docker) StartContainer(ctx context.Context, name string, image string,
} }
hostConfig := &dockerTypesContainer.HostConfig{ hostConfig := &dockerTypesContainer.HostConfig{
AutoRemove: true, AutoRemove: !fxConfig.DisableContainerAutoremove,
PortBindings: portMap, PortBindings: portMap,
} }
resp, err := d.ContainerCreate(ctx, config, hostConfig, nil, name) resp, err := d.ContainerCreate(ctx, config, hostConfig, nil, name)

68
examples/functions/Perl/README.md vendored Normal file
View File

@@ -0,0 +1,68 @@
# Make a Perl function a service with fx
[![asciicast](https://asciinema.org/a/aXpr0jquwhhwhghiDCdC7nY8r.svg)](https://asciinema.org/a/aXpr0jquwhhwhghiDCdC7nY8r)
### Hello World
```perl
sub fx {
return 'hello fx'
}
1;
```
then deploy it with `fx up` command,
```shell
$ fx up -p 8080 --name helloworld func.pl
```
test it using `curl`
```shell
$ curl 127.0.0.1:8080
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 11
Content-Type: text/plain; charset=utf-8
Date: Tue, 06 Aug 2019 15:58:41 GMT
hello fx
```
### Sum
```perl
sub fx {
my $ctx = shift;
my $a = $ctx->req->json->{"a"};
my $b = $ctx->req->json->{"b"};
return int($a) + int($b)
}
1;
```
```shell
fx up --name add --port 40002 --force add.pl
```
Then test it with httpie.
```shell
$ http post 0.0.0.0:40002 a=1 b=2
HTTP/1.1 200 OK
Content-Length: 1
Content-Type: application/json;charset=UTF-8
Date: Thu, 02 Jan 2020 15:39:49 GMT
Server: Mojolicious (Perl)
3
```
### ctx
The `ctx` object is exactly the [Controller](https://mojolicious.org/perldoc/Mojolicious/Controller) of [Mojolicious](https://mojolicious.org/perldoc/Mojolicious) framework.

8
examples/functions/Perl/add.pl vendored Normal file
View File

@@ -0,0 +1,8 @@
sub fx {
my $ctx = shift;
my $a = $ctx->req->json->{"a"};
my $b = $ctx->req->json->{"b"};
return int($a) + int($b)
}
1;

417
examples/functions/Perl/demo.cast vendored Normal file
View File

@@ -0,0 +1,417 @@
{"version": 2, "width": 204, "height": 47, "timestamp": 1577978477, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}}
[1.14954, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[1.150447, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007\u001b]1;..unctions/Perl\u0007"]
[1.198859, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;31m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[1.199061, "o", "\u001b[?1h\u001b=\u001b[?2004h"]
[2.253827, "o", "l"]
[2.400431, "o", "\bls"]
[2.55552, "o", "\u001b[?1l\u001b>"]
[2.555606, "o", "\u001b[?2004l\r\r\n"]
[2.557935, "o", "\u001b]2;ls -G\u0007\u001b]1;ls\u0007"]
[2.565597, "o", "README.md add.pl demo.cast hello.pl\r\n"]
[2.566169, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[2.566464, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007\u001b]1;..unctions/Perl\u0007"]
[2.616843, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;32m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[2.617034, "o", "\u001b[?1h\u001b=\u001b[?2004h"]
[2.915162, "o", "v"]
[2.988711, "o", "\bvi"]
[3.202168, "o", "m"]
[3.350667, "o", " "]
[4.12655, "o", "h"]
[4.274974, "o", "e"]
[4.416048, "o", "llo.pl\u001b[1m \u001b[0m"]
[4.787927, "o", "\b\u001b[0m \b"]
[4.788014, "o", "\u001b[?1l\u001b>\u001b[?2004l"]
[4.788292, "o", "\r\r\n"]
[4.789415, "o", "\u001b]2;/usr/local/Cellar/vim/8.2.0/bin/vim hello.pl\u0007\u001b]1;vim\u0007"]
[4.946445, "o", "\u001b[?1000h\u001b[?1049h\u001b[>4;2m\u001b[?1h\u001b=\u001b[?2004h\u001b[1;47r\u001b[?12h\u001b[?12l\u001b[22;2t\u001b[22;1t"]
[4.947253, "o", "\u001b[27m\u001b[29m\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[H\u001b[2J\u001b[?25l\u001b[47;1H\"hello.pl\""]
[4.947367, "o", " 5L, 35C"]
[4.955849, "o", "\u001b[?1000l\u001b[?2004l"]
[4.974498, "o", "\u001b[?2004h\u001b[?1000h"]
[5.109471, "o", "\u001b[?1000l\u001b[?2004l"]
[5.11056, "o", "\u001b[?2004h"]
[5.110849, "o", "\u001b[?1000h\u001b[?1000l\u001b[?2004l"]
[5.113119, "o", "\u001b[?2004h\u001b[?1000h"]
[5.113304, "o", "\u001b[?1000l\u001b[?2004l"]
[5.116222, "o", "\u001b[?2004h\u001b[?1000h"]
[5.116418, "o", "\u001b[?1000l\u001b[?2004l"]
[5.12038, "o", "\u001b[?2004h\u001b[?1000h\u001b[?1000l\u001b[?2004l"]
[5.125489, "o", "\u001b[?2004h\u001b[?1000h\u001b[?1000l\u001b[?2004l"]
[5.132998, "o", "\u001b[?2004h"]
[5.133158, "o", "\u001b[?1000h\u001b[?2004h"]
[5.134064, "o", "\u001b[?1000l\u001b[?2004l"]
[5.151895, "o", "\u001b[?2004h\u001b[?1000h"]
[5.172471, "o", "\u001b[2;1H▽\u001b[6n\u001b[2;1H \u001b[1;1H\u001b[>c"]
[5.172688, "o", "\u001b]10;?\u0007\u001b]11;?\u0007"]
[5.176877, "o", "\u001b[1;1H\u001b[38;2;75;82;99m 1 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;255;83;112msub \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;130;177;255mfx \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m{\r\n\u001b[38;2;75;82;99m 2 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;199;146;234mreturn\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;195;232;141m'hello fx'\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\r\n\u001b[38;2;75;82;99m 3 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m}\r\n\u001b[38;2;75;82;99m 4 \r\n 5 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;247;140;108m1\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m;\r\n\u001b[38;2;59;64;72m~ \u001b[7;1H~ \u001b[8;1H~ "]
[5.177078, "o", " \u001b[9;1H~ \u001b[10;1H~ \u001b[11;1H~ \u001b[12;1H~ "]
[5.177184, "o", " \u001b[13;1H~ \u001b[14;1H~ \u001b[15;1H~ \u001b[16;1H~ \u001b[17;1H~ "]
[5.177303, "o", " \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ \u001b[21;1H~ \u001b[22;1H~ "]
[5.17742, "o", " \u001b[23;1H~ \u001b[24;1H~ \u001b[25;1H~ \u001b[26;1H~ \u001b[27;1H~ "]
[5.177516, "o", " \u001b[28;1H~ \u001b[29;1H~ \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ "]
[5.177622, "o", " \u001b[33;1H~ \u001b[34;1H~ \u001b[35;1H~ \u001b[36;1H~ \u001b[37;1H~ "]
[5.177732, "o", " \u001b[38;1H~ \u001b[39;1H~ \u001b[40;1H~ \u001b[41;1H~ "]
[5.190961, "o", "\u001b[42;1H~ \u001b[43;1H~ \u001b[44;1H~ \u001b[45;1H~ \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;1H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222mNORMAL\u001b[m\u001b[38;2;191;19"]
[5.192792, "o", "9;213m\u001b[48;2;41;45;62m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m ᚠ perl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;191;199;213m\u001b[48;2;51;55;71m hello.pl perl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m utf-8[unix] \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m 20% \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m☰ 1/5 ㏑\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m : 1 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;10H\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m+0 ~0 -0 ᚠ perl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1C\u001b[38;2;191;199;213m\u001b[48;2;51;55;71mhello.pl\u001b[1;5H\u001b[?25h\u001b[?12$p"]
[5.459655, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;10H\u001b[38;2;191;199;213m\u001b[48;2;71;75;89mᚠ perl! \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;191;199;213m\u001b[48;2;51;55;71m hello.pl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[149C\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m4\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[8C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m2/\u001b[2;5H"]
[5.885479, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1;12H\u001b[38;2;130;177;255m{\u001b[3;5H}\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;10H\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m+0 ~0 -0 ᚠ perl! \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1C\u001b[38;2;191;199;213m\u001b[48;2;51;55;71mhello.pl\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[148C\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m6\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[8C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m3/\u001b[3;5H\u001b[?25h"]
[6.061856, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1;12H{\u001b[3;5H}\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m8\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[8C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m4/\u001b[4;5H\u001b[?25h"]
[6.227967, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;183H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m10\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[8C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m5/\u001b[5;5H"]
[6.440828, "o", "\u0007"]
[6.999501, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[47;1H\u001b[K\u001b[47;1H:\u001b[?1000l\u001b[?2004h\u001b[?25h"]
[7.282638, "o", "q"]
[7.580486, "o", "w"]
[8.042814, "o", "\u001b[?25l\u001b[47;3H\u001b[K\u001b[47;3H\u001b[?25h"]
[8.209127, "o", "\u001b[?25l\u001b[47;2H\u001b[K\u001b[47;2H\u001b[?25h"]
[8.29389, "o", "w"]
[8.364523, "o", "q"]
[8.552089, "o", "\r"]
[8.554758, "o", "\u001b[?1000h\u001b[?25l\u001b[?1000l\u001b[?2004l"]
[8.555496, "o", "\"hello.pl\""]
[8.564609, "o", " 5L, 35C written"]
[8.595134, "o", "\r\u001b[23;2t\u001b[23;1t\r\r\n\u001b[39;49m\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[>4;m\u001b[?1049l"]
[8.599757, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[8.600003, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007\u001b]1;..unctions/Perl\u0007"]
[8.683359, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;32m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[8.683591, "o", "\u001b[?1h\u001b="]
[8.683745, "o", "\u001b[?2004h"]
[9.988453, "o", "f"]
[10.203643, "o", "\bfx"]
[10.533603, "o", " up --name add --port 40001 hello.pl --force"]
[11.146588, "o", "\u001b[?1l\u001b>"]
[11.146941, "o", "\u001b[?2004l\r\r\n"]
[11.148205, "o", "\u001b]2;fx up --name add --port 40001 hello.pl --force\u0007"]
[11.148443, "o", "\u001b]1;fx\u0007"]
[11.24007, "o", "building \u001b[32m[ ]\u001b[0m "]
[11.340717, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.341114, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[11.341521, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kbuilding \u001b[32m[=> ]\u001b[0m "]
[11.411368, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.411537, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[11.445379, "o", "destroying add \u001b[34m[===> ]\u001b[0m "]
[11.5467, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.547266, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[11.54763, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[=====> ]\u001b[0m "]
[11.652602, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.653023, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[11.653426, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[======> ]\u001b[0m "]
[11.756859, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.75701, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[========> ]\u001b[0m "]
[11.857969, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.858251, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[11.858445, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[==========> ]\u001b[0m "]
[11.962964, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.963505, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.963792, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[11.964263, "o", "\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[============> ]\u001b[0m "]
[12.066808, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.067166, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.067532, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[12.067729, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[==============> ]\u001b[0m "]
[12.11908, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.119302, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[12.167966, "o", "deploying add \u001b[36m[================> ]\u001b[0m "]
[12.271321, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.271512, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[==================> ]\u001b[0m "]
[12.373093, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.373377, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[12.373483, "o", "deploying add \u001b[36m[===================>]\u001b[0m "]
[12.475496, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.475887, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[ ]\u001b[0m "]
[12.576106, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.576491, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[=> ]\u001b[0m "]
[12.681062, "o", "\b\b\b\b\b\b\b\b"]
[12.681348, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[12.681596, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[===> ]\u001b[0m "]
[12.785704, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.786212, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[12.7866, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[=====> ]\u001b[0m "]
[12.889932, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.890131, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[======> ]\u001b[0m "]
[12.993483, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[12.993626, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[========> ]\u001b[0m "]
[13.09445, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.094945, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[13.095276, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[==========> ]\u001b[0m "]
[13.195321, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.195719, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[13.195845, "o", "\u001b[K\u001b[Kdeploying add \u001b[36m[============> ]\u001b[0m "]
[13.299457, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.299971, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[==============> ]\u001b[0m "]
[13.403608, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.404077, "o", "\b\b\b\b\b\b\b\b\b"]
[13.404501, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[================> ]\u001b[0m "]
[13.505661, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.506245, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.506398, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.506526, "o", "\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[13.506799, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[==================> ]\u001b[0m "]
[13.608501, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.608887, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[13.609235, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[===================>]\u001b[0m "]
[13.709097, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.709286, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[13.709322, "o", "deploying add \u001b[36m[ ]\u001b[0m "]
[13.812622, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.813279, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.813713, "o", "\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[=> ]\u001b[0m "]
[13.917566, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[13.917907, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[===> ]\u001b[0m "]
[14.02233, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[14.022513, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[=====> ]\u001b[0m "]
[14.125472, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[14.125627, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[======> ]\u001b[0m "]
[14.225728, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[14.226074, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[========> ]\u001b[0m "]
[14.326329, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[14.326708, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[14.327001, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[14.327291, "o", "deploying add \u001b[36m[==========> ]\u001b[0m "]
[14.430275, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[14.43045, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[36m[============> ]\u001b[0m "]
[14.477509, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[14.477667, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[14.480551, "o", "+------------------------------------------------------------------+------+---------------+\r\n| ID | NAME | ENDPOINT |\r\n+------------------------------------------------------------------+------+---------------+"]
[14.480737, "o", "\r\n| dc546007a6b7c8738a3107efe18041da27ccc0f1dfd8e992bc0fb4b0514c9ba0 | /add | 0.0.0.0:40001 |\r\n+------------------------------------------------------------------+------+---------------+\r\n"]
[14.48264, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[14.482857, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007\u001b]1;..unctions/Perl\u0007"]
[14.538028, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;32m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[14.538161, "o", "\u001b[?1h\u001b="]
[14.538226, "o", "\u001b[?2004h"]
[15.721709, "o", "h"]
[15.856214, "o", "\bht"]
[16.027529, "o", "t"]
[17.184631, "o", "p localhost:40001"]
[17.671003, "o", "\u001b[?1l\u001b>"]
[17.671086, "o", "\u001b[?2004l\r\r\n"]
[17.672363, "o", "\u001b]2;http localhost:40001\u0007\u001b]1;http\u0007"]
[17.96737, "o", "\u001b[34mHTTP\u001b[39;49;00m/\u001b[34m1.1\u001b[39;49;00m \u001b[34m200\u001b[39;49;00m \u001b[36mOK\u001b[39;49;00m\r\n\u001b[36mContent-Length\u001b[39;49;00m: 10\r\n\u001b[36mContent-Type\u001b[39;49;00m: application/json;charset=UTF-8\r\n\u001b[36mDate\u001b[39;49;00m: Thu, 02 Jan 2020 15:21:35 GMT\r\n\u001b[36mServer\u001b[39;49;00m: Mojolicious (Perl)\r\r\n\r\r\n"]
[17.968554, "o", "\u001b[33m\"hello fx\"\u001b[39;49;00m\r\n\r\n"]
[17.993945, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[17.994105, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007\u001b]1;..unctions/Perl\u0007"]
[18.046585, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;32m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[18.046727, "o", "\u001b[?1h\u001b=\u001b[?2004h"]
[19.712512, "o", "v"]
[19.834568, "o", "\bvi"]
[20.03562, "o", "m"]
[20.145382, "o", " "]
[20.224959, "o", "a"]
[20.458989, "o", "."]
[20.85012, "o", "\b \b"]
[21.149959, "o", "dd.pl\u001b[1m \u001b[0m"]
[21.640042, "o", "\b\u001b[0m \b"]
[21.640125, "o", "\u001b[?1l\u001b>"]
[21.640405, "o", "\u001b[?2004l\r\r\n"]
[21.641586, "o", "\u001b]2;/usr/local/Cellar/vim/8.2.0/bin/vim add.pl\u0007\u001b]1;vim\u0007"]
[21.809875, "o", "\u001b[?1000h\u001b[?1049h\u001b[>4;2m\u001b[?1h\u001b=\u001b[?2004h\u001b[1;47r\u001b[?12h\u001b[?12l\u001b[22;2t\u001b[22;1t"]
[21.810887, "o", "\u001b[27m\u001b[29m\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[H\u001b[2J\u001b[?25l\u001b[47;1H\"add.pl\""]
[21.811558, "o", " 8L, 129C"]
[21.819874, "o", "\u001b[?1000l\u001b[?2004l"]
[21.836929, "o", "\u001b[?2004h"]
[21.837071, "o", "\u001b[?1000h"]
[21.966477, "o", "\u001b[?1000l\u001b[?2004l"]
[21.967556, "o", "\u001b[?2004h"]
[21.967761, "o", "\u001b[?1000h\u001b[?1000l\u001b[?2004l"]
[21.969825, "o", "\u001b[?2004h"]
[21.969988, "o", "\u001b[?1000h\u001b[?1000l\u001b[?2004l"]
[21.972986, "o", "\u001b[?2004h\u001b[?1000h"]
[21.973119, "o", "\u001b[?1000l\u001b[?2004l"]
[21.977246, "o", "\u001b[?2004h\u001b[?1000h\u001b[?1000l\u001b[?2004l"]
[21.982549, "o", "\u001b[?2004h\u001b[?1000h"]
[21.982683, "o", "\u001b[?1000l\u001b[?2004l"]
[21.990047, "o", "\u001b[?2004h\u001b[?1000h\u001b[?2004h"]
[21.991254, "o", "\u001b[?1000l\u001b[?2004l"]
[22.007821, "o", "\u001b[?2004h\u001b[?1000h"]
[22.024663, "o", "\u001b[2;1H▽\u001b[6n\u001b[2;1H \u001b[1;1H\u001b[>c"]
[22.02487, "o", "\u001b]10;?\u0007\u001b]11;?\u0007"]
[22.032552, "o", "\u001b[1;1H\u001b[38;2;75;82;99m 1 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;255;83;112msub \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;130;177;255mfx \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m{\r\n\u001b[38;2;75;82;99m 2 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;199;146;234mmy\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;255;83;112m$ctx\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m = \u001b[38;2;199;146;234mshift\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m;\r\n\u001b[38;2;75;82;99m 3 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;199;146;234mmy\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;255;83;112m$a\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m = \u001b[38;2;255;83;112m$ctx->req->json->{\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;195;232;141m\"a\"\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;255;83;112m}\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m;\r\n\u001b[38;2;75;82;99m 4 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;199;146;234mmy\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;255;83;112m$b\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m = \u001b[38;2;255;83;112m$ctx->req->json"]
[22.032746, "o", "->{\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;195;232;141m\"b\"\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;255;83;112m}\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m;\r\n\u001b[38;2;75;82;99m 5 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;199;146;234mreturn\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m \u001b[38;2;199;146;234mint\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m(\u001b[38;2;255;83;112m$a\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m) + \u001b[38;2;199;146;234mint\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m(\u001b[38;2;255;83;112m$b\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m)\r\n\u001b[38;2;75;82;99m 6 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m}\r\n\u001b[38;2;75;82;99m 7 \r\n 8 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;247;140;108m1\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m;\r\n\u001b[38;2;59;64;72m~ \u001b[10;1H~ "]
[22.032843, "o", " \u001b[11;1H~ \u001b[12;1H~ \u001b[13;1H~ \u001b[14;1H~ \u001b[15;1H~ "]
[22.03293, "o", " \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ "]
[22.033025, "o", " \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[24;1H~ "]
[22.03311, "o", " \u001b[25;1H~ \u001b[26;1H~ \u001b[27;1H~ \u001b[28;1H~ \u001b[29;1H~ "]
[22.033229, "o", " \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ \u001b[33;1H~ \u001b[34;1H~ "]
[22.033337, "o", " \u001b[35;1H~ \u001b[36;1H~ \u001b[37;1H~ \u001b[38;1H~ \u001b[39;1H~ "]
[22.042308, "o", " \u001b[40;1H~ \u001b[41;1H~ \u001b[42;1H~ \u001b[43;1H~ \u001b[44;1H~ "]
[22.042505, "o", " \u001b[45;1H~ \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;1H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222mNORMAL\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m ᚠ perl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;191;199;213m\u001b[48;2;51;55;71m add.pl perl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m"]
[22.048105, "o", "\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m utf-8[unix] \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m 12% \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m☰ 1/8 ㏑\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m : 1 \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;10H\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m+0 ~0 -0 ᚠ perl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1C\u001b[38;2;191;199;213m\u001b[48;2;51;55;71madd.pl\u001b[1;5H\u001b[?25h"]
[22.048832, "o", "\u001b[?12$p"]
[22.111039, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;10H\u001b[38;2;191;199;213m\u001b[48;2;71;75;89mᚠ perl! \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[38;2;191;199;213m\u001b[48;2;51;55;71m add.pl \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[151C\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m25\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m2/\u001b[2;5H"]
[22.700162, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;10H\u001b[38;2;191;199;213m\u001b[48;2;71;75;89m+0 ~0 -0 ᚠ perl! \u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1C\u001b[38;2;191;199;213m\u001b[48;2;51;55;71madd.pl\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[150C\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m37\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m3/\u001b[3;5H"]
[22.894195, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m50\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m4/\u001b[4;5H"]
[23.081045, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m62\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m5/\u001b[5;5H"]
[23.313711, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1;12H\u001b[38;2;130;177;255m{\u001b[6;5H}\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m75\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m6/\u001b[6;5H\u001b[?25h"]
[23.602087, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1;12H{\u001b[6;5H}\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m87\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m7/\u001b[7;5H\u001b[?25h"]
[23.962955, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;183H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m100\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m8/\u001b[8;5H"]
[24.549961, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;183H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m 87\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m7/\u001b[7;5H"]
[24.793843, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1;12H\u001b[38;2;130;177;255m{\u001b[6;5H}\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m75\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m6/\u001b[6;5H\u001b[?25h"]
[24.99262, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[1;12H{\u001b[6;5H}\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m62\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m5/\u001b[5;5H\u001b[?25h"]
[25.362512, "o", "\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[46;184H\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m50\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[7C\u001b[1m\u001b[38;2;41;45;62m\u001b[48;2;147;158;222m4/\u001b[4;5H"]
[25.77714, "o", "\u001b[?25l\u001b[m\u001b[38;2;191;199;213m\u001b[48;2;41;45;62m\u001b[47;1H\u001b[K\u001b[47;1H:\u001b[?1000l\u001b[?2004h\u001b[?25h"]
[25.945572, "o", "q"]
[26.47528, "o", "\r"]
[26.490539, "o", "\u001b[?1000h\u001b[?25l\u001b[?1000l\u001b[?2004l\u001b[23;2t\u001b[23;1t"]
[26.490711, "o", "\u001b[47;1H\u001b[K\u001b[47;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[>4;m\u001b[?1049l"]
[26.493893, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[26.494036, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007\u001b]1;..unctions/Perl\u0007"]
[26.55072, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;32m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[26.5509, "o", "\u001b[?1h\u001b=\u001b[?2004h"]
[27.310856, "o", "f"]
[27.553944, "o", "\bfx"]
[28.138222, "o", " "]
[28.326337, "o", "u"]
[28.436765, "o", "p"]
[28.894128, "o", " --name add --port 40001 hello.pl --force"]
[29.129425, "o", "\u001b[18D2 add\u001b[P\u001b[P\u001b[11C \b\b"]
[32.439129, "o", "\u001b[?1l\u001b>\u001b[?2004l\r\r\n"]
[32.440378, "o", "\u001b]2;fx up --name add --port 40002 add.pl --force\u0007"]
[32.440597, "o", "\u001b]1;fx\u0007"]
[32.556138, "o", "building \u001b[35m[ ]\u001b[0m "]
[32.660991, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[32.661456, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kbuilding \u001b[35m[=> ]\u001b[0m "]
[32.762575, "o", "\b"]
[32.763291, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[32.763534, "o", "building \u001b[35m[===> ]\u001b[0m "]
[32.783314, "o", "\b\b\b\b\b\b\b\b\b\b\b\b"]
[32.783556, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[32.865981, "o", "destroying add \u001b[34m[=====> ]\u001b[0m "]
[32.966633, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[32.967025, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[32.967261, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[======> ]\u001b[0m "]
[33.069946, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.070613, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[33.070982, "o", "destroying add \u001b[34m[========> ]\u001b[0m "]
[33.170881, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.171194, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[33.171417, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[==========> ]\u001b[0m "]
[33.275611, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.276073, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[============> ]\u001b[0m "]
[33.380623, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.381102, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[33.381339, "o", "\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[==============> ]\u001b[0m "]
[33.48262, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.483143, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.483701, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[33.483998, "o", "destroying add \u001b[34m[================> ]\u001b[0m "]
[33.586747, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.58728, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[33.587416, "o", "destroying add \u001b[34m[==================> ]\u001b[0m "]
[33.691358, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.691957, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[33.692362, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[===================>]\u001b[0m "]
[33.792488, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.792889, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[33.793331, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[ ]\u001b[0m "]
[33.898149, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.89864, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[33.899119, "o", "\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[=> ]\u001b[0m "]
[34.002146, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.002324, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[===> ]\u001b[0m "]
[34.106599, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.107121, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.107633, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[=====> ]\u001b[0m "]
[34.210556, "o", "\b"]
[34.211072, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.21122, "o", "\b\b\b\b\b\b"]
[34.211895, "o", "\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[======> ]\u001b[0m "]
[34.315191, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.315454, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[34.315605, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdestroying add \u001b[34m[========> ]\u001b[0m "]
[34.320443, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.320609, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K"]
[34.320709, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[34.420121, "o", "deploying add \u001b[34m[==========> ]\u001b[0m "]
[34.523078, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.523295, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[============> ]\u001b[0m "]
[34.624895, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.62532, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.625574, "o", "\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[==============> ]\u001b[0m "]
[34.727629, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.728192, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.7286, "o", "\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[================> ]\u001b[0m "]
[34.831119, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.831739, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[==================> ]\u001b[0m "]
[34.932013, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[34.932102, "o", ""]
[34.932296, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[===================>]\u001b[0m "]
[35.036361, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.036569, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.036826, "o", "\b\b\b\b\b\b\b\b\b\b\b"]
[35.036903, "o", "\b\b\b\b\b\b\b\b\b"]
[35.037301, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.037897, "o", "\u001b[Kdeploying add \u001b[34m[ ]\u001b[0m "]
[35.140429, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.14113, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.141475, "o", "deploying add \u001b[34m[=> ]\u001b[0m "]
[35.241427, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.241811, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.242177, "o", "\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[===> ]\u001b[0m "]
[35.344792, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.345114, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.345431, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[=====> ]\u001b[0m "]
[35.44826, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.448627, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.448919, "o", "deploying add \u001b[34m[======> ]\u001b[0m "]
[35.55305, "o", "\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.55356, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.55388, "o", "\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[========> ]\u001b[0m "]
[35.65903, "o", "\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.65939, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.659725, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[==========> ]\u001b[0m "]
[35.75989, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.760206, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.760447, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[============> ]\u001b[0m "]
[35.86524, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.865663, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.866145, "o", "\u001b[K\u001b[Kdeploying add \u001b[34m[==============> ]\u001b[0m "]
[35.970426, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[35.970849, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[35.971211, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[================> ]\u001b[0m "]
[36.074506, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.07483, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[36.0751, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[==================> ]\u001b[0m "]
[36.175231, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.175434, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[===================>]\u001b[0m "]
[36.278976, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.279143, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[36.279243, "o", "deploying add \u001b[34m[ ]\u001b[0m "]
[36.380487, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.380963, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[36.381454, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[=> ]\u001b[0m "]
[36.486341, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.487048, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[===> ]\u001b[0m "]
[36.588875, "o", "\b\b\b\b\b\b\b"]
[36.589343, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.589578, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[36.589795, "o", "\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[=====> ]\u001b[0m "]
[36.691472, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.691721, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[Kdeploying add \u001b[34m[======> ]\u001b[0m "]
[36.711906, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
[36.712114, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K\u001b[K"]
[36.714878, "o", "+------------------------------------------------------------------+------+---------------+\r\n| ID | NAME | ENDPOINT |"]
[36.715104, "o", "\r\n+------------------------------------------------------------------+------+---------------+\r\n| 9ccf40c247b8cd6a82292fc526f6e1139432953b231ba4f51a1f18d4c13f6458 | /add | 0.0.0.0:40002 |\r\n+------------------------------------------------------------------+------+---------------+\r\n"]
[36.716932, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[36.717114, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007"]
[36.717147, "o", "\u001b]1;..unctions/Perl\u0007"]
[36.779836, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;32m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[36.779976, "o", "\u001b[?1h\u001b=\u001b[?2004h"]
[37.398193, "o", "h"]
[37.594295, "o", "\bht"]
[37.71095, "o", "t"]
[37.85487, "o", "p"]
[38.075195, "o", " "]
[38.247123, "o", "p"]
[38.426405, "o", "o"]
[39.448868, "o", "st 0.0.0.0:40002 a=1 b=2"]
[40.51774, "o", "\u001b[?1l\u001b>\u001b[?2004l"]
[40.517813, "o", "\r\r\n"]
[40.518991, "o", "\u001b]2;http post 0.0.0.0:40002 a=1 b=2\u0007"]
[40.51914, "o", "\u001b]1;http\u0007"]
[40.811478, "o", "\u001b[34mHTTP\u001b[39;49;00m/\u001b[34m1.1\u001b[39;49;00m \u001b[34m200\u001b[39;49;00m \u001b[36mOK\u001b[39;49;00m\r\n\u001b[36mContent-Length\u001b[39;49;00m: 1\r\n\u001b[36mContent-Type\u001b[39;49;00m: application/json;charset=UTF-8\r\n\u001b[36mDate\u001b[39;49;00m: Thu, 02 Jan 2020 15:21:57 GMT\r\n\u001b[36mServer\u001b[39;49;00m: Mojolicious (Perl)\r\r\n\r\r\n"]
[40.812798, "o", "\u001b[34m3\u001b[39;49;00m\r\n\r\n"]
[40.837697, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[40.837901, "o", "\u001b]2;minhuang@C02ZL0RJLVDN: ~/Codes/fx/examples/functions/Perl\u0007\u001b]1;..unctions/Perl\u0007"]
[40.890525, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b[01;32m➜ \u001b[36mPerl\u001b[00m \u001b[01;34mgit:(\u001b[31mperl\u001b[34m) \u001b[33m✗\u001b[00m \u001b[K"]
[40.890681, "o", "\u001b[?1h\u001b=\u001b[?2004h"]
[43.215524, "o", "\u001b[?2004l\r\r\n"]

5
examples/functions/Perl/hello.pl vendored Normal file
View File

@@ -0,0 +1,5 @@
sub fx {
return 'hello fx'
}
1;

13
fx.go
View File

@@ -14,9 +14,10 @@ import (
"github.com/metrue/fx/handlers" "github.com/metrue/fx/handlers"
"github.com/metrue/fx/middlewares" "github.com/metrue/fx/middlewares"
"github.com/urfave/cli" "github.com/urfave/cli"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
) )
const version = "0.8.76" const version = "0.9.2"
func init() { func init() {
go checkForUpdate() go checkForUpdate()
@@ -158,6 +159,7 @@ func main() {
middlewares.LoadConfig, middlewares.LoadConfig,
middlewares.Provision, middlewares.Provision,
middlewares.Parse("up"), middlewares.Parse("up"),
middlewares.Language(),
middlewares.Binding, middlewares.Binding,
middlewares.Build, middlewares.Build,
handlers.Up, handlers.Up,
@@ -178,6 +180,13 @@ func main() {
Name: "list", Name: "list",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
Usage: "list deployed services", Usage: "list deployed services",
Flags: []cli.Flag{
cli.StringFlag{
Name: "format, f",
Value: "table",
Usage: "output format, 'table' and 'JSON' supported",
},
},
Action: handle( Action: handle(
middlewares.Parse("list"), middlewares.Parse("list"),
middlewares.LoadConfig, middlewares.LoadConfig,
@@ -213,6 +222,7 @@ func main() {
middlewares.LoadConfig, middlewares.LoadConfig,
middlewares.Provision, middlewares.Provision,
middlewares.Parse("image_build"), middlewares.Parse("image_build"),
middlewares.Language(),
handlers.BuildImage, handlers.BuildImage,
), ),
}, },
@@ -229,6 +239,7 @@ func main() {
middlewares.LoadConfig, middlewares.LoadConfig,
middlewares.Provision, middlewares.Provision,
middlewares.Parse("image_export"), middlewares.Parse("image_export"),
middlewares.Language(),
handlers.ExportImage, handlers.ExportImage,
), ),
}, },

29
go.mod
View File

@@ -5,16 +5,18 @@ go 1.12
require ( require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Microsoft/go-winio v0.4.14 // indirect github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/apex/log v1.1.1 github.com/apex/log v1.1.2
github.com/briandowns/spinner v1.7.0 github.com/briandowns/spinner v1.9.0
github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v0.0.0-20190313072916-46036c230805 github.com/docker/docker v0.0.0-20190313072916-46036c230805
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.3.3 // indirect github.com/docker/go-units v0.3.3 // indirect
github.com/dsnet/compress v0.0.1 // indirect github.com/dsnet/compress v0.0.1 // indirect
github.com/gin-gonic/gin v1.4.0 github.com/gin-gonic/gin v1.4.0
github.com/gobuffalo/packr v1.30.1 github.com/gobuffalo/envy v1.8.1 // indirect
github.com/golang/mock v1.3.1 github.com/gobuffalo/packd v0.3.0
github.com/gobuffalo/packr/v2 v2.8.0
github.com/golang/mock v1.4.1
github.com/golang/snappy v0.0.1 // indirect github.com/golang/snappy v0.0.1 // indirect
github.com/google/go-querystring v1.0.0 github.com/google/go-querystring v1.0.0
github.com/google/uuid v1.1.1 github.com/google/uuid v1.1.1
@@ -22,7 +24,7 @@ require (
github.com/gorilla/mux v1.7.3 // indirect github.com/gorilla/mux v1.7.3 // indirect
github.com/imdario/mergo v0.3.7 // indirect github.com/imdario/mergo v0.3.7 // indirect
github.com/logrusorgru/aurora v0.0.0-20191017060258-dc85c304c434 github.com/logrusorgru/aurora v0.0.0-20191017060258-dc85c304c434
github.com/metrue/go-ssh-client v0.0.0-20191209160027-5773243a8bc9 github.com/metrue/go-ssh-client v0.0.0-20191219103445-1f07b67e2b29
github.com/mholt/archiver v3.1.1+incompatible github.com/mholt/archiver v3.1.1+incompatible
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
@@ -30,18 +32,21 @@ require (
github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter v0.0.4
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/otiai10/copy v1.0.2 github.com/otiai10/copy v1.1.1
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/pierrec/lz4 v0.0.0-20190222153722-062282ea0dcf // indirect github.com/pierrec/lz4 v0.0.0-20190222153722-062282ea0dcf // indirect
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.9.1
github.com/spf13/viper v1.6.1 github.com/rogpeppe/go-internal v1.5.1 // indirect
github.com/stretchr/testify v1.4.0 github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.6.2
github.com/stretchr/testify v1.5.1
github.com/ugorji/go v1.1.7 // indirect github.com/ugorji/go v1.1.7 // indirect
github.com/urfave/cli v1.22.2 github.com/urfave/cli v1.22.3
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect golang.org/x/crypto v0.0.0-20191219195013-becbf705a915 // indirect
golang.org/x/sys v0.0.0-20191223224216-5a3cf8467b4e // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.7 gopkg.in/yaml.v2 v2.2.7 // indirect
gotest.tools v2.2.0+incompatible // indirect gotest.tools v2.2.0+incompatible // indirect
k8s.io/api v0.0.0-20190925180651-d58b53da08f5 k8s.io/api v0.0.0-20190925180651-d58b53da08f5
k8s.io/apimachinery v0.0.0-20190925235427-62598f38f24e k8s.io/apimachinery v0.0.0-20190925235427-62598f38f24e

95
go.sum
View File

@@ -1,5 +1,6 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
@@ -20,8 +21,9 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apex/log v1.1.1 h1:BwhRZ0qbjYtTob0I+2M+smavV0kOC8XgcnGZcyL9liA= github.com/apex/log v1.1.2 h1:bnDuVoi+o98wOdVqfEzNDlY0tcmBia7r4YkjS9EqGYk=
github.com/apex/log v1.1.1/go.mod h1:Ls949n1HFtXfbDcjiTTFQqkVUrte0puoIBfO3SVgwOA= github.com/apex/log v1.1.2/go.mod h1:SyfRweFO+TlkIJ3DVizTSeI1xk7jOIIqOnUPZQTTsww=
github.com/apex/logs v0.0.3/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -29,8 +31,8 @@ github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/briandowns/spinner v1.7.0 h1:aan1hBBOoscry2TXAkgtxkJiq7Se0+9pt+TUWaPrB4g= github.com/briandowns/spinner v1.9.0 h1:+OMAisemaHar1hjuJ3Z2hIvNhQl9Y7GLPWUwwz2Pxo8=
github.com/briandowns/spinner v1.7.0/go.mod h1://Zf9tMcxfRUA36V23M6YGEAv+kECGfvpnLTnb8n4XQ= github.com/briandowns/spinner v1.9.0/go.mod h1://Zf9tMcxfRUA36V23M6YGEAv+kECGfvpnLTnb8n4XQ=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@@ -43,6 +45,7 @@ github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -87,12 +90,20 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.8.1 h1:RUr68liRvs0TS1D5qdW3mQv2SjAsu1QWMCx1tG4kDjs=
github.com/gobuffalo/envy v1.8.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
github.com/gobuffalo/logger v1.0.0 h1:xw9Ko9EcC5iAFprrjJ6oZco9UpzS5MQ4jAwghsLHdy4=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/logger v1.0.3 h1:YaXOTHNPCvkqqA7w05A4v0k2tCdpr+sgFlgINbQ6gqc=
github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM=
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM=
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI=
github.com/gobuffalo/packr/v2 v2.5.1 h1:TFOeY2VoGamPjQLiNDT3mn//ytzk236VMO2j7iHxJR4=
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
github.com/gobuffalo/packr/v2 v2.8.0 h1:IULGd15bQL59ijXLxEvA5wlMxsmx/ZkQv9T282zNVIY=
github.com/gobuffalo/packr/v2 v2.8.0/go.mod h1:PDk2k3vGevNE3SwVyVRgQCCXETC9SaONCNSXT1Q8M1g=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
@@ -105,6 +116,8 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -131,6 +144,7 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -147,6 +161,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
@@ -158,10 +173,13 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU= github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU=
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/karrick/godirwalk v1.15.3 h1:0a2pXOgtB16CqIqXTiT7+K9L73f74n/aNQUnH6Ortew=
github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -183,6 +201,12 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -191,15 +215,11 @@ github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/metrue/go-ssh-client v0.0.0-20191125030649-4ac058ee958b h1:JGD0sJ44XzhsT1voOg00zji4ubuMNcVNK3m7d9GI88k= github.com/metrue/go-ssh-client v0.0.0-20191219103445-1f07b67e2b29 h1:ENoMPMVc24XbBuVZ7guZmTB/7MSd+vqOkImSu9UUiJw=
github.com/metrue/go-ssh-client v0.0.0-20191125030649-4ac058ee958b/go.mod h1:ERHOEBrDy6+8vfoJjjmhdmBpOzdvvP7bLtwYTTK6LOs= github.com/metrue/go-ssh-client v0.0.0-20191219103445-1f07b67e2b29/go.mod h1:aPG/JtXTyLliKDDlkv+nzHbSbz2p2CBMAjNJRK4uhzY=
github.com/metrue/go-ssh-client v0.0.0-20191209160027-5773243a8bc9 h1:HHfMhG77ZLn3FOH3AGXW/F5RpAABVH6Fr5mVZZ97S6w=
github.com/metrue/go-ssh-client v0.0.0-20191209160027-5773243a8bc9/go.mod h1:aPG/JtXTyLliKDDlkv+nzHbSbz2p2CBMAjNJRK4uhzY=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU=
github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
@@ -222,8 +242,6 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs= github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.3 h1:i0LBnzgiChAWHJYTQAZJDOgf8MNxAVYZJ2m63SIDimI=
github.com/olekukonko/tablewriter v0.0.3/go.mod h1:YZeBtGzYYEsCHp2LST/u/0NDwGkRoBtmn1cIWCJiS6M=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -237,8 +255,14 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/otiai10/copy v1.0.2 h1:DDNipYy6RkIkjMwy+AWzgKiNTyj2RUI9yEMeETEpVyc= github.com/otiai10/copy v1.0.2 h1:DDNipYy6RkIkjMwy+AWzgKiNTyj2RUI9yEMeETEpVyc=
github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY=
github.com/otiai10/copy v1.1.1 h1:PH7IFlRQ6Fv9vYmuXbDRLdgTHoP1w483kPNUP2bskpo=
github.com/otiai10/copy v1.1.1/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95 h1:+OLn68pqasWca0z5ryit9KGfp3sUsW4Lqg32iRMJyzs=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@@ -249,6 +273,8 @@ github.com/pierrec/lz4 v0.0.0-20190222153722-062282ea0dcf/go.mod h1:3/3N9NVKO0je
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -267,6 +293,10 @@ github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.5.1 h1:asQ0uD7BN9RU5Im41SEEZTwCi/zAXdMOLS3npYaos2g=
github.com/rogpeppe/go-internal v1.5.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
@@ -279,8 +309,10 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@@ -292,15 +324,19 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -310,6 +346,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
@@ -325,10 +363,10 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8= github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.3 h1:FpNT6zq26xNpHZy08emi755QwzLPs6Pukqjlc7RfOMU=
github.com/urfave/cli v1.22.3/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@@ -347,11 +385,16 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915 h1:aJ0ex187qoXrJHPo8ZasVTASQB7llQP6YeNzgDALPRk=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -368,6 +411,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68= golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68=
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -379,6 +423,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -394,9 +439,10 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 h1:LepdCS8Gf/MVejFIt8lsiexZATdoGVyp5bcyS+rYoUI= golang.org/x/sys v0.0.0-20191223224216-5a3cf8467b4e h1:z2Flw7sLy7DxaQi3zDOvI9X+Kb06+G9iZJlkEyHvujE=
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191223224216-5a3cf8467b4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -416,6 +462,11 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -475,6 +526,10 @@ k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKf
k8s.io/utils v0.0.0-20190920012459-5008bf6f8cd6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20190920012459-5008bf6f8cd6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20190923111123-69764acb6e8e h1:BXSmdH6S3YGLlhC89DZp+sNdYSmwNeDU6Xu5ZpzGOlM= k8s.io/utils v0.0.0-20190923111123-69764acb6e8e h1:BXSmdH6S3YGLlhC89DZp+sNdYSmwNeDU6Xu5ZpzGOlM=
k8s.io/utils v0.0.0-20190923111123-69764acb6e8e/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20190923111123-69764acb6e8e/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -6,13 +6,12 @@ import (
"time" "time"
"github.com/apex/log" "github.com/apex/log"
"github.com/metrue/fx/bundle"
"github.com/metrue/fx/constants" "github.com/metrue/fx/constants"
containerruntimes "github.com/metrue/fx/container_runtimes" containerruntimes "github.com/metrue/fx/container_runtimes"
"github.com/metrue/fx/context" "github.com/metrue/fx/context"
"github.com/metrue/fx/packer" "github.com/metrue/fx/hook"
"github.com/metrue/fx/pkg/spinner" "github.com/metrue/fx/pkg/spinner"
"github.com/metrue/fx/utils"
"github.com/otiai10/copy"
) )
// BuildImage build image // BuildImage build image
@@ -24,22 +23,17 @@ func BuildImage(ctx context.Contexter) (err error) {
workdir := fmt.Sprintf("/tmp/fx-%d", time.Now().Unix()) workdir := fmt.Sprintf("/tmp/fx-%d", time.Now().Unix())
defer os.RemoveAll(workdir) defer os.RemoveAll(workdir)
sources := ctx.Get("sources").([]string) fn := ctx.Get("fn").(string)
deps := ctx.Get("deps").([]string)
language := ctx.Get("language").(string)
if len(sources) == 0 { if err := bundle.Bundle(workdir, language, fn, deps...); err != nil {
return fmt.Errorf("source file/directory of function required")
}
if len(sources) == 1 &&
utils.IsDir(sources[0]) &&
utils.HasDockerfile(sources[0]) {
if err := copy.Copy(sources[0], workdir); err != nil {
return err return err
} }
} else {
if err := packer.Pack(workdir, sources...); err != nil { if err := hook.RunBeforeBuildHook(workdir); err != nil {
return err return err
} }
}
docker := ctx.Get("docker").(containerruntimes.ContainerRuntime) docker := ctx.Get("docker").(containerruntimes.ContainerRuntime)
nameWithTag := ctx.Get("tag").(string) + ":latest" nameWithTag := ctx.Get("tag").(string) + ":latest"
@@ -53,22 +47,18 @@ func BuildImage(ctx context.Contexter) (err error) {
// ExportImage export service's code into a directory // ExportImage export service's code into a directory
func ExportImage(ctx context.Contexter) (err error) { func ExportImage(ctx context.Contexter) (err error) {
outputDir := ctx.Get("output").(string) outputDir := ctx.Get("output").(string)
sources := ctx.Get("sources").([]string) fn := ctx.Get("fn").(string)
deps := ctx.Get("deps").([]string)
if len(sources) == 0 { language := ctx.Get("language").(string)
return fmt.Errorf("source file/directory of function required")
} if err := bundle.Bundle(outputDir, language, fn, deps...); err != nil {
if len(sources) == 1 &&
utils.IsDir(sources[0]) &&
utils.HasDockerfile(sources[0]) {
if err := copy.Copy(sources[0], outputDir); err != nil {
return err return err
} }
} else {
if err := packer.Pack(outputDir, sources...); err != nil { if err := hook.RunBeforeBuildHook(outputDir); err != nil {
return err return err
} }
}
log.Infof("exported to %v: %v", outputDir, constants.CheckedSymbol) log.Infof("exported to %v: %v", outputDir, constants.CheckedSymbol)
return nil return nil

View File

@@ -3,19 +3,19 @@ package handlers
import ( import (
"github.com/metrue/fx/context" "github.com/metrue/fx/context"
"github.com/metrue/fx/infra" "github.com/metrue/fx/infra"
"github.com/metrue/fx/pkg/render" "github.com/metrue/fx/pkg/renderrer"
) )
// List command handle // List command handle
func List(ctx context.Contexter) (err error) { func List(ctx context.Contexter) (err error) {
cli := ctx.GetCliContext() cli := ctx.GetCliContext()
deployer := ctx.Get("deployer").(infra.Deployer) deployer := ctx.Get("deployer").(infra.Deployer)
format := ctx.Get("format").(string)
services, err := deployer.List(ctx.GetContext(), cli.Args().First()) services, err := deployer.List(ctx.GetContext(), cli.Args().First())
if err != nil { if err != nil {
return err return err
} }
render.Table(services) return renderrer.Render(services, format)
return nil
} }

View File

@@ -1,9 +1,10 @@
package handlers package handlers
import ( import (
"github.com/apex/log"
"github.com/metrue/fx/context" "github.com/metrue/fx/context"
"github.com/metrue/fx/infra" "github.com/metrue/fx/infra"
"github.com/metrue/fx/pkg/render" "github.com/metrue/fx/pkg/renderrer"
"github.com/metrue/fx/types" "github.com/metrue/fx/types"
) )
@@ -20,6 +21,12 @@ func Up(ctx context.Contexter) (err error) {
name := ctx.Get("name").(string) name := ctx.Get("name").(string)
deployer := ctx.Get("deployer").(infra.Deployer) deployer := ctx.Get("deployer").(infra.Deployer)
bindings := ctx.Get("bindings").([]types.PortBinding) bindings := ctx.Get("bindings").([]types.PortBinding)
force := ctx.Get("force").(bool)
if force && name != "" {
if err := deployer.Destroy(ctx.GetContext(), name); err != nil {
log.Warnf("destroy service %s failed: %v", name, err)
}
}
if err := deployer.Deploy( if err := deployer.Deploy(
ctx.GetContext(), ctx.GetContext(),
@@ -35,6 +42,5 @@ func Up(ctx context.Contexter) (err error) {
if err != nil { if err != nil {
return err return err
} }
render.Table([]types.Service{service}) return renderrer.Render([]types.Service{service}, "table")
return nil
} }

View File

@@ -11,6 +11,7 @@ import (
) )
func TestUp(t *testing.T) { func TestUp(t *testing.T) {
t.Run("normally up", func(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
@@ -26,6 +27,7 @@ func TestUp(t *testing.T) {
ctx.EXPECT().Get("deployer").Return(deployer) ctx.EXPECT().Get("deployer").Return(deployer)
ctx.EXPECT().Get("bindings").Return(bindings) ctx.EXPECT().Get("bindings").Return(bindings)
ctx.EXPECT().Get("data").Return(data) ctx.EXPECT().Get("data").Return(data)
ctx.EXPECT().Get("force").Return(false)
ctx.EXPECT().GetContext().Return(context.Background()).Times(2) ctx.EXPECT().GetContext().Return(context.Background()).Times(2)
deployer.EXPECT().Deploy(gomock.Any(), data, name, image, bindings).Return(nil) deployer.EXPECT().Deploy(gomock.Any(), data, name, image, bindings).Return(nil)
deployer.EXPECT().GetStatus(gomock.Any(), name).Return(types.Service{ deployer.EXPECT().GetStatus(gomock.Any(), name).Return(types.Service{
@@ -37,4 +39,36 @@ func TestUp(t *testing.T) {
if err := Up(ctx); err != nil { if err := Up(ctx); err != nil {
t.Fatal(err) t.Fatal(err)
} }
})
t.Run("normally up forcely", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := mockCtx.NewMockContexter(ctrl)
deployer := mockDeployer.NewMockDeployer(ctrl)
bindings := []types.PortBinding{}
name := "sample-name"
image := "sample-image"
data := "sample-data"
ctx.EXPECT().Get("name").Return(name)
ctx.EXPECT().Get("image").Return(image)
ctx.EXPECT().Get("deployer").Return(deployer)
ctx.EXPECT().Get("bindings").Return(bindings)
ctx.EXPECT().Get("data").Return(data)
ctx.EXPECT().Get("force").Return(true)
ctx.EXPECT().GetContext().Return(context.Background()).Times(3)
deployer.EXPECT().Deploy(gomock.Any(), data, name, image, bindings).Return(nil)
deployer.EXPECT().Destroy(gomock.Any(), name).Return(nil)
deployer.EXPECT().GetStatus(gomock.Any(), name).Return(types.Service{
ID: "id-1",
Name: name,
Host: "127.0.0.1",
Port: 2100,
}, nil)
if err := Up(ctx); err != nil {
t.Fatal(err)
}
})
} }

1
hook/.hooks/before_build Normal file
View File

@@ -0,0 +1 @@
npm install

15
hook/fixture/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "fixture",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"leftpad": "0.0.1"
}
}

73
hook/hook.go Normal file
View File

@@ -0,0 +1,73 @@
package hook
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"github.com/metrue/fx/utils"
)
// Hooker defines hook interface
type Hooker interface {
Run() error
}
// Hook to run
type Hook struct {
name string
script string
}
// New a hook
func New(name string, script string, workdir string) *Hook {
return &Hook{
name: name,
script: script,
}
}
// Run execute a hook
func (h *Hook) Run(workdir string) error {
var script string
if !utils.IsRegularFile(h.script) {
hookScript, err := ioutil.TempFile(os.TempDir(), "fx-hook-script-")
if err != nil {
return err
}
defer os.Remove(hookScript.Name())
content := []byte(h.script)
if _, err = hookScript.Write(content); err != nil {
return err
}
if err := hookScript.Close(); err != nil {
return err
}
script = hookScript.Name()
} else {
absScript, err := filepath.Abs(h.script)
if err != nil {
return err
}
script = absScript
}
cmd := exec.Command("/bin/sh", script)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if workdir != "" {
cmd.Dir = workdir
}
if err := cmd.Run(); err != nil {
return err
}
return nil
}
// Name hook name
func (h *Hook) Name() string {
return h.name
}

54
hook/hook_manager.go Normal file
View File

@@ -0,0 +1,54 @@
package hook
import (
"os"
"path/filepath"
"github.com/metrue/fx/utils"
)
// HookNameBeforeBuild before build hook
const HookNameBeforeBuild = "before_build"
// RunBeforeBuildHook trigger before_build hook
func RunBeforeBuildHook(workdir string) error {
hooks, err := descovery("")
if err != nil {
return err
}
for _, h := range hooks {
if h.Name() == HookNameBeforeBuild {
if err := h.Run(workdir); err != nil {
return err
}
}
}
return nil
}
func descovery(hookdir string) ([]*Hook, error) {
if hookdir == "" {
dir, err := os.Getwd()
if err != nil {
return nil, err
}
hookdir = filepath.Join(dir, ".hooks")
}
hooks := []*Hook{}
if !utils.IsDir(hookdir) {
return hooks, nil
}
if err := filepath.Walk(hookdir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.Name() == HookNameBeforeBuild {
hooks = append(hooks, New("before_build", path, ""))
}
return nil
}); err != nil {
return nil, err
}
return hooks, nil
}

40
hook/hook_manager_test.go Normal file
View File

@@ -0,0 +1,40 @@
package hook
import (
"os"
"path/filepath"
"testing"
)
func TestHookManager(t *testing.T) {
t.Run("descovery in default hookdir .hooks", func(t *testing.T) {
hooks, err := descovery("")
if err != nil {
t.Fatal(err)
}
if len(hooks) != 1 {
t.Fatalf("should have one hook, but got %d", len(hooks))
}
if hooks[0].Name() != HookNameBeforeBuild {
t.Fatalf("should be before_build hook, but got %s", hooks[0].Name())
}
})
t.Run("descovery in empty hookdir", func(t *testing.T) {
hooks, err := descovery(filepath.Join(os.TempDir(), ".hooks"))
if err != nil {
t.Fatal(err)
}
if len(hooks) != 0 {
t.Fatalf("should get 0 hooks, but got %d", len(hooks))
}
})
t.Run("run before_build hook", func(t *testing.T) {
if err := RunBeforeBuildHook("fixture"); err != nil {
t.Fatal(err)
}
})
}

21
hook/hook_test.go Normal file
View File

@@ -0,0 +1,21 @@
package hook
import (
"testing"
)
func TestHook(t *testing.T) {
t.Run("text", func(t *testing.T) {
h := New("before_build", "npm install leftpad", "fixture")
if err := h.Run("fixture"); err != nil {
t.Fatal(err)
}
})
t.Run("script", func(t *testing.T) {
h := New("before_build", ".hooks/before_build", "fixture")
if err := h.Run("fixture"); err != nil {
t.Fatal(err)
}
})
}

View File

@@ -86,12 +86,6 @@ func (d *Deployer) Ping(ctx context.Context) error {
// List services // List services
func (d *Deployer) List(ctx context.Context, name string) (svcs []types.Service, err error) { func (d *Deployer) List(ctx context.Context, name string) (svcs []types.Service, err error) {
const task = "listing"
spinner.Start(task)
defer func() {
spinner.Stop(task, err)
}()
// FIXME support remote host // FIXME support remote host
return d.cli.ListContainer(ctx, name) return d.cli.ListContainer(ctx, name)
} }

View File

@@ -1,5 +0,0 @@
{
"master": "52.78.196.250",
"agents": [
"13.125.243.192",
],

View File

@@ -5,13 +5,14 @@ import (
"os" "os"
"time" "time"
"github.com/metrue/fx/bundle"
containerruntimes "github.com/metrue/fx/container_runtimes" containerruntimes "github.com/metrue/fx/container_runtimes"
"github.com/metrue/fx/context" "github.com/metrue/fx/context"
"github.com/metrue/fx/hook"
"github.com/metrue/fx/packer" "github.com/metrue/fx/packer"
"github.com/metrue/fx/pkg/spinner" "github.com/metrue/fx/pkg/spinner"
"github.com/metrue/fx/types" "github.com/metrue/fx/types"
"github.com/metrue/fx/utils" "github.com/metrue/fx/utils"
"github.com/otiai10/copy"
) )
// Build image // Build image
@@ -23,6 +24,9 @@ func Build(ctx context.Contexter) (err error) {
}() }()
workdir := fmt.Sprintf("/tmp/fx-%d", time.Now().Unix()) workdir := fmt.Sprintf("/tmp/fx-%d", time.Now().Unix())
if err := utils.EnsureDir(workdir); err != nil {
return err
}
defer os.RemoveAll(workdir) defer os.RemoveAll(workdir)
// Cases supports // Cases supports
@@ -35,23 +39,17 @@ func Build(ctx context.Contexter) (err error) {
// fx up func.js helper.js ./lib/ // fx up func.js helper.js ./lib/
// When only one directory given and there is a Dockerfile in given directory, treat it as a containerized project and skip packing // When only one directory given and there is a Dockerfile in given directory, treat it as a containerized project and skip packing
sources := ctx.Get("sources").([]string) fn := ctx.Get("fn").(string)
deps := ctx.Get("deps").([]string)
language := ctx.Get("language").(string)
if len(sources) == 0 { if err := bundle.Bundle(workdir, language, fn, deps...); err != nil {
return fmt.Errorf("source file/directory of function required")
}
if len(sources) == 1 &&
utils.IsDir(sources[0]) &&
utils.HasDockerfile(sources[0]) {
if err := copy.Copy(sources[0], workdir); err != nil {
return err return err
} }
} else {
if err := packer.Pack(workdir, sources...); err != nil { if err := hook.RunBeforeBuildHook(workdir); err != nil {
return err return err
} }
}
cloudType := ctx.Get("cloud_type").(string) cloudType := ctx.Get("cloud_type").(string)
name := ctx.Get("name").(string) name := ctx.Get("name").(string)
@@ -66,11 +64,11 @@ func Build(ctx context.Contexter) (err error) {
if err := docker.BuildImage(ctx.GetContext(), workdir, name); err != nil { if err := docker.BuildImage(ctx.GetContext(), workdir, name); err != nil {
return err return err
} }
nameWithTag := name + ":latest" nameWithTag := name + ":latest"
if err := docker.TagImage(ctx.GetContext(), name, nameWithTag); err != nil { if err := docker.TagImage(ctx.GetContext(), name, nameWithTag); err != nil {
return err return err
} }
ctx.Set("image", nameWithTag) ctx.Set("image", nameWithTag)
} }

23
middlewares/language.go Normal file
View File

@@ -0,0 +1,23 @@
package middlewares
import (
"fmt"
"path/filepath"
"github.com/metrue/fx/constants"
"github.com/metrue/fx/context"
)
// Language to find out what language of function is
func Language() func(ctx context.Contexter) (err error) {
return func(ctx context.Contexter) error {
fn := ctx.Get("fn").(string)
ext := filepath.Ext(fn)
language, ok := constants.ExtLangMapping[ext]
if !ok {
return fmt.Errorf("%s not supported yet", ext)
}
ctx.Set("language", language)
return nil
}
}

View File

@@ -0,0 +1,19 @@
package middlewares
import (
"testing"
"github.com/golang/mock/gomock"
mockCtx "github.com/metrue/fx/context/mocks"
)
func TestLanguage(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := mockCtx.NewMockContexter(ctrl)
ctx.EXPECT().Get("fn").Return("/tmp/fx.js")
ctx.EXPECT().Set("language", "node")
if err := Language()(ctx); err != nil {
t.Fatal(err)
}
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/metrue/fx/context" "github.com/metrue/fx/context"
"github.com/metrue/fx/utils"
) )
// Parse parse input // Parse parse input
@@ -13,15 +14,29 @@ func Parse(action string) func(ctx context.Contexter) (err error) {
cli := ctx.GetCliContext() cli := ctx.GetCliContext()
switch action { switch action {
case "up": case "up":
sources := []string{} if !cli.Args().Present() {
for _, s := range cli.Args() { return fmt.Errorf("no function given")
sources = append(sources, s)
} }
ctx.Set("sources", sources)
if !utils.IsRegularFile(cli.Args().First()) {
return fmt.Errorf("invalid function source file: %s", cli.Args().First())
}
ctx.Set("fn", cli.Args().First())
deps := []string{}
for ind, s := range cli.Args() {
if ind != 0 {
deps = append(deps, s)
}
}
ctx.Set("deps", deps)
name := cli.String("name") name := cli.String("name")
ctx.Set("name", name) ctx.Set("name", name)
port := cli.Int("port") port := cli.Int("port")
ctx.Set("port", port) ctx.Set("port", port)
force := cli.Bool("force")
ctx.Set("force", force)
case "down": case "down":
services := cli.Args() services := cli.Args()
if len(services) == 0 { if len(services) == 0 {
@@ -35,23 +50,49 @@ func Parse(action string) func(ctx context.Contexter) (err error) {
case "list": case "list":
name := cli.Args().First() name := cli.Args().First()
ctx.Set("filter", name) ctx.Set("filter", name)
format := cli.String("format")
ctx.Set("format", format)
case "image_build": case "image_build":
sources := []string{} if !cli.Args().Present() {
for _, s := range cli.Args() { return fmt.Errorf("no function given")
sources = append(sources, s)
} }
ctx.Set("sources", sources)
if !utils.IsRegularFile(cli.Args().First()) {
return fmt.Errorf("invalid function source file: %s", cli.Args().First())
}
ctx.Set("fn", cli.Args().First())
deps := []string{}
for ind, s := range cli.Args() {
if ind != 0 {
deps = append(deps, s)
}
}
ctx.Set("deps", deps)
tag := cli.String("tag") tag := cli.String("tag")
if tag == "" { if tag == "" {
tag = uuid.New().String() tag = uuid.New().String()
} }
ctx.Set("tag", tag) ctx.Set("tag", tag)
case "image_export": case "image_export":
sources := []string{} if !cli.Args().Present() {
for _, s := range cli.Args() { return fmt.Errorf("no function given")
sources = append(sources, s)
} }
ctx.Set("sources", sources)
if !utils.IsRegularFile(cli.Args().First()) {
return fmt.Errorf("invalid function source file: %s", cli.Args().First())
}
ctx.Set("fn", cli.Args().First())
deps := []string{}
for ind, s := range cli.Args() {
if ind != 0 {
deps = append(deps, s)
}
}
ctx.Set("deps", deps)
outputDir := cli.String("output") outputDir := cli.String("output")
if outputDir == "" { if outputDir == "" {
return fmt.Errorf("output directory required") return fmt.Errorf("output directory required")

53
middlewares/parse_test.go Normal file
View File

@@ -0,0 +1,53 @@
package middlewares
import (
"io/ioutil"
"os"
"testing"
"flag"
"github.com/golang/mock/gomock"
mockCtx "github.com/metrue/fx/context/mocks"
"github.com/urfave/cli"
)
func TestParse(t *testing.T) {
t.Run("source code not existed", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := mockCtx.NewMockContexter(ctrl)
argset := flag.NewFlagSet("test", 0)
cli := cli.NewContext(nil, argset, nil)
argset.Parse([]string{"this_file_should_not_existed"})
ctx.EXPECT().GetCliContext().Return(cli)
if err := Parse("up")(ctx); err == nil {
t.Fatal("should got file or directory not existed error")
}
})
t.Run("source code ready", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := mockCtx.NewMockContexter(ctrl)
argset := flag.NewFlagSet("test", 0)
cli := cli.NewContext(nil, argset, nil)
fd, err := ioutil.TempFile("", "fx_func_*.js")
if err != nil {
t.Fatal(err)
}
defer os.Remove(fd.Name())
argset.Parse([]string{fd.Name()})
ctx.EXPECT().GetCliContext().Return(cli)
ctx.EXPECT().Set("fn", fd.Name())
ctx.EXPECT().Set("deps", []string{})
ctx.EXPECT().Set("name", "")
ctx.EXPECT().Set("port", 0)
ctx.EXPECT().Set("force", false)
if err := Parse("up")(ctx); err != nil {
t.Fatal(err)
}
})
}

View File

@@ -59,8 +59,8 @@ func Provision(ctx context.Contexter) (err error) {
if os.Getenv("KUBECONFIG") != "" { if os.Getenv("KUBECONFIG") != "" {
cloudType = types.CloudTypeK8S cloudType = types.CloudTypeK8S
conf = os.Getenv("KUBECONFIG") conf = os.Getenv("KUBECONFIG")
}
ctx.Set("cloud_type", types.CloudTypeK8S) ctx.Set("cloud_type", types.CloudTypeK8S)
}
if cloudType == types.CloudTypeDocker { if cloudType == types.CloudTypeDocker {
var meta map[string]string var meta map[string]string

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +0,0 @@
FROM php:latest
COPY . .
EXPOSE 3000
CMD php -S 0.0.0.0:3000

View File

@@ -1,4 +0,0 @@
<?php
function Fx($input) {
return $input["a"]+$input["b"];
}

Some files were not shown because too many files have changed in this diff Show More