Full Code of Code-Hex/Neo-cowsay for AI

master f68c20f068c2 cached
123 files
112.2 KB
39.9k tokens
145 symbols
1 requests
Download .txt
Repository: Code-Hex/Neo-cowsay
Branch: master
Commit: f68c20f068c2
Files: 123
Total size: 112.2 KB

Directory structure:
gitextract_va4xlec5/

├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── lgtm.yml
│       ├── main.yml
│       └── release.yml
├── .gitignore
├── .goreleaser.yml
├── LICENSE
├── Makefile
├── README.md
├── balloon.go
├── bin/
│   └── .gitkeep
├── cmd/
│   ├── cmd.go
│   ├── cowsay/
│   │   └── main.go
│   ├── cowthink/
│   │   └── main.go
│   ├── go.mod
│   ├── go.sum
│   ├── internal/
│   │   ├── cli/
│   │   │   ├── cli.go
│   │   │   └── cli_test.go
│   │   ├── screen/
│   │   │   ├── buffer.go
│   │   │   └── screen.go
│   │   └── super/
│   │       └── supercow.go
│   └── testdata/
│       ├── cowsay/
│       │   ├── W_option.txt
│       │   ├── b_option.txt
│       │   ├── d_option.txt
│       │   ├── eyes_option.txt
│       │   ├── f_tux_option.txt
│       │   ├── g_option.txt
│       │   ├── n_option.txt
│       │   ├── p_option.txt
│       │   ├── s_option.txt
│       │   ├── t_option.txt
│       │   ├── tongue_option.txt
│       │   ├── wired_option.txt
│       │   └── y_option.txt
│       └── cowthink/
│           ├── W_option.txt
│           ├── b_option.txt
│           ├── d_option.txt
│           ├── eyes_option.txt
│           ├── f_tux_option.txt
│           ├── g_option.txt
│           ├── n_option.txt
│           ├── p_option.txt
│           ├── s_option.txt
│           ├── t_option.txt
│           ├── tongue_option.txt
│           ├── wired_option.txt
│           └── y_option.txt
├── cow.go
├── cow_test.go
├── cows/
│   ├── beavis.zen.cow
│   ├── bong.cow
│   ├── bud-frogs.cow
│   ├── bunny.cow
│   ├── cheese.cow
│   ├── cower.cow
│   ├── daemon.cow
│   ├── default.cow
│   ├── deno.cow
│   ├── docker.cow
│   ├── dragon-and-cow.cow
│   ├── dragon.cow
│   ├── elephant-in-snake.cow
│   ├── elephant.cow
│   ├── eyes.cow
│   ├── flaming-sheep.cow
│   ├── ghostbusters.cow
│   ├── gopher.cow
│   ├── head-in.cow
│   ├── hellokitty.cow
│   ├── kiss.cow
│   ├── kitty.cow
│   ├── koala.cow
│   ├── kosh.cow
│   ├── luke-koala.cow
│   ├── meow.cow
│   ├── milk.cow
│   ├── moofasa.cow
│   ├── moose.cow
│   ├── mutilated.cow
│   ├── ren.cow
│   ├── sage.cow
│   ├── satanic.cow
│   ├── sheep.cow
│   ├── skeleton.cow
│   ├── small.cow
│   ├── sodomized.cow
│   ├── squirrel.cow
│   ├── stegosaurus.cow
│   ├── stimpy.cow
│   ├── supermilker.cow
│   ├── surgery.cow
│   ├── telebears.cow
│   ├── turkey.cow
│   ├── turtle.cow
│   ├── tux.cow
│   ├── vader-koala.cow
│   ├── vader.cow
│   └── www.cow
├── cowsay.go
├── cowsay_test.go
├── decoration/
│   ├── aurora.go
│   ├── bold.go
│   ├── decoration.go
│   └── rainbow.go
├── doc/
│   ├── cowsay.1
│   └── cowsay.1.txt.tpl
├── embed.go
├── examples/
│   ├── basic/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── echo-server/
│       ├── README.md
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── go.mod
├── go.sum
├── split.go
├── split_windows.go
└── testdata/
    ├── default.cow
    ├── nest.cow
    └── testdir/
        └── test.cow

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
* @Code-Hex

================================================
FILE: .github/FUNDING.yml
================================================
github: Code-Hex


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "daily"
  - package-ecosystem: "gomod"
    directory: "/"
    schedule:
      interval: "daily"


================================================
FILE: .github/workflows/lgtm.yml
================================================
on:
  pull_request_review:
    types:
      - submitted

jobs:
  lgtm:
    name: LGTM
    runs-on: ubuntu-latest
    if: github.event.review.state == 'approved'
    steps:
    - name: Cowsay LGTM
      uses: Code-Hex/neo-cowsay-action@v1.0.2
      with:
        message: 'LGTM'
        cow: 'random'
        cowsay_on_comment: true
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

================================================
FILE: .github/workflows/main.yml
================================================
on:
  push:
    branches:
      - "master"
  pull_request:

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
    name: test
    runs-on: ${{ matrix.os }}
    steps:
    - name: Setup Go 1.17.2
      uses: actions/setup-go@v2
      with:
        go-version: 1.17.2
    - name: Check out code into the Go module directory
      uses: actions/checkout@v3
    - name: Vet
      run: make vet
    - name: Test
      run: make test
    - name: Lint
      if: matrix.os == 'ubuntu-latest'
      run: |
        go get golang.org/x/lint/golint
        export PATH="$PATH:$(go env GOPATH)/bin"
        make lint
      env:
        GO111MODULE: off
    - name: Declare some variables
      if: matrix.os == 'ubuntu-latest'
      id: vars
      run: |
        echo "::set-output name=coverage_txt::${RUNNER_TEMP}/coverage.txt"
    - name: Test Coverage (pkg)
      if: matrix.os == 'ubuntu-latest'
      run: go test ./... -coverprofile=${{ steps.vars.outputs.coverage_txt }}
    - name: Upload coverage
      if: matrix.os == 'ubuntu-latest'
      uses: codecov/codecov-action@v3
      with:
        files: ${{ steps.vars.outputs.coverage_txt }}

================================================
FILE: .github/workflows/release.yml
================================================
on:
  push:
    tags:
      - "v*.*.*"

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
    - name: Setup Go 1.17.2
      uses: actions/setup-go@v2
      with:
        go-version: 1.17.2
    - name: Check out code into the Go module directory
      uses: actions/checkout@v3
    - name: Run GoReleaser
      if: contains(github.ref, 'tags/v')
      uses: goreleaser/goreleaser-action@v2
      with:
        version: latest
        args: release --rm-dist
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}

  winget:
    runs-on: ubuntu-latest
    needs: release
    steps:
      - uses: vedantmgoyal2009/winget-releaser@v2
        with:
          identifier: codehex.Neo-cowsay
          installers-regex: '_Windows_\w+\.zip$'
          token: ${{ secrets.WINGET_TOKEN }}


================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof

github-token
build
releases
bin/*
!bin/.gitkeep


================================================
FILE: .goreleaser.yml
================================================
builds:
  - id: cowsay
    dir: cmd
    main: ./cowsay/main.go
    binary: cowsay
    env:
      - CGO_ENABLED=0
    ldflags: -s -w -X main.version={{.Version}}
    goos:
      - linux
      - darwin
      - windows
    goarch:
      - 386
      - amd64
      - arm
      - arm64
    goarm:
      - 6
      - 7
    ignore:
      - goos: darwin
        goarch: 386
      - goos: linux
        goarch: arm
        goarm: 7
      - goos: windows
        goarch: arm
        goarm: 7
  - id: cowthink
    dir: cmd
    main: ./cowthink/main.go
    binary: cowthink
    env:
      - CGO_ENABLED=0
    ldflags: -s -w -X main.version={{.Version}}
    goos:
      - linux
      - darwin
      - windows
    goarch:
      - 386
      - amd64
      - arm
      - arm64
    goarm:
      - 6
      - 7
    ignore:
      - goos: darwin
        goarch: 386
      - goos: linux
        goarch: arm
        goarm: 7
      - goos: windows
        goarch: arm
        goarm: 7

archives:
- builds:
  - cowsay
  - cowthink
  name_template: 'cowsay_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
  replacements:
    darwin: macOS
    linux: Linux
    windows: Windows
    386: i386
    amd64: x86_64
  format_overrides:
  - goos: windows
    format: zip
  files:
  - LICENSE
  - doc/cowsay.1

brews:
- name: neo-cowsay
  tap:
    owner: Code-Hex
    name: homebrew-tap
    token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
  homepage: https://github.com/Code-Hex/Neo-cowsay
  description: "Fast, funny, everyone wanted? new cowsay!!"
  folder: Formula
  install: |
    bin.install "cowsay"
    bin.install "cowthink"
    man1.install Dir["doc/cowsay.1"]

nfpms:
  - license: Artistic License 2.0
    maintainer: Kei Kamikawa <x00.x7f.x86@gmail.com>
    homepage: https://github.com/Code-Hex/Neo-cowsay
    bindir: /usr/local/bin
    description: "Fast, funny, everyone wanted? new cowsay!!"
    formats:
      - apk
      - deb
      - rpm
    contents:
      - src: "doc/cowsay.1"
        dst: "/usr/share/man/man1/cowsay.1"

checksum:
  name_template: 'cowsay_checksums.txt'

changelog:
  sort: asc
  filters:
    exclude:
    - '^docs:'
    - '^test:'
    - Merge pull request
    - Merge branch


================================================
FILE: LICENSE
================================================
		       The Artistic License 2.0

	    Copyright (c) 2000-2006, The Perl Foundation.

     Everyone is permitted to copy and distribute verbatim copies
      of this license document, but changing it is not allowed.

Preamble

This license establishes the terms under which a given free software
Package may be copied, modified, distributed, and/or redistributed.
The intent is that the Copyright Holder maintains some artistic
control over the development of that Package while still keeping the
Package available as open source and free software.

You are always permitted to make arrangements wholly outside of this
license directly with the Copyright Holder of a given Package.  If the
terms of this license do not permit the full use that you propose to
make of the Package, you should contact the Copyright Holder and seek
a different licensing arrangement.

Definitions

    "Copyright Holder" means the individual(s) or organization(s)
    named in the copyright notice for the entire Package.

    "Contributor" means any party that has contributed code or other
    material to the Package, in accordance with the Copyright Holder's
    procedures.

    "You" and "your" means any person who would like to copy,
    distribute, or modify the Package.

    "Package" means the collection of files distributed by the
    Copyright Holder, and derivatives of that collection and/or of
    those files. A given Package may consist of either the Standard
    Version, or a Modified Version.

    "Distribute" means providing a copy of the Package or making it
    accessible to anyone else, or in the case of a company or
    organization, to others outside of your company or organization.

    "Distributor Fee" means any fee that you charge for Distributing
    this Package or providing support for this Package to another
    party.  It does not mean licensing fees.

    "Standard Version" refers to the Package if it has not been
    modified, or has been modified only in ways explicitly requested
    by the Copyright Holder.

    "Modified Version" means the Package, if it has been changed, and
    such changes were not explicitly requested by the Copyright
    Holder.

    "Original License" means this Artistic License as Distributed with
    the Standard Version of the Package, in its current version or as
    it may be modified by The Perl Foundation in the future.

    "Source" form means the source code, documentation source, and
    configuration files for the Package.

    "Compiled" form means the compiled bytecode, object code, binary,
    or any other form resulting from mechanical transformation or
    translation of the Source form.


Permission for Use and Modification Without Distribution

(1)  You are permitted to use the Standard Version and create and use
Modified Versions for any purpose without restriction, provided that
you do not Distribute the Modified Version.


Permissions for Redistribution of the Standard Version

(2)  You may Distribute verbatim copies of the Source form of the
Standard Version of this Package in any medium without restriction,
either gratis or for a Distributor Fee, provided that you duplicate
all of the original copyright notices and associated disclaimers.  At
your discretion, such verbatim copies may or may not include a
Compiled form of the Package.

(3)  You may apply any bug fixes, portability changes, and other
modifications made available from the Copyright Holder.  The resulting
Package will still be considered the Standard Version, and as such
will be subject to the Original License.


Distribution of Modified Versions of the Package as Source

(4)  You may Distribute your Modified Version as Source (either gratis
or for a Distributor Fee, and with or without a Compiled form of the
Modified Version) provided that you clearly document how it differs
from the Standard Version, including, but not limited to, documenting
any non-standard features, executables, or modules, and provided that
you do at least ONE of the following:

    (a)  make the Modified Version available to the Copyright Holder
    of the Standard Version, under the Original License, so that the
    Copyright Holder may include your modifications in the Standard
    Version.

    (b)  ensure that installation of your Modified Version does not
    prevent the user installing or running the Standard Version. In
    addition, the Modified Version must bear a name that is different
    from the name of the Standard Version.

    (c)  allow anyone who receives a copy of the Modified Version to
    make the Source form of the Modified Version available to others
    under

	(i)  the Original License or

	(ii)  a license that permits the licensee to freely copy,
	modify and redistribute the Modified Version using the same
	licensing terms that apply to the copy that the licensee
	received, and requires that the Source form of the Modified
	Version, and of any works derived from it, be made freely
	available in that license fees are prohibited but Distributor
	Fees are allowed.


Distribution of Compiled Forms of the Standard Version
or Modified Versions without the Source

(5)  You may Distribute Compiled forms of the Standard Version without
the Source, provided that you include complete instructions on how to
get the Source of the Standard Version.  Such instructions must be
valid at the time of your distribution.  If these instructions, at any
time while you are carrying out such distribution, become invalid, you
must provide new instructions on demand or cease further distribution.
If you provide valid instructions or cease distribution within thirty
days after you become aware that the instructions are invalid, then
you do not forfeit any of your rights under this license.

(6)  You may Distribute a Modified Version in Compiled form without
the Source, provided that you comply with Section 4 with respect to
the Source of the Modified Version.


Aggregating or Linking the Package

(7)  You may aggregate the Package (either the Standard Version or
Modified Version) with other packages and Distribute the resulting
aggregation provided that you do not charge a licensing fee for the
Package.  Distributor Fees are permitted, and licensing fees for other
components in the aggregation are permitted. The terms of this license
apply to the use and Distribution of the Standard or Modified Versions
as included in the aggregation.

(8) You are permitted to link Modified and Standard Versions with
other works, to embed the Package in a larger work of your own, or to
build stand-alone binary or bytecode versions of applications that
include the Package, and Distribute the result without restriction,
provided the result does not expose a direct interface to the Package.


Items That are Not Considered Part of a Modified Version

(9) Works (including, but not limited to, modules and scripts) that
merely extend or make use of the Package, do not, by themselves, cause
the Package to be a Modified Version.  In addition, such works are not
considered parts of the Package itself, and are not subject to the
terms of this license.


General Provisions

(10)  Any use, modification, and distribution of the Standard or
Modified Versions is governed by this Artistic License. By using,
modifying or distributing the Package, you accept this license. Do not
use, modify, or distribute the Package, if you do not accept this
license.

(11)  If your Modified Version has been derived from a Modified
Version made by someone other than you, you are nevertheless required
to ensure that your Modified Version complies with the requirements of
this license.

(12)  This license does not grant you the right to use any trademark,
service mark, tradename, or logo of the Copyright Holder.

(13)  This license includes the non-exclusive, worldwide,
free-of-charge patent license to make, have made, use, offer to sell,
sell, import and otherwise transfer the Package with respect to any
patent claims licensable by the Copyright Holder that are necessarily
infringed by the Package. If you institute patent litigation
(including a cross-claim or counterclaim) against any party alleging
that the Package constitutes direct or contributory patent
infringement, then this Artistic License to you shall terminate on the
date that such litigation is filed.

(14)  Disclaimer of Warranty:
THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

================================================
FILE: Makefile
================================================
.PHONY: build
build: build/cowsay build/cowthink

.PHONY: build/cowsay
build/cowsay:
	CGO_ENABLED=0 cd cmd && go build -o ../bin/cowsay -ldflags "-w -s" ./cowsay

.PHONY: build/cowthink
build/cowthink:
	CGO_ENABLED=0 cd cmd && go build -o ../bin/cowthink -ldflags "-w -s" ./cowthink

.PHONY: lint
lint:
	golint ./...
	cd cmd && golint ./...

.PHONY: vet
vet:
	go vet ./...
	cd cmd && go vet ./...

.PHONY: test
test: test/pkg test/cli

.PHONY: test/pkg
test/pkg:
	go test ./...

.PHONY: test/cli
test/cli:
	cd cmd && go test ./...

.PHONY: man
man:
	asciidoctor --doctype manpage --backend manpage doc/cowsay.1.txt.tpl -o doc/cowsay.1

.PHONY: man/preview
man/preview:
	cat doc/cowsay.1 | groff -man -Tascii | less


================================================
FILE: README.md
================================================
# Neo Cowsay

Neo Cowsay is written in Go. This cowsay is extended the original cowsay. added fun more options, and you can be used as a library.

for GitHub Actions users: [Code-Hex/neo-cowsay-action](https://github.com/marketplace/actions/neo-cowsay)

[![Go Reference](https://pkg.go.dev/badge/github.com/Code-Hex/Neo-cowsay/v2.svg)](https://pkg.go.dev/github.com/Code-Hex/Neo-cowsay/v2) [![.github/workflows/main.yml](https://github.com/Code-Hex/Neo-cowsay/actions/workflows/main.yml/badge.svg)](https://github.com/Code-Hex/Neo-cowsay/actions/workflows/main.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/Code-Hex/Neo-cowsay)](https://goreportcard.com/report/github.com/Code-Hex/Neo-cowsay) [![codecov](https://codecov.io/gh/Code-Hex/Neo-cowsay/branch/master/graph/badge.svg?token=WwjmyHrOPv)](https://codecov.io/gh/Code-Hex/Neo-cowsay)

```
 ______________
< I'm Neo cows >
 --------------
       \   ^__^
        \  (oo)\_______
           (__)\       )\/\
               ||----w |
               ||     ||
```

## About cowsay

According to the [original](https://web.archive.org/web/20071026043648/http://www.nog.net/~tony/warez/cowsay.shtml) original manual.

```
cowsay is a configurable talking cow, written in Perl. It operates
much as the figlet program does, and it written in the same spirit
of silliness.
```

This is also supported `COWPATH` env. Please read more details in [#33](https://github.com/Code-Hex/Neo-cowsay/pull/33) if you want to use this.

## What makes it different from the original?

- fast
- utf8 is supported
- new some cowfiles is added
- cowfiles in binary
- random pickup cowfile option
- provides command-line fuzzy finder to search any cows with `-f -` [#39](https://github.com/Code-Hex/Neo-cowsay/pull/39)
- coloring filter options
- super mode

<details>
<summary>Movies for new options 🐮</summary>

### Random

[![asciicast](https://asciinema.org/a/228210.svg)](https://asciinema.org/a/228210)

### Rainbow and Aurora, Bold

[![asciicast](https://asciinema.org/a/228213.svg)](https://asciinema.org/a/228213)

## And, Super Cows mode

https://user-images.githubusercontent.com/6500104/140379043-53e44994-b1b0-442e-bda7-4f7ab3aedf01.mov

</details>

## Usage

### As command

```
cow{say,think} version 2.0.0, (c) 2021 codehex
Usage: cowsay [-bdgpstwy] [-h] [-e eyes] [-f cowfile] [--random]
      [-l] [-n] [-T tongue] [-W wrapcolumn]
      [--bold] [--rainbow] [--aurora] [--super] [message]

Original Author: (c) 1999 Tony Monroe
Repository: https://github.com/Code-Hex/Neo-cowsay
```
Normal
```
$ cowsay Hello
 _______
< Hello >
 -------
       \   ^__^
        \  (oo)\_______
           (__)\       )\/\
               ||----w |
               ||     ||
```
Borg mode
```
$ cowsay -b Hello
 _______
< Hello >
 -------
       \   ^__^
        \  (==)\_______
           (__)\       )\/\
               ||----w |
               ||     ||
```

### As library

```go
package main

import (
	"fmt"

	cowsay "github.com/Code-Hex/Neo-cowsay/v2"
)

func main() {
	say, err := cowsay.Say(
		"Hello",
		cowsay.Type("default"),
		cowsay.BallonWidth(40),
	)
	if err != nil {
		panic(err)
	}
	fmt.Println(say)
}
```

[Examples](https://github.com/Code-Hex/Neo-cowsay/blob/master/examples) or [GoDoc](https://pkg.go.dev/github.com/Code-Hex/Neo-cowsay/v2)

## Install

### Windows users via Scoop

    $ scoop install neo-cowsay

### Windows users via Winget

    $ winget install neo-cowsay

### Mac and Linux users via Homebrew

    $ brew update
    $ brew install Code-Hex/tap/neo-cowsay

### Binary

You can download from [here](https://github.com/Code-Hex/Neo-cowsay/releases)

### library

    $ go get github.com/Code-Hex/Neo-cowsay/v2

### Go

#### cowsay

    $ go install github.com/Code-Hex/Neo-cowsay/cmd/v2/cowsay@latest

#### cowthink

    $ go install github.com/Code-Hex/Neo-cowsay/cmd/v2/cowthink@latest

## License

<details>
<summary>cowsay license</summary>

```
==============
cowsay License
==============

cowsay is distributed under the same licensing terms as Perl: the
Artistic License or the GNU General Public License.  If you don't
want to track down these licenses and read them for yourself, use
the parts that I'd prefer:

(0) I wrote it and you didn't.

(1) Give credit where credit is due if you borrow the code for some
other purpose.

(2) If you have any bugfixes or suggestions, please notify me so
that I may incorporate them.

(3) If you try to make money off of cowsay, you suck.

===============
cowsay Legalese
===============

(0) Copyright (c) 1999 Tony Monroe.  All rights reserved.  All
lefts may or may not be reversed at my discretion.

(1) This software package can be freely redistributed or modified
under the terms described above in the "cowsay License" section
of this file.

(2) cowsay is provided "as is," with no warranties whatsoever,
expressed or implied.  If you want some implied warranty about
merchantability and/or fitness for a particular purpose, you will
not find it here, because there is no such thing here.

(3) I hate legalese.
```

</details>

(The Artistic License or The GNU General Public License)

## Author
Neo Cowsay: [codehex](https://twitter.com/CodeHex)  
Original: (c) 1999 Tony Monroe


================================================
FILE: balloon.go
================================================
package cowsay

import (
	"fmt"
	"strings"

	wordwrap "github.com/Code-Hex/go-wordwrap"
	runewidth "github.com/mattn/go-runewidth"
)

type border struct {
	first  [2]rune
	middle [2]rune
	last   [2]rune
	only   [2]rune
}

func (cow *Cow) borderType() border {
	if cow.thinking {
		return border{
			first:  [2]rune{'(', ')'},
			middle: [2]rune{'(', ')'},
			last:   [2]rune{'(', ')'},
			only:   [2]rune{'(', ')'},
		}
	}

	return border{
		first:  [2]rune{'/', '\\'},
		middle: [2]rune{'|', '|'},
		last:   [2]rune{'\\', '/'},
		only:   [2]rune{'<', '>'},
	}
}

type line struct {
	text      string
	runeWidth int
}

type lines []*line

func (cow *Cow) maxLineWidth(lines []*line) int {
	maxWidth := 0
	for _, line := range lines {
		if line.runeWidth > maxWidth {
			maxWidth = line.runeWidth
		}
		if !cow.disableWordWrap && maxWidth > cow.ballonWidth {
			return cow.ballonWidth
		}
	}
	return maxWidth
}

func (cow *Cow) getLines(phrase string) []*line {
	text := cow.canonicalizePhrase(phrase)
	lineTexts := strings.Split(text, "\n")
	lines := make([]*line, 0, len(lineTexts))
	for _, lineText := range lineTexts {
		lines = append(lines, &line{
			text:      lineText,
			runeWidth: runewidth.StringWidth(lineText),
		})
	}
	return lines
}

func (cow *Cow) canonicalizePhrase(phrase string) string {
	// Replace tab to 8 spaces
	phrase = strings.Replace(phrase, "\t", "       ", -1)

	if cow.disableWordWrap {
		return phrase
	}
	width := cow.ballonWidth
	return wordwrap.WrapString(phrase, uint(width))
}

// Balloon to get the balloon and the string entered in the balloon.
func (cow *Cow) Balloon(phrase string) string {
	defer cow.buf.Reset()

	lines := cow.getLines(phrase)
	maxWidth := cow.maxLineWidth(lines)

	cow.writeBallon(lines, maxWidth)

	return cow.buf.String()
}

func (cow *Cow) writeBallon(lines []*line, maxWidth int) {
	top := make([]byte, 0, maxWidth+2)
	bottom := make([]byte, 0, maxWidth+2)

	top = append(top, ' ')
	bottom = append(bottom, ' ')

	for i := 0; i < maxWidth+2; i++ {
		top = append(top, '_')
		bottom = append(bottom, '-')
	}

	borderType := cow.borderType()

	cow.buf.Write(top)
	cow.buf.Write([]byte{' ', '\n'})
	defer func() {
		cow.buf.Write(bottom)
		cow.buf.Write([]byte{' ', '\n'})
	}()

	l := len(lines)
	if l == 1 {
		border := borderType.only
		cow.buf.WriteRune(border[0])
		cow.buf.WriteRune(' ')
		cow.buf.WriteString(lines[0].text)
		cow.buf.WriteRune(' ')
		cow.buf.WriteRune(border[1])
		cow.buf.WriteRune('\n')
		return
	}

	var border [2]rune
	for i := 0; i < l; i++ {
		switch i {
		case 0:
			border = borderType.first
		case l - 1:
			border = borderType.last
		default:
			border = borderType.middle
		}
		cow.buf.WriteRune(border[0])
		cow.buf.WriteRune(' ')
		cow.padding(lines[i], maxWidth)
		cow.buf.WriteRune(' ')
		cow.buf.WriteRune(border[1])
		cow.buf.WriteRune('\n')
	}
}

func (cow *Cow) flush(text, top, bottom fmt.Stringer) string {
	return fmt.Sprintf(
		"%s\n%s%s\n",
		top.String(),
		text.String(),
		bottom.String(),
	)
}

func (cow *Cow) padding(line *line, maxWidth int) {
	if maxWidth <= line.runeWidth {
		cow.buf.WriteString(line.text)
		return
	}

	cow.buf.WriteString(line.text)
	l := maxWidth - line.runeWidth
	for i := 0; i < l; i++ {
		cow.buf.WriteRune(' ')
	}
}


================================================
FILE: bin/.gitkeep
================================================


================================================
FILE: cmd/cmd.go
================================================
package cmd


================================================
FILE: cmd/cowsay/main.go
================================================
package main

import (
	"os"

	"github.com/Code-Hex/Neo-cowsay/cmd/v2/internal/cli"
)

var version string

func main() {
	os.Exit((&cli.CLI{
		Version:  version,
		Thinking: false,
	}).Run(os.Args[1:]))
}


================================================
FILE: cmd/cowthink/main.go
================================================
package main

import (
	"os"

	"github.com/Code-Hex/Neo-cowsay/cmd/v2/internal/cli"
)

var version string

func main() {
	os.Exit((&cli.CLI{
		Version:  version,
		Thinking: true,
	}).Run(os.Args[1:]))
}


================================================
FILE: cmd/go.mod
================================================
module github.com/Code-Hex/Neo-cowsay/cmd/v2

go 1.16

require (
	github.com/Code-Hex/Neo-cowsay/v2 v2.0.3
	github.com/Code-Hex/go-wordwrap v1.0.0
	github.com/google/go-cmp v0.5.6
	github.com/jessevdk/go-flags v1.5.0
	github.com/ktr0731/go-fuzzyfinder v0.5.1
	github.com/mattn/go-colorable v0.1.11
	github.com/mattn/go-runewidth v0.0.13
	github.com/rivo/uniseg v0.2.0
	golang.org/x/crypto v0.1.0
)

replace github.com/Code-Hex/Neo-cowsay/v2 => ../


================================================
FILE: cmd/go.sum
================================================
github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=
github.com/Code-Hex/go-wordwrap v1.0.0/go.mod h1:/SsbgkY2Q0aPQRyvXcyQwWYTQOIwSORKe6MPjRVGIWU=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM=
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/ktr0731/go-fuzzyfinder v0.5.1 h1:rDcWxmGi6ux4NURekn9iAXpbYBp8Kj4cznrz162S9og=
github.com/ktr0731/go-fuzzyfinder v0.5.1/go.mod h1:gud27uRG2vF+oD58eGhYZj7Pc9enRX0qecwp09w/jno=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/nsf/termbox-go v0.0.0-20201124104050-ed494de23a00 h1:Rl8NelBe+n7SuLbJyw13ho7CGWUt2BjGGKIoreCWQ/c=
github.com/nsf/termbox-go v0.0.0-20201124104050-ed494de23a00/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=


================================================
FILE: cmd/internal/cli/cli.go
================================================
package cli

import (
	"bufio"
	cryptorand "crypto/rand"
	"errors"
	"fmt"
	"io"
	"math"
	"math/big"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/Code-Hex/Neo-cowsay/cmd/v2/internal/super"
	cowsay "github.com/Code-Hex/Neo-cowsay/v2"
	"github.com/Code-Hex/Neo-cowsay/v2/decoration"
	"github.com/Code-Hex/go-wordwrap"
	"github.com/jessevdk/go-flags"
	"github.com/ktr0731/go-fuzzyfinder"
	"github.com/mattn/go-colorable"
)

func init() {
	// safely set the seed globally so we generate random ids. Tries to use a
	// crypto seed before falling back to time.
	var seed int64
	cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64))
	if err != nil {
		// This should not happen, but worst-case fallback to time-based seed.
		seed = time.Now().UnixNano()
	} else {
		seed = cryptoseed.Int64()
	}
	rand.Seed(seed)
}

// options struct for parse command line arguments
type options struct {
	Help     bool   `short:"h"`
	Eyes     string `short:"e"`
	Tongue   string `short:"T"`
	Width    int    `short:"W"`
	Borg     bool   `short:"b"`
	Dead     bool   `short:"d"`
	Greedy   bool   `short:"g"`
	Paranoia bool   `short:"p"`
	Stoned   bool   `short:"s"`
	Tired    bool   `short:"t"`
	Wired    bool   `short:"w"`
	Youthful bool   `short:"y"`
	List     bool   `short:"l"`
	NewLine  bool   `short:"n"`
	File     string `short:"f"`
	Bold     bool   `long:"bold"`
	Super    bool   `long:"super"`
	Random   bool   `long:"random"`
	Rainbow  bool   `long:"rainbow"`
	Aurora   bool   `long:"aurora"`
}

// CLI prepare for running command-line.
type CLI struct {
	Version  string
	Thinking bool
	stderr   io.Writer
	stdout   io.Writer
	stdin    io.Reader
}

func (c *CLI) program() string {
	if c.Thinking {
		return "cowthink"
	}
	return "cowsay"
}

// Run runs command-line.
func (c *CLI) Run(argv []string) int {
	if c.stderr == nil {
		c.stderr = os.Stderr
	}
	if c.stdout == nil {
		c.stdout = colorable.NewColorableStdout()
	}
	if c.stdin == nil {
		c.stdin = os.Stdin
	}
	if err := c.mow(argv); err != nil {
		fmt.Fprintf(c.stderr, "%s: %s\n", c.program(), err.Error())
		return 1
	}
	return 0
}

// mow will parsing for cowsay command line arguments and invoke cowsay.
func (c *CLI) mow(argv []string) error {
	var opts options
	args, err := c.parseOptions(&opts, argv)
	if err != nil {
		return err
	}

	if opts.List {
		cowPaths, err := cowsay.Cows()
		if err != nil {
			return err
		}
		for _, cowPath := range cowPaths {
			if cowPath.LocationType == cowsay.InBinary {
				fmt.Fprintf(c.stdout, "Cow files in binary:\n")
			} else {
				fmt.Fprintf(c.stdout, "Cow files in %s:\n", cowPath.Name)
			}
			fmt.Fprintln(c.stdout, wordwrap.WrapString(strings.Join(cowPath.CowFiles, " "), 80))
			fmt.Fprintln(c.stdout)
		}
		return nil
	}

	if err := c.mowmow(&opts, args); err != nil {
		return err
	}

	return nil
}

func (c *CLI) parseOptions(opts *options, argv []string) ([]string, error) {
	p := flags.NewParser(opts, flags.None)
	args, err := p.ParseArgs(argv)
	if err != nil {
		return nil, err
	}

	if opts.Help {
		c.stdout.Write(c.usage())
		os.Exit(0)
	}

	return args, nil
}

func (c *CLI) usage() []byte {
	year := strconv.Itoa(time.Now().Year())
	return []byte(c.program() + ` version ` + c.Version + `, (c) ` + year + ` codehex
Usage: ` + c.program() + ` [-bdgpstwy] [-h] [-e eyes] [-f cowfile] [--random]
          [-l] [-n] [-T tongue] [-W wrapcolumn]
          [--bold] [--rainbow] [--aurora] [--super] [message]

Original Author: (c) 1999 Tony Monroe
`)
}

func (c *CLI) generateOptions(opts *options) []cowsay.Option {
	o := make([]cowsay.Option, 0, 8)
	if opts.File == "-" {
		cows := cowList()
		idx, _ := fuzzyfinder.Find(cows, func(i int) string {
			return cows[i]
		})
		opts.File = cows[idx]
	}
	o = append(o, cowsay.Type(opts.File))
	if c.Thinking {
		o = append(o,
			cowsay.Thinking(),
			cowsay.Thoughts('o'),
		)
	}
	if opts.Random {
		o = append(o, cowsay.Random())
	}
	if opts.Eyes != "" {
		o = append(o, cowsay.Eyes(opts.Eyes))
	}
	if opts.Tongue != "" {
		o = append(o, cowsay.Tongue(opts.Tongue))
	}
	if opts.Width > 0 {
		o = append(o, cowsay.BallonWidth(uint(opts.Width)))
	}
	if opts.NewLine {
		o = append(o, cowsay.DisableWordWrap())
	}
	return selectFace(opts, o)
}

func cowList() []string {
	cows, err := cowsay.Cows()
	if err != nil {
		return cowsay.CowsInBinary()
	}
	list := make([]string, 0)
	for _, cow := range cows {
		list = append(list, cow.CowFiles...)
	}
	return list
}

func (c *CLI) phrase(opts *options, args []string) string {
	if len(args) > 0 {
		return strings.Join(args, " ")
	}
	lines := make([]string, 0, 40)
	scanner := bufio.NewScanner(c.stdin)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return strings.Join(lines, "\n")
}

func (c *CLI) mowmow(opts *options, args []string) error {
	phrase := c.phrase(opts, args)
	o := c.generateOptions(opts)
	if opts.Super {
		return super.RunSuperCow(phrase, opts.Bold, o...)
	}

	say, err := cowsay.Say(phrase, o...)
	if err != nil {
		var notfound *cowsay.NotFound
		if errors.As(err, &notfound) {
			return fmt.Errorf("could not find %s cowfile", notfound.Cowfile)
		}
		return err
	}

	options := make([]decoration.Option, 0)

	if opts.Bold {
		options = append(options, decoration.WithBold())
	}
	if opts.Rainbow {
		options = append(options, decoration.WithRainbow())
	}
	if opts.Aurora {
		options = append(options, decoration.WithAurora(rand.Intn(256)))
	}

	w := decoration.NewWriter(c.stdout, options...)
	fmt.Fprintln(w, say)

	return nil
}

func selectFace(opts *options, o []cowsay.Option) []cowsay.Option {
	switch {
	case opts.Borg:
		o = append(o,
			cowsay.Eyes("=="),
			cowsay.Tongue("  "),
		)
	case opts.Dead:
		o = append(o,
			cowsay.Eyes("xx"),
			cowsay.Tongue("U "),
		)
	case opts.Greedy:
		o = append(o,
			cowsay.Eyes("$$"),
			cowsay.Tongue("  "),
		)
	case opts.Paranoia:
		o = append(o,
			cowsay.Eyes("@@"),
			cowsay.Tongue("  "),
		)
	case opts.Stoned:
		o = append(o,
			cowsay.Eyes("**"),
			cowsay.Tongue("U "),
		)
	case opts.Tired:
		o = append(o,
			cowsay.Eyes("--"),
			cowsay.Tongue("  "),
		)
	case opts.Wired:
		o = append(o,
			cowsay.Eyes("OO"),
			cowsay.Tongue("  "),
		)
	case opts.Youthful:
		o = append(o,
			cowsay.Eyes(".."),
			cowsay.Tongue("  "),
		)
	}
	return o
}


================================================
FILE: cmd/internal/cli/cli_test.go
================================================
package cli

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
)

func TestCLI_Run(t *testing.T) {
	clis := []struct {
		name     string
		thinking bool
	}{
		{
			name:     "cowsay",
			thinking: false,
		},
		{
			name:     "cowthink",
			thinking: true,
		},
	}
	for _, cli := range clis {
		cli := cli
		t.Run(cli.name, func(t *testing.T) {
			t.Parallel()
			tests := []struct {
				name     string
				phrase   string
				argv     []string
				testfile string
			}{
				{
					name:     "ignore wordwrap option",
					phrase:   "foo\nbar\nbaz",
					argv:     []string{"-n"},
					testfile: "n_option.txt",
				},
				{
					name:     "tired option",
					phrase:   "tired",
					argv:     []string{"-t"},
					testfile: "t_option.txt",
				},
				{
					name:     "specifies width of the ballon is 3",
					phrase:   "foobarbaz",
					argv:     []string{"-W", "3"},
					testfile: "W_option.txt",
				},
				{
					name:     "borg mode",
					phrase:   "foobarbaz",
					argv:     []string{"-b"},
					testfile: "b_option.txt",
				},
				{
					name:     "dead mode",
					phrase:   "0xdeadbeef",
					argv:     []string{"-d"},
					testfile: "d_option.txt",
				},
				{
					name:     "greedy mode",
					phrase:   "give me money",
					argv:     []string{"-g"},
					testfile: "g_option.txt",
				},
				{
					name:     "paranoid mode",
					phrase:   "everyone hates me",
					argv:     []string{"-p"},
					testfile: "p_option.txt",
				},
				{
					name:     "stoned mode",
					phrase:   "I don't know",
					argv:     []string{"-s"},
					testfile: "s_option.txt",
				},
				{
					name:     "wired mode",
					phrase:   "Wanna Netflix and chill?",
					argv:     []string{"-w"},
					testfile: "wired_option.txt",
				},
				{
					name:     "youthful mode",
					phrase:   "I forgot my ID at home",
					argv:     []string{"-y"},
					testfile: "y_option.txt",
				},
				{
					name:     "eyes option",
					phrase:   "I'm not angry",
					argv:     []string{"-e", "^^"},
					testfile: "eyes_option.txt",
				},
				{
					name:     "tongue option",
					phrase:   "hungry",
					argv:     []string{"-T", ":"},
					testfile: "tongue_option.txt",
				},
				{
					name:     "-f tux",
					phrase:   "what is macOS?",
					argv:     []string{"-f", "tux"},
					testfile: "f_tux_option.txt",
				},
			}
			for _, tt := range tests {
				tt := tt
				t.Run(tt.name, func(t *testing.T) {
					var stdout bytes.Buffer
					c := &CLI{
						Thinking: cli.thinking,
						stdout:   &stdout,
						stdin:    strings.NewReader(tt.phrase),
					}
					exit := c.Run(tt.argv)
					if exit != 0 {
						t.Fatalf("unexpected exit code: %d", exit)
					}
					testpath := filepath.Join("..", "..", "testdata", cli.name, tt.testfile)
					content, err := ioutil.ReadFile(testpath)
					if err != nil {
						t.Fatal(err)
					}
					got := strings.Replace(stdout.String(), "\r", "", -1)  // for windows
					want := strings.Replace(string(content), "\r", "", -1) // for windows
					if want != got {
						t.Log(cmp.Diff(want, got))
						t.Errorf("want\n%s\n-----got\n%s\n", want, got)
					}
				})
			}

			t.Run("program name", func(t *testing.T) {
				c := &CLI{Thinking: cli.thinking}
				if cli.name != c.program() {
					t.Fatalf("want %q, but got %q", cli.name, c.program())
				}
			})

			t.Run("not found cowfile", func(t *testing.T) {
				var stderr bytes.Buffer
				c := &CLI{
					Thinking: cli.thinking,
					stderr:   &stderr,
				}

				exit := c.Run([]string{"-f", "unknown"})
				if exit == 0 {
					t.Errorf("unexpected exit code: %d", exit)
				}
				want := fmt.Sprintf("%s: could not find unknown cowfile\n", cli.name)
				if want != stderr.String() {
					t.Errorf("want %q, but got %q", want, stderr.String())
				}
			})
		})
	}
}


================================================
FILE: cmd/internal/screen/buffer.go
================================================
package screen

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// buffer is the global screen buffer
// Its not recommended write to buffer dirrectly, use package Print,Printf,Println functions instead.
var buffer strings.Builder

// Flush buffer and ensure that it will not overflow screen
func Flush() string {
	defer buffer.Reset()
	return buffer.String()
}

// MoveWriter is implemented io.Writer and io.StringWriter.
type MoveWriter struct {
	idx  int
	x, y int
	w    io.Writer
	buf  bytes.Buffer
}

var _ interface {
	io.Writer
	io.StringWriter
} = (*MoveWriter)(nil)

// NewMoveWriter creates a new MoveWriter.
func NewMoveWriter(w io.Writer, x, y int) *MoveWriter {
	x, y = getXY(x, y)
	return &MoveWriter{
		w: w,
		x: x,
		y: y,
	}
}

// SetPosx sets pos x
func (m *MoveWriter) SetPosx(x int) {
	x, _ = getXY(x, 0)
	m.x = x
}

// Reset resets
func (m *MoveWriter) Reset() {
	m.idx = 0
	m.buf.Reset()
}

// Write writes bytes. which is implemented io.Writer.
func (m *MoveWriter) Write(bs []byte) (nn int, _ error) {
	br := bytes.NewReader(bs)
	for {
		b, err := br.ReadByte()
		if err != nil && err != io.EOF {
			return 0, err
		}
		if err == io.EOF {
			n, _ := fmt.Fprintf(m.w, "\x1b[%d;%dH%s\x1b[0K",
				m.y+m.idx,
				m.x,
				m.buf.String(),
			)
			nn += n
			return
		}
		if b == '\n' {
			n, _ := fmt.Fprintf(m.w, "\x1b[%d;%dH%s\x1b[0K",
				m.y+m.idx,
				m.x,
				m.buf.String(),
			)
			m.buf.Reset()
			m.idx++
			nn += n
		} else {
			m.buf.WriteByte(b)
		}
	}
}

// WriteString writes string. which is implemented io.StringWriter.
func (m *MoveWriter) WriteString(s string) (nn int, _ error) {
	for _, char := range s {
		if char == '\n' {
			n, _ := fmt.Fprintf(m.w, "\x1b[%d;%dH%s\x1b[0K",
				m.y+m.idx,
				m.x,
				m.buf.String(),
			)
			m.buf.Reset()
			m.idx++
			nn += n
		} else {
			m.buf.WriteRune(char)
		}
	}
	if m.buf.Len() > 0 {
		n, _ := fmt.Fprintf(m.w, "\x1b[%d;%dH%s\x1b[0K",
			m.y+m.idx,
			m.x,
			m.buf.String(),
		)
		nn += n
	}
	return
}

// getXY gets relative or absolute coorditantes
// To get relative, set PCT flag to number:
//
//      // Get 10% of total width to `x` and 20 to y
//      x, y = tm.GetXY(10|tm.PCT, 20)
//
func getXY(x int, y int) (int, int) {
	// Set percent flag: num | PCT
	//
	// Check percent flag: num & PCT
	//
	// Reset percent flag: num & 0xFF
	const shift = uint(^uint(0)>>63) << 4
	const PCT = 0x8000 << shift
	if y == -1 {
		y = currentHeight() + 1
	}

	if x&PCT != 0 {
		x = int((x & 0xFF) * Width() / 100)
	}

	if y&PCT != 0 {
		y = int((y & 0xFF) * Height() / 100)
	}

	return x, y
}

// currentHeight returns current height. Line count in Screen buffer.
func currentHeight() int {
	return strings.Count(buffer.String(), "\n")
}


================================================
FILE: cmd/internal/screen/screen.go
================================================
package screen

import (
	"os"
	"sync"

	colorable "github.com/mattn/go-colorable"
	"golang.org/x/crypto/ssh/terminal"
)

// Stdout color supported stdout
var Stdout = colorable.NewColorableStdout()

// SaveState saves cursor state.
func SaveState() { Stdout.Write([]byte("\0337")) }

// RestoreState restores cursor state.
func RestoreState() { Stdout.Write([]byte("\0338")) }

// Clear clears terminal screen.
func Clear() { Stdout.Write([]byte("\033[2J")) }

// HideCursor hide the cursor
func HideCursor() { Stdout.Write([]byte("\033[?25l")) }

// UnHideCursor unhide the cursor
func UnHideCursor() { Stdout.Write([]byte("\033[?25h")) }

var size struct {
	once   sync.Once
	width  int
	height int
}

func getSize() (int, int) {
	size.once.Do(func() {
		var err error
		size.width, size.height, err = terminal.GetSize(int(os.Stdout.Fd()))
		if err != nil {
			size.width, size.height = -1, -1
		}
	})
	return size.width, size.height
}

// Width returns console width
func Width() int {
	width, _ := getSize()
	return width
}

// Height returns console height
func Height() int {
	_, height := getSize()
	return height
}


================================================
FILE: cmd/internal/super/supercow.go
================================================
package super

import (
	"errors"
	"io"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/Code-Hex/Neo-cowsay/cmd/v2/internal/screen"
	cowsay "github.com/Code-Hex/Neo-cowsay/v2"
	"github.com/Code-Hex/Neo-cowsay/v2/decoration"
	runewidth "github.com/mattn/go-runewidth"
	"github.com/rivo/uniseg"
)

func getNoSaidCow(cow *cowsay.Cow, opts ...cowsay.Option) (string, error) {
	opts = append(opts, cowsay.Thoughts(' '))
	cow, err := cow.Clone(opts...)
	if err != nil {
		return "", err
	}
	return cow.GetCow()
}

// RunSuperCow runs super cow mode animation on the your terminal
func RunSuperCow(phrase string, withBold bool, opts ...cowsay.Option) error {
	cow, err := cowsay.New(opts...)
	if err != nil {
		return err
	}
	balloon := cow.Balloon(phrase)
	blank := createBlankSpace(balloon)

	said, err := cow.GetCow()
	if err != nil {
		return err
	}

	notSaid, err := getNoSaidCow(cow, opts...)
	if err != nil {
		return err
	}

	saidCow := balloon + said
	saidCowLines := strings.Count(saidCow, "\n") + 1

	// When it is higher than the height of the terminal
	h := screen.Height()
	if saidCowLines > h {
		return errors.New("too height messages")
	}

	notSaidCow := blank + notSaid

	renderer := newRenderer(saidCow, notSaidCow)

	screen.SaveState()
	screen.HideCursor()
	screen.Clear()

	go renderer.createFrames(cow, withBold)

	renderer.render()

	screen.UnHideCursor()
	screen.RestoreState()

	return nil
}

func createBlankSpace(balloon string) string {
	var buf strings.Builder
	l := strings.Count(balloon, "\n")
	for i := 0; i < l; i++ {
		buf.WriteRune('\n')
	}
	return buf.String()
}

func maxLen(cow []string) int {
	max := 0
	for _, line := range cow {
		l := runewidth.StringWidth(line)
		if max < l {
			max = l
		}
	}
	return max
}

type cowLine struct {
	raw      string
	clusters []rune
}

func (c *cowLine) Len() int {
	return len(c.clusters)
}

func (c *cowLine) Slice(i, j int) string {
	if c.Len() == 0 {
		return ""
	}
	return string(c.clusters[i:j])
}

func makeCowLines(cow string) []*cowLine {
	sep := strings.Split(cow, "\n")
	cowLines := make([]*cowLine, len(sep))
	for i, line := range sep {
		g := uniseg.NewGraphemes(line)
		clusters := make([]rune, 0)
		for g.Next() {
			clusters = append(clusters, g.Runes()...)
		}
		cowLines[i] = &cowLine{
			raw:      line,
			clusters: clusters,
		}
	}
	return cowLines
}

type renderer struct {
	max         int
	middle      int
	screenWidth int
	heightDiff  int
	frames      chan string

	saidCow         string
	notSaidCowLines []*cowLine

	quit chan os.Signal
}

func newRenderer(saidCow, notSaidCow string) *renderer {
	notSaidCowSep := strings.Split(notSaidCow, "\n")
	w, cowsWidth := screen.Width(), maxLen(notSaidCowSep)
	max := w + cowsWidth

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

	return &renderer{
		max:             max,
		middle:          max / 2,
		screenWidth:     w,
		heightDiff:      screen.Height() - strings.Count(saidCow, "\n") - 1,
		frames:          make(chan string, max),
		saidCow:         saidCow,
		notSaidCowLines: makeCowLines(notSaidCow),
		quit:            quit,
	}
}

const (
	// Frequency the color changes
	magic = 2

	span    = 30 * time.Millisecond
	standup = 3 * time.Second
)

func (r *renderer) createFrames(cow *cowsay.Cow, withBold bool) {
	const times = standup / span
	w := r.newWriter(withBold)

	for x, i := 0, 1; i <= r.max; i++ {
		if i == r.middle {
			w.SetPosx(r.posX(i))
			for k := 0; k < int(times); k++ {
				base := x * 70
				// draw colored cow
				w.SetColorSeq(base)
				w.WriteString(r.saidCow)
				r.frames <- w.String()
				if k%magic == 0 {
					x++
				}
			}
		} else {
			base := x * 70
			w.SetPosx(r.posX(i))
			w.SetColorSeq(base)

			for _, line := range r.notSaidCowLines {
				if i > r.screenWidth {
					// Left side animations
					n := i - r.screenWidth
					if n < line.Len() {
						w.WriteString(line.Slice(n, line.Len()))
					}
				} else if i <= line.Len() {
					// Right side animations
					w.WriteString(line.Slice(0, i-1))
				} else {
					w.WriteString(line.raw)
				}
				w.Write([]byte{'\n'})
			}
			r.frames <- w.String()
		}
		if i%magic == 0 {
			x++
		}
	}
	close(r.frames)
}

func (r *renderer) render() {
	initCh := make(chan struct{}, 1)
	initCh <- struct{}{}

	for view := range r.frames {
		select {
		case <-r.quit:
			screen.Clear()
			return
		case <-initCh:
		case <-time.After(span):
		}
		io.Copy(screen.Stdout, strings.NewReader(view))
	}
}

func (r *renderer) posX(i int) int {
	posx := r.screenWidth - i
	if posx < 1 {
		posx = 1
	}
	return posx
}

// Writer is wrapper which is both screen.MoveWriter and decoration.Writer.
type Writer struct {
	buf *strings.Builder
	mw  *screen.MoveWriter
	dw  *decoration.Writer
}

func (r *renderer) newWriter(withBold bool) *Writer {
	var buf strings.Builder
	mw := screen.NewMoveWriter(&buf, r.posX(0), r.heightDiff)
	options := []decoration.Option{
		decoration.WithAurora(0),
	}
	if withBold {
		options = append(options, decoration.WithBold())
	}
	dw := decoration.NewWriter(mw, options...)
	return &Writer{
		buf: &buf,
		mw:  mw,
		dw:  dw,
	}
}

// WriteString writes string. which is implemented io.StringWriter.
func (w *Writer) WriteString(s string) (int, error) { return w.dw.WriteString(s) }

// Write writes bytes. which is implemented io.Writer.
func (w *Writer) Write(p []byte) (int, error) { return w.dw.Write(p) }

// SetPosx sets posx
func (w *Writer) SetPosx(x int) { w.mw.SetPosx(x) }

// SetColorSeq sets color sequence.
func (w *Writer) SetColorSeq(colorSeq int) { w.dw.SetColorSeq(colorSeq) }

// Reset resets calls some Reset methods.
func (w *Writer) Reset() {
	w.buf.Reset()
	w.mw.Reset()
}

func (w *Writer) String() string {
	defer w.Reset()
	return w.buf.String()
}


================================================
FILE: cmd/testdata/cowsay/W_option.txt
================================================
 _____ 
/ foo \
| bar |
\ baz /
 ----- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/b_option.txt
================================================
 ___________ 
< foobarbaz >
 ----------- 
        \   ^__^
         \  (==)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/d_option.txt
================================================
 ____________ 
< 0xdeadbeef >
 ------------ 
        \   ^__^
         \  (xx)\_______
            (__)\       )\/\
             U  ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/eyes_option.txt
================================================
 _______________ 
< I'm not angry >
 --------------- 
        \   ^__^
         \  (^^)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/f_tux_option.txt
================================================
 ________________ 
< what is macOS? >
 ---------------- 
   \
    \
        .--.
       |o_o |
       |:_/ |
      //   \ \
     (|     | )
    /'\_   _/`\
    \___)=(___/



================================================
FILE: cmd/testdata/cowsay/g_option.txt
================================================
 _______________ 
< give me money >
 --------------- 
        \   ^__^
         \  ($$)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/n_option.txt
================================================
 _____ 
/ foo \
| bar |
\ baz /
 ----- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/p_option.txt
================================================
 ___________________ 
< everyone hates me >
 ------------------- 
        \   ^__^
         \  (@@)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/s_option.txt
================================================
 ______________ 
< I don't know >
 -------------- 
        \   ^__^
         \  (**)\_______
            (__)\       )\/\
             U  ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/t_option.txt
================================================
 _______ 
< tired >
 ------- 
        \   ^__^
         \  (--)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/tongue_option.txt
================================================
 ________ 
< hungry >
 -------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
             :  ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/wired_option.txt
================================================
 __________________________ 
< Wanna Netflix and chill? >
 -------------------------- 
        \   ^__^
         \  (OO)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowsay/y_option.txt
================================================
 ________________________ 
< I forgot my ID at home >
 ------------------------ 
        \   ^__^
         \  (..)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/W_option.txt
================================================
 _____ 
( foo )
( bar )
( baz )
 ----- 
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/b_option.txt
================================================
 ___________ 
( foobarbaz )
 ----------- 
        o   ^__^
         o  (==)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/d_option.txt
================================================
 ____________ 
( 0xdeadbeef )
 ------------ 
        o   ^__^
         o  (xx)\_______
            (__)\       )\/\
             U  ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/eyes_option.txt
================================================
 _______________ 
( I'm not angry )
 --------------- 
        o   ^__^
         o  (^^)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/f_tux_option.txt
================================================
 ________________ 
( what is macOS? )
 ---------------- 
   o
    o
        .--.
       |o_o |
       |:_/ |
      //   \ \
     (|     | )
    /'\_   _/`\
    \___)=(___/



================================================
FILE: cmd/testdata/cowthink/g_option.txt
================================================
 _______________ 
( give me money )
 --------------- 
        o   ^__^
         o  ($$)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/n_option.txt
================================================
 _____ 
( foo )
( bar )
( baz )
 ----- 
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/p_option.txt
================================================
 ___________________ 
( everyone hates me )
 ------------------- 
        o   ^__^
         o  (@@)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/s_option.txt
================================================
 ______________ 
( I don't know )
 -------------- 
        o   ^__^
         o  (**)\_______
            (__)\       )\/\
             U  ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/t_option.txt
================================================
 _______ 
( tired )
 ------- 
        o   ^__^
         o  (--)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/tongue_option.txt
================================================
 ________ 
( hungry )
 -------- 
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
             :  ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/wired_option.txt
================================================
 __________________________ 
( Wanna Netflix and chill? )
 -------------------------- 
        o   ^__^
         o  (OO)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cmd/testdata/cowthink/y_option.txt
================================================
 ________________________ 
( I forgot my ID at home )
 ------------------------ 
        o   ^__^
         o  (..)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


================================================
FILE: cow.go
================================================
package cowsay

import (
	"fmt"
	"math/rand"
	"strings"
)

// Cow struct!!
type Cow struct {
	eyes            string
	tongue          string
	typ             *CowFile
	thoughts        rune
	thinking        bool
	ballonWidth     int
	disableWordWrap bool

	buf strings.Builder
}

// New returns pointer of Cow struct that made by options
func New(options ...Option) (*Cow, error) {
	cow := &Cow{
		eyes:     "oo",
		tongue:   "  ",
		thoughts: '\\',
		typ: &CowFile{
			Name:         "default",
			BasePath:     "cows",
			LocationType: InBinary,
		},
		ballonWidth: 40,
	}
	for _, o := range options {
		if err := o(cow); err != nil {
			return nil, err
		}
	}
	return cow, nil
}

// Say returns string that said by cow
func (cow *Cow) Say(phrase string) (string, error) {
	mow, err := cow.GetCow()
	if err != nil {
		return "", err
	}
	return cow.Balloon(phrase) + mow, nil
}

// Clone returns a copy of cow.
//
// If any options are specified, they will be reflected.
func (cow *Cow) Clone(options ...Option) (*Cow, error) {
	ret := new(Cow)
	*ret = *cow
	ret.buf.Reset()
	for _, o := range options {
		if err := o(ret); err != nil {
			return nil, err
		}
	}
	return ret, nil
}

// Option defined for Options
type Option func(*Cow) error

// Eyes specifies eyes
// The specified string will always be adjusted to be equal to two characters.
func Eyes(s string) Option {
	return func(c *Cow) error {
		c.eyes = adjustTo2Chars(s)
		return nil
	}
}

// Tongue specifies tongue
// The specified string will always be adjusted to be less than or equal to two characters.
func Tongue(s string) Option {
	return func(c *Cow) error {
		c.tongue = adjustTo2Chars(s)
		return nil
	}
}

func adjustTo2Chars(s string) string {
	if len(s) >= 2 {
		return s[:2]
	}
	if len(s) == 1 {
		return s + " "
	}
	return "  "
}

func containCows(target string) (*CowFile, error) {
	cowPaths, err := Cows()
	if err != nil {
		return nil, err
	}
	for _, cowPath := range cowPaths {
		cowfile, ok := cowPath.Lookup(target)
		if ok {
			return cowfile, nil
		}
	}
	return nil, nil
}

// NotFound is indicated not found the cowfile.
type NotFound struct {
	Cowfile string
}

var _ error = (*NotFound)(nil)

func (n *NotFound) Error() string {
	return fmt.Sprintf("not found %q cowfile", n.Cowfile)
}

// Type specify name of the cowfile
func Type(s string) Option {
	if s == "" {
		s = "default"
	}
	return func(c *Cow) error {
		cowfile, err := containCows(s)
		if err != nil {
			return err
		}
		if cowfile != nil {
			c.typ = cowfile
			return nil
		}
		return &NotFound{Cowfile: s}
	}
}

// Thinking enables thinking mode
func Thinking() Option {
	return func(c *Cow) error {
		c.thinking = true
		return nil
	}
}

// Thoughts Thoughts allows you to specify
// the rune that will be drawn between
// the speech bubbles and the cow
func Thoughts(thoughts rune) Option {
	return func(c *Cow) error {
		c.thoughts = thoughts
		return nil
	}
}

// Random specifies something .cow from cows directory
func Random() Option {
	pick, err := pickCow()
	return func(c *Cow) error {
		if err != nil {
			return err
		}
		c.typ = pick
		return nil
	}
}

func pickCow() (*CowFile, error) {
	cowPaths, err := Cows()
	if err != nil {
		return nil, err
	}
	cowPath := cowPaths[rand.Intn(len(cowPaths))]

	n := len(cowPath.CowFiles)
	cowfile := cowPath.CowFiles[rand.Intn(n)]
	return &CowFile{
		Name:         cowfile,
		BasePath:     cowPath.Name,
		LocationType: cowPath.LocationType,
	}, nil
}

// BallonWidth specifies ballon size
func BallonWidth(size uint) Option {
	return func(c *Cow) error {
		c.ballonWidth = int(size)
		return nil
	}
}

// DisableWordWrap disables word wrap.
// Ignoring width of the ballon.
func DisableWordWrap() Option {
	return func(c *Cow) error {
		c.disableWordWrap = true
		return nil
	}
}


================================================
FILE: cow_test.go
================================================
package cowsay

import (
	"errors"
	"fmt"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
)

func TestCow_Clone(t *testing.T) {
	tests := []struct {
		name string
		opts []Option
		from *Cow
		want *Cow
	}{
		{
			name: "without options",
			opts: []Option{},
			from: func() *Cow {
				cow, _ := New()
				return cow
			}(),
			want: func() *Cow {
				cow, _ := New()
				return cow
			}(),
		},
		{
			name: "with some options",
			opts: []Option{},
			from: func() *Cow {
				cow, _ := New(
					Type("docker"),
					BallonWidth(60),
				)
				return cow
			}(),
			want: func() *Cow {
				cow, _ := New(
					Type("docker"),
					BallonWidth(60),
				)
				return cow
			}(),
		},
		{
			name: "clone and some options",
			opts: []Option{
				Thinking(),
				Thoughts('o'),
			},
			from: func() *Cow {
				cow, _ := New(
					Type("docker"),
					BallonWidth(60),
				)
				return cow
			}(),
			want: func() *Cow {
				cow, _ := New(
					Type("docker"),
					BallonWidth(60),
					Thinking(),
					Thoughts('o'),
				)
				return cow
			}(),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := tt.want.Clone(tt.opts...)
			if err != nil {
				t.Fatal(err)
			}
			if diff := cmp.Diff(tt.want, got,
				cmp.AllowUnexported(Cow{}),
				cmpopts.IgnoreFields(Cow{}, "buf")); diff != "" {
				t.Errorf("(-want, +got)\n%s", diff)
			}
		})
	}

	t.Run("random", func(t *testing.T) {
		cow, _ := New(
			Type(""),
			Thinking(),
			Thoughts('o'),
			Eyes("xx"),
			Tongue("u"),
			Random(),
		)

		cloned, _ := cow.Clone()

		if diff := cmp.Diff(cow, cloned,
			cmp.AllowUnexported(Cow{}),
			cmpopts.IgnoreFields(Cow{}, "buf")); diff != "" {
			t.Errorf("(-want, +got)\n%s", diff)
		}
	})

	t.Run("error", func(t *testing.T) {
		cow, err := New()
		if err != nil {
			t.Fatal(err)
		}

		wantErr := errors.New("error")
		_, err = cow.Clone(func(*Cow) error {
			return wantErr
		})
		if wantErr != err {
			t.Fatalf("want %v, but got %v", wantErr, err)
		}
	})
}

func Test_adjustTo2Chars(t *testing.T) {
	tests := []struct {
		name string
		s    string
		want string
	}{
		{
			name: "empty",
			s:    "",
			want: "  ",
		},
		{
			name: "1 character",
			s:    "1",
			want: "1 ",
		},
		{
			name: "2 characters",
			s:    "12",
			want: "12",
		},
		{
			name: "3 characters",
			s:    "123",
			want: "12",
		},
	}
	for _, tt := range tests {
		t.Run(tt.s, func(t *testing.T) {
			if got := adjustTo2Chars(tt.s); got != tt.want {
				t.Errorf("adjustTo2Chars() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestNotFound_Error(t *testing.T) {
	file := "test"
	n := &NotFound{
		Cowfile: file,
	}
	want := fmt.Sprintf("not found %q cowfile", file)
	if want != n.Error() {
		t.Fatalf("want %q but got %q", want, n.Error())
	}
}


================================================
FILE: cows/beavis.zen.cow
================================================
##
## Beavis, with Zen philosophy removed.
##
$the_cow = <<EOC;
   $thoughts         __------~~-,
    $thoughts      ,'            ,
          /               \\
         /                :
        |                  '
        |                  |
        |                  |
         |   _--           |
         _| =-.     .-.   ||
         o|/o/       _.   |
         /  ~          \\ |
       (____\@)  ___~    |
          |_===~~~.`    |
       _______.--~     |
       \\________       |
                \\      |
              __/-___-- -__
             /            _ \\
EOC


================================================
FILE: cows/bong.cow
================================================
##
## A cow with a bong, from lars@csua.berkeley.edu
##
$the_cow = <<EOC;
         $thoughts
          $thoughts
            ^__^ 
    _______/($eyes)
/\\/(       /(__)
   | W----|| |~|
   ||     || |~|  ~~
             |~|  ~
             |_| o
             |#|/
            _+#+_
EOC


================================================
FILE: cows/bud-frogs.cow
================================================
##
## The Budweiser frogs
##
$the_cow = <<EOC;
     $thoughts
      $thoughts
          oO)-.                       .-(Oo
         /__  _\\                     /_  __\\
         \\  \\(  |     ()~()         |  )/  /
          \\__|\\ |    (-___-)        | /|__/
          '  '--'    ==`-'==        '--'  '
EOC


================================================
FILE: cows/bunny.cow
================================================
##
## A cute little wabbit
##
$the_cow = <<EOC;
  $thoughts
   $thoughts   \\
        \\ /\\
        ( )
      .( o ).
EOC


================================================
FILE: cows/cheese.cow
================================================
##
## The cheese from milk & cheese
##
$the_cow = <<EOC;
   $thoughts
    $thoughts
      _____   _________
     /     \\_/         |
    |                 ||
    |                 ||
   |    ###\\  /###   | |
   |     0  \\/  0    | |
  /|                 | |
 / |        <        |\\ \\
| /|                 | | |
| |     \\_______/   |  | |
| |                 | / /
/||                 /|||
   ----------------|
        | |    | |
        ***    ***
       /___\\  /___\\
EOC


================================================
FILE: cows/cower.cow
================================================
##
## A cowering cow
##
$the_cow = <<EOC;
     $thoughts
      $thoughts
        ,__, |    | 
        (oo)\\|    |___
        (__)\\|    |   )\\_
             |    |_w |  \\
             |    |  ||   *

             Cower....
EOC


================================================
FILE: cows/daemon.cow
================================================
##
## 4.4 >> 5.4
##
$the_cow = <<EOC;
   $thoughts         ,        ,
    $thoughts       /(        )`
     $thoughts      \\ \\___   / |
            /- _  `-/  '
           (/\\/ \\ \\   /\\
           / /   | `    \\
           O O   ) /    |
           `-^--'`<     '
          (_.)  _  )   /
           `.___/`    /
             `-----' /
<----.     __ / __   \\
<----|====O)))==) \\) /====
<----'    `--' `.__,' \\
             |        |
              \\       /
        ______( (_  / \\______
      ,'  ,-----'   |        \\
      `--{__________)        \\/
EOC


================================================
FILE: cows/default.cow
================================================
$the_cow = <<EOC;
        $thoughts   ^__^
         $thoughts  ($eyes)\\_______
            (__)\\       )\\/\\
             $tongue ||----w |
                ||     ||
EOC


================================================
FILE: cows/deno.cow
================================================
## https://github.com/kawarimidoll/deno-cli-tools/blob/30107adad1dd7d00da8be08c76f843bbfd88b455/denosay/mod.ts#L64-L73
$the_cow = <<EOC;
     $thoughts
      $thoughts  _
        ( ・ヽ
          \ \
           ⎞ \
           |  `ヽ
           ⎩      ト、
            u¯u︶u
EOC

================================================
FILE: cows/docker.cow
================================================
##
## Docker Cow
##
$the_cow = <<EOC;
    $thoughts
     $thoughts
      $thoughts
                    ##         .
              ## ## ##        ==
           ## ## ## ## ##    ===
       /"""""""""""""""""\___/ ===
      {                       /  ===-
       \______ O           __/
         \    \         __/
          \____\_______/

EOC


================================================
FILE: cows/dragon-and-cow.cow
================================================
##
## A dragon smiting a cow, possible credit to kube@csua.berkeley.edu
##
$the_cow = <<EOC;
                       $thoughts                    ^    /^
                        $thoughts                  / \\  // \\
                         $thoughts   |\\___/|      /   \\//  .\\
                          $thoughts  /O  O  \\__  /    //  | \\ \\           *----*
                            /     /  \\/_/    //   |  \\  \\          \\   |
                            \@___\@`    \\/_   //    |   \\   \\         \\/\\ \\
                           0/0/|       \\/_ //     |    \\    \\         \\  \\
                       0/0/0/0/|        \\///      |     \\     \\       |  |
                    0/0/0/0/0/_|_ /   (  //       |      \\     _\\     |  /
                 0/0/0/0/0/0/`/,_ _ _/  ) ; -.    |    _ _\\.-~       /   /
                             ,-}        _      *-.|.-~-.           .~    ~
            \\     \\__/        `/\\      /                 ~-. _ .-~      /
             \\____($eyes)           *.   }            {                   /
             (    (--)          .----~-.\\        \\-`                 .~
             //__\\\\  \\__ Ack!   ///.----..<        \\             _ -~
            //    \\\\               ///-._ _ _ _ _ _ _{^ - - - - ~
EOC


================================================
FILE: cows/dragon.cow
================================================
##
## The Whitespace Dragon
##
$the_cow = <<EOC;
      $thoughts                    / \\  //\\
       $thoughts    |\\___/|      /   \\//  \\\\
            /0  0  \\__  /    //  | \\ \\    
           /     /  \\/_/    //   |  \\  \\  
           \@_^_\@'/   \\/_   //    |   \\   \\ 
           //_^_/     \\/_ //     |    \\    \\
        ( //) |        \\///      |     \\     \\
      ( / /) _|_ /   )  //       |      \\     _\\
    ( // /) '/,_ _ _/  ( ; -.    |    _ _\\.-~        .-~~~^-.
  (( / / )) ,-{        _      `-.|.-~-.           .~         `.
 (( // / ))  '/\\      /                 ~-. _ .-~      .-~^-.  \\
 (( /// ))      `.   {            }                   /      \\  \\
  (( / ))     .----~-.\\        \\-'                 .~         \\  `. \\^-.
             ///.----..>        \\             _ -~             `.  ^-`  ^-_
               ///-._ _ _ _ _ _ _}^ - - - - ~                     ~-- ,.-~
                                                                  /.-~
EOC


================================================
FILE: cows/elephant-in-snake.cow
================================================
##
## Do we need to explain this?
##
$the_cow = <<EOC;
   $thoughts
    $thoughts              ....       
           ........    .      
          .            .      
         .             .      
.........              .......
..............................

Elephant inside ASCII snake
EOC


================================================
FILE: cows/elephant.cow
================================================
##
## An elephant out and about
##
$the_cow = <<EOC;
 $thoughts     /\\  ___  /\\
  $thoughts   // \\/   \\/ \\\\
     ((    O O    ))
      \\\\ /     \\ //
       \\/  | |  \\/ 
        |  | |  |  
        |  | |  |  
        |   o   |  
        | |   | |  
        |m|   |m|  
EOC


================================================
FILE: cows/eyes.cow
================================================
##
## Evil-looking eyes
##
$the_cow = <<EOC;
    $thoughts
     $thoughts
                                   .::!!!!!!!:.
  .!!!!!:.                        .:!!!!!!!!!!!!
  ~~~~!!!!!!.                 .:!!!!!!!!!UWWW\$\$\$ 
      :\$\$NWX!!:           .:!!!!!!XUWW\$\$\$\$\$\$\$\$\$P 
      \$\$\$\$\$##WX!:      .<!!!!UW\$\$\$\$"  \$\$\$\$\$\$\$\$# 
      \$\$\$\$\$  \$\$\$UX   :!!UW\$\$\$\$\$\$\$\$\$   4\$\$\$\$\$* 
      ^\$\$\$B  \$\$\$\$\\     \$\$\$\$\$\$\$\$\$\$\$\$   d\$\$R" 
        "*\$bd\$\$\$\$      '*\$\$\$\$\$\$\$\$\$\$\$o+#" 
             """"          """"""" 
EOC


================================================
FILE: cows/flaming-sheep.cow
================================================
##
## The flaming sheep, contributed by Geordan Rosario (geordan@csua.berkeley.edu)
##
$the_cow = <<EOC;
  $thoughts            .    .     .   
   $thoughts      .  . .     `  ,     
    $thoughts    .; .  : .' :  :  : . 
     $thoughts   i..`: i` i.i.,i  i . 
      $thoughts   `,--.|i |i|ii|ii|i: 
           U${eyes}U\\.'\@\@\@\@\@\@`.||' 
           \\__/(\@\@\@\@\@\@\@\@\@\@)'  
                (\@\@\@\@\@\@\@\@)    
                `YY~~~~YY'    
                 ||    ||     
EOC


================================================
FILE: cows/ghostbusters.cow
================================================
##
## Ghostbusters!
##
$the_cow = <<EOC;
          $thoughts
           $thoughts
            $thoughts          __---__
                    _-       /--______
               __--( /     \\ )XXXXXXXXXXX\\v.
             .-XXX(   O   O  )XXXXXXXXXXXXXXX-
            /XXX(       U     )        XXXXXXX\\
          /XXXXX(              )--_  XXXXXXXXXXX\\
         /XXXXX/ (      O     )   XXXXXX   \\XXXXX\\
         XXXXX/   /            XXXXXX   \\__ \\XXXXX
         XXXXXX__/          XXXXXX         \\__---->
 ---___  XXX__/          XXXXXX      \\__         /
   \\-  --__/   ___/\\  XXXXXX            /  ___--/=
    \\-\\    ___/    XXXXXX              '--- XXXXXX
       \\-\\/XXX\\ XXXXXX                      /XXXXX
         \\XXXXXXXXX   \\                    /XXXXX/
          \\XXXXXX      >                 _/XXXXX/
            \\XXXXX--__/              __-- XXXX/
             -XXXXXXXX---------------  XXXXXX-
                \\XXXXXXXXXXXXXXXXXXXXXXXXXX/
                  ""VXXXXXXXXXXXXXXXXXXV""
EOC


================================================
FILE: cows/gopher.cow
================================================
$the_cow = <<EOC;
    $thoughts 
     $thoughts    ,_---~~~~~----._         
  _,,_,*^____      _____``*g*\\"*, 
 / __/ /'     ^.  /      \\ ^@q   f 
[  @f | @))    |  | @))   l  0 _/  
 \`/   \~____ / __ \_____/    \\   
  |           _l__l_           I   
  |          [______]           I  
  |            | | |            |  
  |             ~ ~             |  
  |                             |   
  |                             |
EOC


================================================
FILE: cows/head-in.cow
================================================
##
## Go stick yer head in a cow.
##
$the_cow = <<EOC;
    $thoughts
     $thoughts
    ^__^         /
    ($eyes)\\_______/  _________
    (__)\\       )=(  ____|_ \\_____
     $tongue ||----w |  \\ \\     \\_____ |
        ||     ||   ||           ||
EOC


================================================
FILE: cows/hellokitty.cow
================================================
##
## Hello Kitty
##
$the_cow = <<EOC;
  $thoughts
   $thoughts
      /\\_)o<
     |      \\
     | O . O|
      \\_____/
EOC


================================================
FILE: cows/kiss.cow
================================================
##
## A lovers' empbrace
##
$the_cow = <<EOC;
     $thoughts
      $thoughts
             ,;;;;;;;,
            ;;;;;;;;;;;,
           ;;;;;'_____;'
           ;;;(/))))|((\\
           _;;((((((|))))
          / |_\\\\\\\\\\\\\\\\\\\\\\\\
     .--~(  \\ ~))))))))))))
    /     \\  `\\-(((((((((((\\\\
    |    | `\\   ) |\\       /|)
     |    |  `. _/  \\_____/ |
      |    , `\\~            /
       |    \\  \\           /
      | `.   `\\|          /
      |   ~-   `\\        /
       \\____~._/~ -_,   (\\
        |-----|\\   \\    ';;
       |      | :;;;'     \\
      |  /    |            |
      |       |            |
EOC


================================================
FILE: cows/kitty.cow
================================================
##
## A kitten of sorts, I think
##
$the_cow = <<EOC;
     $thoughts
      $thoughts
       ("`-'  '-/") .___..--' ' "`-._
         ` *_ *  )    `-.   (      ) .`-.__. `)
         (_Y_.) ' ._   )   `._` ;  `` -. .-'
      _.. `--'_..-_/   /--' _ .' ,4
   ( i l ),-''  ( l i),'  ( ( ! .-'    
EOC


================================================
FILE: cows/koala.cow
================================================
##
## From the canonical koala collection
##
$the_cow = <<EOC;
  $thoughts
   $thoughts
       ___  
     {~._.~}
      ( Y )
     ()~*~()   
     (_)-(_)   
EOC


================================================
FILE: cows/kosh.cow
================================================
##
## It's a Kosh Cow!
##
$the_cow = <<EOC;
    $thoughts
     $thoughts
      $thoughts
  ___       _____     ___
 /   \\     /    /|   /   \\
|     |   /    / |  |     |
|     |  /____/  |  |     |     
|     |  |    |  |  |     |
|     |  | {} | /   |     |
|     |  |____|/    |     |
|     |    |==|     |     |
|      \\___________/      |
|                         |
|                         |
EOC


================================================
FILE: cows/luke-koala.cow
================================================
##
## From the canonical koala collection
##
$the_cow = <<EOC;
  $thoughts
   $thoughts          .
       ___   //
     {~._.~}// 
      ( Y )K/  
     ()~*~()   
     (_)-(_)   
     Luke    
     Sywalker
     koala   
EOC


================================================
FILE: cows/meow.cow
================================================
##
## A meowing tiger?
##
$the_cow = <<EOC;
  $thoughts
   $thoughts ,   _ ___.--'''`--''//-,-_--_.
      \\`"' ` || \\\\ \\ \\\\/ / // / ,-\\\\`,_
     /'`  \\ \\ || Y  | \\|/ / // / - |__ `-,
    /\@"\\  ` \\ `\\ |  | ||/ // | \\/  \\  `-._`-,_.,
   /  _.-. `.-\\,___/\\ _/|_/_\\_\\/|_/ |     `-._._)
   `-'``/  /  |  // \\__/\\__  /  \\__/ \\
        `-'  /-\\/  | -|   \\__ \\   |-' |
          __/\\ / _/ \\/ __,-'   ) ,' _|'
         (((__/(((_.' ((___..-'((__,'
EOC


================================================
FILE: cows/milk.cow
================================================
##
## Milk from Milk and Cheese
##
$the_cow = <<EOC;
 $thoughts     ____________ 
  $thoughts    |__________|
      /           /\\
     /           /  \\
    /___________/___/|
    |          |     |
    |  ==\\ /== |     |
    |   O   O  | \\ \\ |
    |     <    |  \\ \\|
   /|          |   \\ \\
  / |  \\_____/ |   / /
 / /|          |  / /|
/||\\|          | /||\\/
    -------------|   
        | |    | | 
       <__/    \\__>
EOC


================================================
FILE: cows/moofasa.cow
================================================
##
## MOOfasa.
##
$the_cow = <<EOC;
       $thoughts    ____
        $thoughts  /    \\
          | ^__^ |
          | ($eyes) |______
          | (__) |      )\\/\\
           \\____/|----w |
                ||     ||

             Moofasa
EOC


================================================
FILE: cows/moose.cow
================================================
$the_cow = <<EOC;
  $thoughts
   $thoughts   \\_\\_    _/_/
    $thoughts      \\__/
           ($eyes)\\_______
           (__)\\       )\\/\\
            $tongue ||----w |
               ||     ||
EOC


================================================
FILE: cows/mutilated.cow
================================================
##
## A mutilated cow, from aspolito@csua.berkeley.edu
##
$the_cow = <<EOC;
       $thoughts   \\_______
 v__v   $thoughts  \\   O   )
 ($eyes)      ||----w |
 (__)      ||     ||  \\/\\
  $tongue
EOC


================================================
FILE: cows/ren.cow
================================================
##
## Ren 
##
$the_cow = <<EOC;
   $thoughts
    $thoughts
    ____  
   /# /_\\_
  |  |/o\\o\\
  |  \\\\_/_/
 / |_   |  
|  ||\\_ ~| 
|  ||| \\/  
|  |||_    
 \\//  |    
  ||  |    
  ||_  \\   
  \\_|  o|  
  /\\___/   
 /  ||||__ 
    (___)_)
EOC


================================================
FILE: cows/sage.cow
================================================
## http://www.chris.com/ascii/joan/www.geocities.com/SoHo/7373/men.html#confucious
$the_cow = <<EOC;
   $thoughts
    $thoughts
      .
    .:::.
  .:::::::.
 V^V^V^V^V^V 
  (| ^ ^ |)      
   | (_) | 
   `//=\\'      
   (((()))
    )))((
    (())))
     ))((
     (()
      ))
      (
EOC

================================================
FILE: cows/satanic.cow
================================================
##
## Satanic cow, source unknown.
##
$the_cow = <<EOC;
     $thoughts
      $thoughts  (__)  
         (\\/)  
  /-------\\/    
 / | 666 ||    
*  ||----||      
   ~~    ~~      
EOC


================================================
FILE: cows/sheep.cow
================================================
##
## The non-flaming sheep.
##
$the_cow = <<EOC
  $thoughts
   $thoughts
       __     
      U${eyes}U\\.'\@\@\@\@\@\@`.
      \\__/(\@\@\@\@\@\@\@\@\@\@)
           (\@\@\@\@\@\@\@\@)
           `YY~~~~YY'
            ||    ||
EOC


================================================
FILE: cows/skeleton.cow
================================================
##
## This 'Scowleton' brought to you by one of 
## {appel,kube,rowe}@csua.berkeley.edu
##
$the_cow = <<EOC;
          $thoughts      (__)      
           $thoughts     /$eyes|  
            $thoughts   (_"_)*+++++++++*
                   //I#\\\\\\\\\\\\\\\\I\\
                   I[I|I|||||I I `
                   I`I'///'' I I
                   I I       I I
                   ~ ~       ~ ~
                     Scowleton
EOC


================================================
FILE: cows/small.cow
================================================
##
## A small cow, artist unknown
##
$the_cow = <<EOC;
       $thoughts   ,__,
        $thoughts  ($eyes)____
           (__)    )\\
            $tongue||--|| *
EOC


================================================
FILE: cows/sodomized.cow
================================================
##
## A cow performing an unnatural act, artist unknown.
##
$the_cow = <<EOC;
      $thoughts                _
       $thoughts              (_)
        $thoughts   ^__^       / \\
         $thoughts  ($eyes)\\_____/_\\ \\
            (__)\\       ) /
             $tongue ||----w ((
                ||     ||>> 
EOC


================================================
FILE: cows/squirrel.cow
================================================
$the_cow = <<EOC;
   $thoughts
    $thoughts
                  _ _
       | \__/|  .~    ~.
       /$eyes `./      .'
      {o__,   \    {
        / .  . )    \
        `-` '-' \    }
       .(   _(   )_.'
      '---.~_ _ _|
                                                     
EOC


================================================
FILE: cows/stegosaurus.cow
================================================
##
## A stegosaur with a top hat?
##
$the_cow = <<EOC;
    $thoughts                         .       .
     $thoughts                       / `.   .' " 
      $thoughts              .---.  <    > <    >  .---.
       $thoughts             |    \\  \\ - ~ ~ - /  /    |
         _____          ..-~             ~-..-~
        |     |   \\~~~\\.'                    `./~~~/
       ---------   \\__/                        \\__/
      .'  O    \\     /               /       \\  " 
     (_____,    `._.'               |         }  \\/~~~/
      `----.          /       }     |        /    \\__/
            `-.      |       /      |       /      `. ,~~|
                ~-.__|      /_ - ~ ^|      /- _      `..-'   
                     |     /        |     /     ~-.     `-. _  _  _
                     |_____|        |_____|         ~ - . _ _ _ _ _>
EOC


================================================
FILE: cows/stimpy.cow
================================================
##
## Stimpy!
##
$the_cow = <<EOC;
  $thoughts     .    _  .    
   $thoughts    |\\_|/__/|    
       / / \\/ \\  \\  
      /__|O||O|__ \\ 
     |/_ \\_/\\_/ _\\ |  
     | | (____) | ||  
     \\/\\___/\\__/  // 
     (_/         ||
      |          ||
      |          ||\\   
       \\        //_/  
        \\______//
       __ || __||
      (____(____)
EOC


================================================
FILE: cows/supermilker.cow
================================================
##
## A cow being milked, probably from Lars Smith (lars@csua.berkeley.edu)
##
$the_cow = <<EOC;
  $thoughts   ^__^
   $thoughts  ($eyes)\\_______        ________
      (__)\\       )\\/\\    |Super |
       $tongue ||----W |       |Milker|
          ||    UDDDDDDDDD|______|
EOC


================================================
FILE: cows/surgery.cow
================================================
##
## A cow operation, artist unknown
##
$the_cow = <<EOC;
          $thoughts           \\  / 
           $thoughts           \\/  
               (__)    /\\         
               ($eyes)   O  O        
               _\\/_   //         
         *    (    ) //       
          \\  (\\\\    //       
           \\(  \\\\    )                              
            (   \\\\   )   /\\                          
  ___[\\______/^^^^^^^\\__/) o-)__                     
 |\\__[=======______//________)__\\                    
 \\|_______________//____________|                    
     |||      || //||     |||
     |||      || @.||     |||                        
      ||      \\/  .\\/      ||                        
                 . .                                 
                '.'.`                                

            COW-OPERATION                           
EOC


================================================
FILE: cows/telebears.cow
================================================
##
## A cow performing an unnatural act, artist unknown.
##
$the_cow = <<EOC;
      $thoughts                _
       $thoughts              (_)   <-- TeleBEARS
        $thoughts   ^__^       / \\
         $thoughts  ($eyes)\\_____/_\\ \\
            (__)\\  you  ) /
             $tongue ||----w ((
                ||     ||>> 
EOC


================================================
FILE: cows/turkey.cow
================================================
##
## Turkey!
##
$the_cow = <<EOC;
  $thoughts                                  ,+*^^*+___+++_
   $thoughts                           ,*^^^^              )
    $thoughts                       _+*                     ^**+_
     $thoughts                    +^       _ _++*+_+++_,         )
              _+^^*+_    (     ,+*^ ^          \\+_        )
             {       )  (    ,(    ,_+--+--,      ^)      ^\\
            { (\@)    } f   ,(  ,+-^ __*_*_  ^^\\_   ^\\       )
           {:;-/    (_+*-+^^^^^+*+*<_ _++_)_    )    )      /
          ( /  (    (        ,___    ^*+_+* )   <    <      \\
           U _/     )    *--<  ) ^\\-----++__)   )    )       )
            (      )  _(^)^^))  )  )\\^^^^^))^*+/    /       /
          (      /  (_))_^)) )  )  ))^^^^^))^^^)__/     +^^
         (     ,/    (^))^))  )  ) ))^^^^^^^))^^)       _)
          *+__+*       (_))^)  ) ) ))^^^^^^))^^^^^)____*^
          \\             \\_)^)_)) ))^^^^^^^^^^))^^^^)
           (_             ^\\__^^^^^^^^^^^^))^^^^^^^)
             ^\\___            ^\\__^^^^^^))^^^^^^^^)\\\\
                  ^^^^^\\uuu/^^\\uuu/^^^^\\^\\^\\^\\^\\^\\^\\^\\
                     ___) >____) >___   ^\\_\\_\\_\\_\\_\\_\\)
                    ^^^//\\\\_^^//\\\\_^       ^(\\_\\_\\_\\)
                      ^^^ ^^ ^^^ ^
EOC


================================================
FILE: cows/turtle.cow
================================================
##
## A mysterious turtle...
##
$the_cow = <<EOC;
    $thoughts                                  ___-------___
     $thoughts                             _-~~             ~~-_
      $thoughts                         _-~                    /~-_
             /^\\__/^\\         /~  \\                   /    \\
           /|  O|| O|        /      \\_______________/        \\
          | |___||__|      /       /                \\          \\
          |          \\    /      /                    \\          \\
          |   (_______) /______/                        \\_________ \\
          |         / /         \\                      /            \\
           \\         \\^\\\\         \\                  /               \\     /
             \\         ||           \\______________/      _-_       //\\__//
               \\       ||------_-~~-_ ------------- \\ --/~   ~\\    || __/
                 ~-----||====/~     |==================|       |/~~~~~
                  (_(__/  ./     /                    \\_\\      \\.
                         (_(___/                         \\_____)_)
EOC


================================================
FILE: cows/tux.cow
================================================
##
## TuX
## (c) pborys@p-soft.silesia.linux.org.pl 
##
$the_cow = <<EOC;
   $thoughts
    $thoughts
        .--.
       |o_o |
       |:_/ |
      //   \\ \\
     (|     | )
    /'\\_   _/`\\
    \\___)=(___/

EOC


================================================
FILE: cows/vader-koala.cow
================================================
##
## Another canonical koala?
##
$the_cow = <<EOC;
   $thoughts
    $thoughts        .
     .---.  //
    Y|o o|Y// 
   /_(i=i)K/ 
   ~()~*~()~  
    (_)-(_)   

     Darth 
     Vader    
     koala        
EOC


================================================
FILE: cows/vader.cow
================================================
##
## Cowth Vader, from geordan@csua.berkeley.edu
##
$the_cow = <<EOC;
        $thoughts    ,-^-.
         $thoughts   !oYo!
          $thoughts /./=\\.\\______
               ##        )\\/\\
                ||-----w||
                ||      ||

               Cowth Vader
EOC


================================================
FILE: cows/www.cow
================================================
##
## A cow wadvertising the World Wide Web, from lim@csua.berkeley.edu
##
$the_cow = <<EOC;
        $thoughts   ^__^
         $thoughts  ($eyes)\\_______
            (__)\\       )\\/\\
             $tongue ||--WWW |
                ||     ||
EOC


================================================
FILE: cowsay.go
================================================
package cowsay

import (
	"io/ioutil"
	"math/rand"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
}

// Say to return cowsay string.
func Say(phrase string, options ...Option) (string, error) {
	cow, err := New(options...)
	if err != nil {
		return "", err
	}
	return cow.Say(phrase)
}

// LocationType indicates the type of COWPATH.
type LocationType int

const (
	// InBinary indicates the COWPATH in binary.
	InBinary LocationType = iota

	// InDirectory indicates the COWPATH in your directory.
	InDirectory
)

// CowPath is information of the COWPATH.
type CowPath struct {
	// Name is name of the COWPATH.
	// If you specified `COWPATH=/foo/bar`, Name is `/foo/bar`.
	Name string
	// CowFiles are name of the cowfile which are trimmed ".cow" suffix.
	CowFiles []string
	// LocationType is the type of COWPATH
	LocationType LocationType
}

// Lookup will look for the target cowfile in the specified path.
// If it exists, it returns the cowfile information and true value.
func (c *CowPath) Lookup(target string) (*CowFile, bool) {
	for _, cowfile := range c.CowFiles {
		if cowfile == target {
			return &CowFile{
				Name:         cowfile,
				BasePath:     c.Name,
				LocationType: c.LocationType,
			}, true
		}
	}
	return nil, false
}

// CowFile is information of the cowfile.
type CowFile struct {
	// Name is name of the cowfile.
	Name string
	// BasePath is the path which the cowpath is in.
	BasePath string
	// LocationType is the type of COWPATH
	LocationType LocationType
}

// ReadAll reads the cowfile content.
// If LocationType is InBinary, the file read from binary.
// otherwise reads from file system.
func (c *CowFile) ReadAll() ([]byte, error) {
	if c.LocationType == InBinary {
		// go embed is used "/" separator
		joinedPath := path.Join(c.BasePath, c.Name+".cow")
		return Asset(joinedPath)
	}
	joinedPath := filepath.Join(c.BasePath, c.Name+".cow")
	return ioutil.ReadFile(joinedPath)
}

// Cows to get list of cows
func Cows() ([]*CowPath, error) {
	cowPaths, err := cowsFromCowPath()
	if err != nil {
		return nil, err
	}
	cowPaths = append(cowPaths, &CowPath{
		Name:         "cows",
		CowFiles:     CowsInBinary(),
		LocationType: InBinary,
	})
	return cowPaths, nil
}

func cowsFromCowPath() ([]*CowPath, error) {
	cowPaths := make([]*CowPath, 0)
	cowPath := os.Getenv("COWPATH")
	if cowPath == "" {
		return cowPaths, nil
	}
	paths := splitPath(cowPath)
	for _, path := range paths {
		dirEntries, err := ioutil.ReadDir(path)
		if err != nil {
			return nil, err
		}
		path := &CowPath{
			Name:         path,
			CowFiles:     []string{},
			LocationType: InDirectory,
		}
		for _, entry := range dirEntries {
			name := entry.Name()
			if strings.HasSuffix(name, ".cow") {
				name = strings.TrimSuffix(name, ".cow")
				path.CowFiles = append(path.CowFiles, name)
			}
		}
		sort.Strings(path.CowFiles)
		cowPaths = append(cowPaths, path)
	}
	return cowPaths, nil
}

// GetCow to get cow's ascii art
func (cow *Cow) GetCow() (string, error) {
	src, err := cow.typ.ReadAll()
	if err != nil {
		return "", err
	}

	r := strings.NewReplacer(
		"\\\\", "\\",
		"\\@", "@",
		"\\$", "$",
		"$eyes", cow.eyes,
		"${eyes}", cow.eyes,
		"$tongue", cow.tongue,
		"${tongue}", cow.tongue,
		"$thoughts", string(cow.thoughts),
		"${thoughts}", string(cow.thoughts),
	)
	newsrc := r.Replace(string(src))
	separate := strings.Split(newsrc, "\n")
	mow := make([]string, 0, len(separate))
	for _, line := range separate {
		if strings.Contains(line, "$the_cow = <<EOC") || strings.HasPrefix(line, "##") {
			continue
		}

		if strings.HasPrefix(line, "EOC") {
			break
		}

		mow = append(mow, line)
	}
	return strings.Join(mow, "\n"), nil
}


================================================
FILE: cowsay_test.go
================================================
package cowsay

import (
	"bytes"
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
)

func TestCows(t *testing.T) {
	t.Run("no set COWPATH env", func(t *testing.T) {
		cowPaths, err := Cows()
		if err != nil {
			t.Fatal(err)
		}
		if len(cowPaths) != 1 {
			t.Fatalf("want 1, but got %d", len(cowPaths))
		}
		cowPath := cowPaths[0]
		if len(cowPath.CowFiles) == 0 {
			t.Fatalf("no cowfiles")
		}

		wantCowPath := &CowPath{
			Name:         "cows",
			LocationType: InBinary,
		}
		if diff := cmp.Diff(wantCowPath, cowPath,
			cmpopts.IgnoreFields(CowPath{}, "CowFiles"),
		); diff != "" {
			t.Errorf("(-want, +got)\n%s", diff)
		}
	})

	t.Run("set COWPATH env", func(t *testing.T) {
		cowpath := filepath.Join("testdata", "testdir")

		os.Setenv("COWPATH", cowpath)
		defer os.Unsetenv("COWPATH")

		cowPaths, err := Cows()
		if err != nil {
			t.Fatal(err)
		}
		if len(cowPaths) != 2 {
			t.Fatalf("want 2, but got %d", len(cowPaths))
		}

		wants := []*CowPath{
			{
				Name:         filepath.Join("testdata", "testdir"),
				LocationType: InDirectory,
			},
			{
				Name:         "cows",
				LocationType: InBinary,
			},
		}
		if diff := cmp.Diff(wants, cowPaths,
			cmpopts.IgnoreFields(CowPath{}, "CowFiles"),
		); diff != "" {
			t.Errorf("(-want, +got)\n%s", diff)
		}

		if len(cowPaths[0].CowFiles) != 1 {
			t.Fatalf("unexpected cowfiles len = %d, %+v",
				len(cowPaths[0].CowFiles), cowPaths[0].CowFiles,
			)
		}

		if cowPaths[0].CowFiles[0] != "test" {
			t.Fatalf("want %q but got %q", "test", cowPaths[0].CowFiles[0])
		}
	})

	t.Run("set COWPATH env", func(t *testing.T) {
		os.Setenv("COWPATH", "notfound")
		defer os.Unsetenv("COWPATH")

		_, err := Cows()
		if err == nil {
			t.Fatal("want error")
		}
	})

}

func TestCowPath_Lookup(t *testing.T) {
	t.Run("looked for cowfile", func(t *testing.T) {
		c := &CowPath{
			Name:         "basepath",
			CowFiles:     []string{"test"},
			LocationType: InBinary,
		}
		got, ok := c.Lookup("test")
		if !ok {
			t.Errorf("want %v", ok)
		}
		want := &CowFile{
			Name:         "test",
			BasePath:     "basepath",
			LocationType: InBinary,
		}

		if diff := cmp.Diff(want, got); diff != "" {
			t.Errorf("(-want, +got)\n%s", diff)
		}
	})

	t.Run("no cowfile", func(t *testing.T) {
		c := &CowPath{
			Name:         "basepath",
			CowFiles:     []string{"test"},
			LocationType: InBinary,
		}
		got, ok := c.Lookup("no cowfile")
		if ok {
			t.Errorf("want %v", !ok)
		}
		if got != nil {
			t.Error("want nil")
		}
	})
}

func TestCowFile_ReadAll(t *testing.T) {
	fromTestData := &CowFile{
		Name:         "test",
		BasePath:     filepath.Join("testdata", "testdir"),
		LocationType: InDirectory,
	}
	fromTestdataContent, err := fromTestData.ReadAll()
	if err != nil {
		t.Fatal(err)
	}

	fromBinary := &CowFile{
		Name:         "default",
		BasePath:     "cows",
		LocationType: InBinary,
	}
	fromBinaryContent, err := fromBinary.ReadAll()
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(fromTestdataContent, fromBinaryContent) {
		t.Fatalf("testdata\n%s\n\nbinary%s\n", string(fromTestdataContent), string(fromBinaryContent))
	}

}

const defaultSay = ` ________ 
< cowsay >
 -------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||`

func TestSay(t *testing.T) {
	type args struct {
		phrase  string
		options []Option
	}
	tests := []struct {
		name     string
		args     args
		wantFile string
		wantErr  bool
	}{
		{
			name: "default",
			args: args{
				phrase: "hello!",
			},
			wantFile: "default.cow",
			wantErr:  false,
		},
		{
			name: "nest",
			args: args{
				phrase: defaultSay,
				options: []Option{
					DisableWordWrap(),
				},
			},
			wantFile: "nest.cow",
			wantErr:  false,
		},
		{
			name: "error",
			args: args{
				phrase: "error",
				options: []Option{
					func(*Cow) error {
						return errors.New("error")
					},
				},
			},
			wantErr: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := Say(tt.args.phrase, tt.args.options...)
			if (err != nil) != tt.wantErr {
				t.Errorf("Say() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if tt.wantErr {
				return
			}
			filename := filepath.Join("testdata", tt.wantFile)
			content, err := ioutil.ReadFile(filename)
			if err != nil {
				t.Fatal(err)
			}
			got = strings.Replace(got, "\r", "", -1)               // for windows
			want := strings.Replace(string(content), "\r", "", -1) // for windows
			if want != got {
				t.Log(cmp.Diff([]byte(want), []byte(got)))
				t.Fatalf("want\n%s\n\ngot\n%s", want, got)
			}
		})
	}
}


================================================
FILE: decoration/aurora.go
================================================
package decoration

import (
	"fmt"
	"io"
	"math"
	"unicode"
	"unicode/utf8"
)

func (w *Writer) writeAsAurora(b []byte) (nn int, err error) {
	defer w.buf.Reset()

	for len(b) > 0 {
		char, size := utf8.DecodeRune(b)
		if char == '\n' {
			w.buf.WriteRune(char)
			b = b[size:]
			continue
		}
		if unicode.IsSpace(char) {
			w.buf.WriteRune(char)
		} else {
			fmt.Fprintf(&w.buf, "\033[38;5;%d%sm%c\033[0m",
				rgb(float64(w.options.colorSeq)),
				w.options.maybeBold(),
				char,
			)
		}
		w.options.colorSeq++
		b = b[size:]
	}

	return w.writer.Write(w.buf.Bytes())
}

func (w *Writer) writeStringAsAurora(s string) (nn int, err error) {
	defer w.buf.Reset()

	for _, char := range s {
		if char == '\n' {
			w.buf.WriteRune(char)
			continue
		}
		if unicode.IsSpace(char) {
			w.buf.WriteRune(char)
		} else {
			fmt.Fprintf(&w.buf, "\033[38;5;%d%sm%c\033[0m",
				rgb(float64(w.options.colorSeq)),
				w.options.maybeBold(),
				char,
			)
		}
		w.options.colorSeq++
	}
	if sw, ok := w.writer.(io.StringWriter); ok {
		return sw.WriteString(w.buf.String())
	}
	return w.writer.Write(w.buf.Bytes())
}

// https://sking7.github.io/articles/139888127.html#:~:text=value%20of%20frequency.-,Using,-out-of-phase
const (
	freq = 0.01
	m    = math.Pi / 3

	redPhase   = 0
	greenPhase = 2 * m
	bluePhase  = 4 * m
)

var rgbMemo = map[float64]int64{}

func rgb(i float64) int64 {
	if v, ok := rgbMemo[i]; ok {
		return v
	}
	red := int64(6*(math.Sin(freq*i+redPhase)*127+128)/256) * 36
	green := int64(6*(math.Sin(freq*i+greenPhase)*127+128)/256) * 6
	blue := int64(6*(math.Sin(freq*i+bluePhase)*127+128)/256) * 1
	rgbMemo[i] = 16 + red + green + blue
	return rgbMemo[i]
}


================================================
FILE: decoration/bold.go
================================================
package decoration

import (
	"fmt"
	"io"
	"unicode"
	"unicode/utf8"
)

func (w *Writer) writeAsDefaultBold(b []byte) (nn int, err error) {
	defer w.buf.Reset()

	for len(b) > 0 {
		char, size := utf8.DecodeRune(b)
		if char == '\n' {
			w.buf.WriteRune(char)
			b = b[size:]
			continue
		}
		if unicode.IsSpace(char) {
			w.buf.WriteRune(char)
		} else {
			fmt.Fprintf(&w.buf, "\x1b[1m%c\x1b[0m", char)
		}
		b = b[size:]
	}
	return w.writer.Write(w.buf.Bytes())
}

func (w *Writer) writeStringAsDefaultBold(s string) (nn int, err error) {
	defer w.buf.Reset()

	for _, char := range s {
		if char == '\n' {
			w.buf.WriteRune(char)
			continue
		}
		if unicode.IsSpace(char) {
			w.buf.WriteRune(char)
		} else {
			fmt.Fprintf(&w.buf, "\x1b[1m%c\x1b[0m", char)
		}
	}
	if sw, ok := w.writer.(io.StringWriter); ok {
		return sw.WriteString(w.buf.String())
	}
	return w.writer.Write(w.buf.Bytes())
}


================================================
FILE: decoration/decoration.go
================================================
package decoration

import (
	"bytes"
	"io"
)

type options struct {
	withBold    bool
	withRainbow bool
	withAurora  bool
	colorSeq    int
}

func (o *options) maybeBold() string {
	if o.withBold {
		return ";1"
	}
	return ""
}

// Option for any writer in this package.
type Option func(o *options)

// WithBold writes with bold.
func WithBold() Option {
	return func(o *options) {
		o.withBold = true
	}
}

// WithRainbow writes with rainbow.
func WithRainbow() Option {
	return func(o *options) {
		o.withRainbow = true
	}
}

// WithAurora writes with aurora.
func WithAurora(initialSeq int) Option {
	return func(o *options) {
		o.withAurora = true
		o.colorSeq = initialSeq
	}
}

// Writer is a writer to decorates.
type Writer struct {
	writer  io.Writer
	buf     bytes.Buffer
	options *options
}

var _ interface {
	io.Writer
	io.StringWriter
} = (*Writer)(nil)

// NewWriter creates a new writer.
func NewWriter(w io.Writer, opts ...Option) *Writer {
	options := new(options)
	for _, optFunc := range opts {
		optFunc(options)
	}
	return &Writer{
		writer:  w,
		options: options,
	}
}

// SetColorSeq sets current color sequence.
func (w *Writer) SetColorSeq(colorSeq int) {
	w.options.colorSeq = colorSeq
}

// Write writes bytes. which is implemented io.Writer.
//
// If Bold is enabled in the options, the text will be written as Bold.
// If both Aurora and Rainbow are enabled in the options, Aurora will take precedence.
func (w *Writer) Write(b []byte) (nn int, err error) {
	switch {
	case w.options.withAurora:
		return w.writeAsAurora(b)
	case w.options.withRainbow:
		return w.writeAsRainbow(b)
	case w.options.withBold:
		return w.writeAsDefaultBold(b)
	default:
		return w.writer.Write(b)
	}
}

// WriteString writes string. which is implemented io.StringWriter.
//
// See also Write.
func (w *Writer) WriteString(s string) (n int, err error) {
	switch {
	case w.options.withAurora:
		return w.writeStringAsAurora(s)
	case w.options.withRainbow:
		return w.writeStringAsRainbow(s)
	case w.options.withBold:
		return w.writeStringAsDefaultBold(s)
	default:
		if sw, ok := w.writer.(io.StringWriter); ok {
			return sw.WriteString(w.buf.String())
		}
		return w.writer.Write([]byte(s))
	}
}


================================================
FILE: decoration/rainbow.go
================================================
package decoration

import (
	"fmt"
	"io"
	"unicode"
	"unicode/utf8"
)

const (
	red = iota + 31
	green
	yellow
	blue
	magenta
	cyan
)

var rainbow = []int{magenta, red, yellow, green, cyan, blue}

func (w *Writer) writeAsRainbow(b []byte) (nn int, err error) {
	defer w.buf.Reset()

	for len(b) > 0 {
		char, size := utf8.DecodeRune(b)
		if char == '\n' {
			w.options.colorSeq = 0
			w.buf.WriteRune(char)
			b = b[size:]
			continue
		}
		if unicode.IsSpace(char) {
			w.buf.WriteRune(char)
		} else {
			fmt.Fprintf(&w.buf, "\x1b[%d%sm%c\x1b[0m",
				rainbow[w.options.colorSeq%len(rainbow)],
				w.options.maybeBold(),
				char,
			)
		}
		w.options.colorSeq++
		b = b[size:]
	}

	return w.writer.Write(w.buf.Bytes())
}

func (w *Writer) writeStringAsRainbow(s string) (nn int, err error) {
	defer w.buf.Reset()

	for _, char := range s {
		if char == '\n' {
			w.options.colorSeq = 0
			w.buf.WriteRune(char)
			continue
		}
		if unicode.IsSpace(char) {
			w.buf.WriteRune(char)
		} else {
			fmt.Fprintf(&w.buf, "\x1b[%d%sm%c\x1b[0m",
				rainbow[w.options.colorSeq%len(rainbow)],
				w.options.maybeBold(),
				char,
			)
		}
		w.options.colorSeq++
	}

	if sw, ok := w.writer.(io.StringWriter); ok {
		return sw.WriteString(w.buf.String())
	}
	return w.writer.Write(w.buf.Bytes())
}


================================================
FILE: doc/cowsay.1
================================================
'\" t
.\"     Title: cowsay
.\"    Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.16
.\"      Date: 2021-11-13
.\"    Manual: \ \&
.\"    Source: \ \&
.\"  Language: English
.\"
.TH "NEO COWSAY/COWTHINK" "1" "2021-11-13" "\ \&" "\ \&"
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.ss \n[.ss] 0
.nh
.ad l
.de URL
\fI\\$2\fP <\\$1>\\$3
..
.als MTO URL
.if \n[.g] \{\
.  mso www.tmac
.  am URL
.    ad l
.  .
.  am MTO
.    ad l
.  .
.  LINKSTYLE blue R < >
.\}
.SH "NAME"
Neo cowsay/cowthink \- configurable speaking/thinking cow (and a bit more)
.SH "SYNOPSIS"
.sp
cowsay [\-e \fIeye_string\fP] [\-f \fIcowfile\fP] [\-h] [\-l] [\-n] [\-T \fItongue_string\fP] [\-W \fIcolumn\fP] [\-bdgpstwy]
[\-\-random] [\-\-bold] [\-\-rainbow] [\-\-aurora] [\-\-super] [\fImessage\fP]
.SH "DESCRIPTION"
.sp
\fINeo\-cowsay\fP (cowsay) generates an ASCII picture of a cow saying something provided by the
user.  If run with no arguments, it accepts standard input, word\-wraps
the message given at about 40 columns, and prints the cow saying the
given message on standard output.
.sp
To aid in the use of arbitrary messages with arbitrary whitespace,
use the \fB\-n\fP option.  If it is specified, the given message will not be
word\-wrapped.  This is possibly useful if you want to make the cow
think or speak in figlet(6).  If \fB\-n\fP is specified, there must not be any command\-line arguments left
after all the switches have been processed.
.sp
The \fB\-W\fP specifies roughly (where the message should be wrapped. The default
is equivalent to \fB\-W 40\fP i.e. wrap words at or before the 40th column.
.sp
If any command\-line arguments are left over after all switches have
been processed, they become the cow\(cqs message. The program will not
accept standard input for a message in this case.
.sp
There are several provided modes which change the appearance of the
cow depending on its particular emotional/physical state.
.sp
The \fB\-b\fP option initiates Borg mode
.sp
\fB\-d\fP causes the cow to appear dead
.sp
\fB\-g\fP invokes greedy mode
.sp
\fB\-p\fP causes a state of paranoia to come over the cow
.sp
\fB\-s\fP makes the cow appear thoroughly stoned
.sp
\fB\-t\fP yields a tired cow
.sp
\fB\-w\fP is somewhat the opposite of \fB\-t\fP and initiates wired mode
.sp
\fB\-y\fP brings on the cow\(cqs youthful appearance.
.sp
The user may specify the \fB\-e\fP option to select the appearance of the cow\(cqs eyes, in which case
the first two characters of the argument string \fIeye_string\fP will be used. The default eyes are \fIoo\fP. The tongue is similarly
configurable through \fB\-T\fP and \fItongue_string\fP; it must be two characters and does not appear by default. However,
it does appear in the \fIdead\fP and \fIstoned\fP modes. Any configuration
done by \fB\-e\fP and \fB\-T\fP will be lost if one of the provided modes is used.
.sp
The \fB\-f\fP option specifies a particular cow picture file (\(lqcowfile\(rq) to
use. If the cowfile spec contains \fI/\fP then it will be interpreted
as a path relative to the current directory. Otherwise, cowsay
will search the path specified in the \fBCOWPATH\fP environment variable. If \fB\-f \-\fP is specified, provides
interactive Unix filter (command\-line fuzzy finder) to search the cowfile.
.sp
To list all cowfiles on the current \fBCOWPATH\fP, invoke \fBcowsay\fP with the \fB\-l\fP switch.
.sp
\fB\-\-random\fP pick randomly from available cowfiles
.sp
\fB\-\-bold\fP outputs as bold text
.sp
\fB\-\-rainbow\fP and \fB\-\-aurora\fP filters with colors an ASCII picture of a cow saying something
.sp
\fB\-\-super\fP ...enjoy!
.sp
If the program is invoked as \fBcowthink\fP then the cow will think its message instead of saying it.
.SH "COWFILE FORMAT"
.sp
A cowfile is made up of a simple block of \fBperl(1)\fP code, which assigns a picture of a cow to the variable \fB$the_cow\fP.
Should you wish to customize the eyes or the tongue of the cow,
then the variables \fB$eyes\fP and \fB$tongue\fP may be used. The trail leading up to the cow\(cqs message balloon is
composed of the character(s) in the \fB$thoughts\fP variable. Any backslashes must be reduplicated to prevent interpolation.
The name of a cowfile should end with \fB.cow ,\fP otherwise it is assumed not to be a cowfile. Also, at\-signs (\(lq@\(rq)
must be backslashed because that is what Perl 5 expects.
.SH "ENVIRONMENT"
.sp
The COWPATH environment variable, if present, will be used to search
for cowfiles.  It contains a colon\-separated list of directories,
much like \fBPATH or MANPATH\fP. It should always contain the \fB/usr/local/share/cows\fP
directory, or at least a directory with a file called \fBdefault.cow\fP in it.
.SH "FILES"
.sp
\fB%PREFIX%/share/cows\fP holds a sample set of cowfiles. If your \fBCOWPATH\fP is not explicitly set, it automatically contains this directory.
.SH "BUGS"
.sp
.URL "https://github.com/Code\-Hex/Neo\-cowsay" "" ""
.sp
If there are any, please report bugs and feature requests in the issue tracker.
Please do your best to provide a reproducible test case for bugs. This should
include the \fBcowsay\fP command, the actual output and the expected output.
.SH "AUTHORS"
.sp
Neo\-cowsay author is Kei Kamikawa (\c
.MTO "x00.x7f.x86\(atgmail.com" "" ")."
.sp
The original author is Tony Monroe (\c
.MTO "tony\(atnog.net" "" "),"
with suggestions from Shannon
Appel (\c
.MTO "appel\(atCSUA.Berkeley.EDU" "" ")"
and contributions from Anthony Polito
(\c
.MTO "aspolito\(atCSUA.Berkeley.EDU" "" ")."
.SH "SEE ALSO"
.sp
perl(1), wall(1), nwrite(1), figlet(6)

================================================
FILE: doc/cowsay.1.txt.tpl
================================================
cowsay(1)
=========

Name
----
Neo cowsay/cowthink - configurable speaking/thinking cow (and a bit more)

SYNOPSIS
--------
cowsay [-e _eye_string_] [-f _cowfile_] [-h] [-l] [-n] [-T _tongue_string_] [-W _column_] [-bdgpstwy]
       [--random] [--bold] [--rainbow] [--aurora] [--super] [_message_]

DESCRIPTION
-----------
_Neo-cowsay_ (cowsay) generates an ASCII picture of a cow saying something provided by the
user.  If run with no arguments, it accepts standard input, word-wraps
the message given at about 40 columns, and prints the cow saying the
given message on standard output.

To aid in the use of arbitrary messages with arbitrary whitespace,
use the *-n* option.  If it is specified, the given message will not be
word-wrapped.  This is possibly useful if you want to make the cow
think or speak in figlet(6).  If *-n* is specified, there must not be any command-line arguments left
after all the switches have been processed.

The *-W* specifies roughly (where the message should be wrapped. The default
is equivalent to *-W 40* i.e. wrap words at or before the 40th column.

If any command-line arguments are left over after all switches have
been processed, they become the cow's message. The program will not
accept standard input for a message in this case.

There are several provided modes which change the appearance of the
cow depending on its particular emotional/physical state. 

The *-b* option initiates Borg mode

*-d* causes the cow to appear dead 

*-g* invokes greedy mode

*-p* causes a state of paranoia to come over the cow

*-s* makes the cow appear thoroughly stoned

*-t* yields a tired cow

*-w* is somewhat the opposite of *-t* and initiates wired mode

*-y* brings on the cow's youthful appearance.

The user may specify the *-e* option to select the appearance of the cow's eyes, in which case
the first two characters of the argument string _eye_string_ will be used. The default eyes are 'oo'. The tongue is similarly
configurable through *-T* and _tongue_string_; it must be two characters and does not appear by default. However,
it does appear in the 'dead' and 'stoned' modes. Any configuration
done by *-e* and *-T* will be lost if one of the provided modes is used.

The *-f* option specifies a particular cow picture file (``cowfile'') to
use. If the cowfile spec contains '/' then it will be interpreted
as a path relative to the current directory. Otherwise, cowsay
will search the path specified in the *COWPATH* environment variable. If *-f -* is specified, provides
interactive Unix filter (command-line fuzzy finder) to search the cowfile.

To list all cowfiles on the current *COWPATH*, invoke *cowsay* with the *-l* switch.

*--random* pick randomly from available cowfiles

*--bold* outputs as bold text

*--rainbow* and *--aurora* filters with colors an ASCII picture of a cow saying something

*--super* ...enjoy!

If the program is invoked as *cowthink* then the cow will think its message instead of saying it.

COWFILE FORMAT
--------------
A cowfile is made up of a simple block of *perl(1)* code, which assigns a picture of a cow to the variable *$the_cow*.
Should you wish to customize the eyes or the tongue of the cow,
then the variables *$eyes* and *$tongue* may be used. The trail leading up to the cow's message balloon is
composed of the character(s) in the *$thoughts* variable. Any backslashes must be reduplicated to prevent interpolation.
The name of a cowfile should end with *.cow ,* otherwise it is assumed not to be a cowfile. Also, at-signs (``@'')
must be backslashed because that is what Perl 5 expects.

ENVIRONMENT
-----------
The COWPATH environment variable, if present, will be used to search
for cowfiles.  It contains a colon-separated list of directories,
much like *PATH or MANPATH*. It should always contain the */usr/local/share/cows*
directory, or at least a directory with a file called *default.cow* in it.

FILES
-----
*%PREFIX%/share/cows* holds a sample set of cowfiles. If your *COWPATH* is not explicitly set, it automatically contains this directory.

BUGS
----
https://github.com/Code-Hex/Neo-cowsay

If there are any, please report bugs and feature requests in the issue tracker.
Please do your best to provide a reproducible test case for bugs. This should
include the *cowsay* command, the actual output and the expected output.

AUTHORS
-------
Neo-cowsay author is Kei Kamikawa (x00.x7f.x86@gmail.com).

The original author is Tony Monroe (tony@nog.net), with suggestions from Shannon
Appel (appel@CSUA.Berkeley.EDU) and contributions from Anthony Polito
(aspolito@CSUA.Berkeley.EDU).

SEE ALSO
--------
perl(1), wall(1), nwrite(1), figlet(6)

================================================
FILE: embed.go
================================================
package cowsay

import (
	"embed"
	"sort"
	"strings"
)

//go:embed cows/*
var cowsDir embed.FS

// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(path string) ([]byte, error) {
	return cowsDir.ReadFile(path)
}

// AssetNames returns the list of filename of the assets.
func AssetNames() []string {
	entries, err := cowsDir.ReadDir("cows")
	if err != nil {
		panic(err)
	}
	names := make([]string, 0, len(entries))
	for _, entry := range entries {
		name := strings.TrimSuffix(entry.Name(), ".cow")
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}

var cowsInBinary = AssetNames()

// CowsInBinary returns the list of cowfiles which are in binary.
// the list is memoized.
func CowsInBinary() []string {
	return cowsInBinary
}


================================================
FILE: examples/basic/go.mod
================================================
module github.com/Code-Hex/Neo-cowsay/v2/example

go 1.16

require github.com/Code-Hex/Neo-cowsay/v2 v2.0.1

replace github.com/Code-Hex/Neo-cowsay/v2 => ../../


================================================
FILE: examples/basic/go.sum
================================================
github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=
github.com/Code-Hex/go-wordwrap v1.0.0/go.mod h1:/SsbgkY2Q0aPQRyvXcyQwWYTQOIwSORKe6MPjRVGIWU=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=


================================================
FILE: examples/basic/main.go
================================================
package main

import (
	"fmt"

	cowsay "github.com/Code-Hex/Neo-cowsay/v2"
)

func main() {
	if false {
		simple()
	} else {
		complex()
	}
}

func simple() {
	say, err := cowsay.Say(
		"Hello",
		cowsay.Type("default"),
		cowsay.BallonWidth(40),
	)
	if err != nil {
		panic(err)
	}
	fmt.Println(say)
}

func complex() {
	cow, err := cowsay.New(
		cowsay.BallonWidth(40),
		//cowsay.Thinking(),
		cowsay.Random(),
	)
	if err != nil {
		panic(err)
	}
	say, err := cow.Say("Hello")
	if err != nil {
		panic(err)
	}
	fmt.Println(say)
}


================================================
FILE: examples/echo-server/README.md
================================================
## echo server

```
$ go build
$ ./echo-server
2021/11/14 16:16:27 server addr => 127.0.0.1:54456
```


## client

Use [netcat](https://en.wikipedia.org/wiki/Netcat)

Please enter `^D` (control + D) after you enter any characters.

```
$ nc 127.0.0.1 54456
hello
 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```


================================================
FILE: examples/echo-server/go.mod
================================================
module github.com/Code-Hex/Neo-cowsay/v2/examples/echo-server

go 1.16

require github.com/Code-Hex/Neo-cowsay/v2 v2.0.1

replace github.com/Code-Hex/Neo-cowsay/v2 => ../../


================================================
FILE: examples/echo-server/go.sum
================================================
github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=
github.com/Code-Hex/go-wordwrap v1.0.0/go.mod h1:/SsbgkY2Q0aPQRyvXcyQwWYTQOIwSORKe6MPjRVGIWU=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=


================================================
FILE: examples/echo-server/main.go
================================================
package main

import (
	"context"
	"io"
	"log"
	"net"
	"os"
	"os/signal"
	"strings"
	"time"

	cowsay "github.com/Code-Hex/Neo-cowsay/v2"
)

const limit = 1000

func main() {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		log.Fatal(err)
	}
	log.Println("server addr =>", ln.Addr())

	ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
	defer cancel()

	go func() {
		for {
			conn, err := ln.Accept()
			if err != nil {
				log.Println(err)
				return
			}
			conn.SetDeadline(time.Now().Add(5 * time.Second))

			go func() {
				defer conn.Close()
				go func() {
					<-ctx.Done()
					// cancel
					conn.SetDeadline(time.Now())
				}()

				var buf strings.Builder
				rd := io.LimitReader(conn, limit)
				if _, err := io.Copy(&buf, rd); err != nil {
					log.Println("error:", err)
					return
				}

				phrase := strings.TrimSpace(buf.String())
				log.Println(phrase)
				say, _ := cowsay.Say(phrase)
				conn.Write([]byte(say))
			}()
		}
	}()

	<-ctx.Done()
}


================================================
FILE: go.mod
================================================
module github.com/Code-Hex/Neo-cowsay/v2

require (
	github.com/Code-Hex/go-wordwrap v1.0.0
	github.com/google/go-cmp v0.5.6
	github.com/mattn/go-runewidth v0.0.13
	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

go 1.16


================================================
FILE: go.sum
================================================
github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=
github.com/Code-Hex/go-wordwrap v1.0.0/go.mod h1:/SsbgkY2Q0aPQRyvXcyQwWYTQOIwSORKe6MPjRVGIWU=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=


================================================
FILE: split.go
================================================
//go:build !windows
// +build !windows

package cowsay

import "strings"

func splitPath(s string) []string {
	return strings.Split(s, ":")
}


================================================
FILE: split_windows.go
================================================
//go:build windows
// +build windows

package cowsay

import "strings"

func splitPath(s string) []string {
	return strings.Split(s, ";")
}


================================================
FILE: testdata/default.cow
================================================
 ________ 
< hello! >
 -------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

================================================
FILE: testdata/nest.cow
================================================
 ______________________________ 
/  ________                    \
| < cowsay >                   |
|  --------                    |
|         \   ^__^             |
|          \  (oo)\_______     |
|             (__)\       )\/\ |
|                 ||----w |    |
\                 ||     ||    /
 ------------------------------ 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

================================================
FILE: testdata/testdir/test.cow
================================================
$the_cow = <<EOC;
        $thoughts   ^__^
         $thoughts  ($eyes)\\_______
            (__)\\       )\\/\\
             $tongue ||----w |
                ||     ||
EOC
Download .txt
gitextract_va4xlec5/

├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── lgtm.yml
│       ├── main.yml
│       └── release.yml
├── .gitignore
├── .goreleaser.yml
├── LICENSE
├── Makefile
├── README.md
├── balloon.go
├── bin/
│   └── .gitkeep
├── cmd/
│   ├── cmd.go
│   ├── cowsay/
│   │   └── main.go
│   ├── cowthink/
│   │   └── main.go
│   ├── go.mod
│   ├── go.sum
│   ├── internal/
│   │   ├── cli/
│   │   │   ├── cli.go
│   │   │   └── cli_test.go
│   │   ├── screen/
│   │   │   ├── buffer.go
│   │   │   └── screen.go
│   │   └── super/
│   │       └── supercow.go
│   └── testdata/
│       ├── cowsay/
│       │   ├── W_option.txt
│       │   ├── b_option.txt
│       │   ├── d_option.txt
│       │   ├── eyes_option.txt
│       │   ├── f_tux_option.txt
│       │   ├── g_option.txt
│       │   ├── n_option.txt
│       │   ├── p_option.txt
│       │   ├── s_option.txt
│       │   ├── t_option.txt
│       │   ├── tongue_option.txt
│       │   ├── wired_option.txt
│       │   └── y_option.txt
│       └── cowthink/
│           ├── W_option.txt
│           ├── b_option.txt
│           ├── d_option.txt
│           ├── eyes_option.txt
│           ├── f_tux_option.txt
│           ├── g_option.txt
│           ├── n_option.txt
│           ├── p_option.txt
│           ├── s_option.txt
│           ├── t_option.txt
│           ├── tongue_option.txt
│           ├── wired_option.txt
│           └── y_option.txt
├── cow.go
├── cow_test.go
├── cows/
│   ├── beavis.zen.cow
│   ├── bong.cow
│   ├── bud-frogs.cow
│   ├── bunny.cow
│   ├── cheese.cow
│   ├── cower.cow
│   ├── daemon.cow
│   ├── default.cow
│   ├── deno.cow
│   ├── docker.cow
│   ├── dragon-and-cow.cow
│   ├── dragon.cow
│   ├── elephant-in-snake.cow
│   ├── elephant.cow
│   ├── eyes.cow
│   ├── flaming-sheep.cow
│   ├── ghostbusters.cow
│   ├── gopher.cow
│   ├── head-in.cow
│   ├── hellokitty.cow
│   ├── kiss.cow
│   ├── kitty.cow
│   ├── koala.cow
│   ├── kosh.cow
│   ├── luke-koala.cow
│   ├── meow.cow
│   ├── milk.cow
│   ├── moofasa.cow
│   ├── moose.cow
│   ├── mutilated.cow
│   ├── ren.cow
│   ├── sage.cow
│   ├── satanic.cow
│   ├── sheep.cow
│   ├── skeleton.cow
│   ├── small.cow
│   ├── sodomized.cow
│   ├── squirrel.cow
│   ├── stegosaurus.cow
│   ├── stimpy.cow
│   ├── supermilker.cow
│   ├── surgery.cow
│   ├── telebears.cow
│   ├── turkey.cow
│   ├── turtle.cow
│   ├── tux.cow
│   ├── vader-koala.cow
│   ├── vader.cow
│   └── www.cow
├── cowsay.go
├── cowsay_test.go
├── decoration/
│   ├── aurora.go
│   ├── bold.go
│   ├── decoration.go
│   └── rainbow.go
├── doc/
│   ├── cowsay.1
│   └── cowsay.1.txt.tpl
├── embed.go
├── examples/
│   ├── basic/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── echo-server/
│       ├── README.md
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── go.mod
├── go.sum
├── split.go
├── split_windows.go
└── testdata/
    ├── default.cow
    ├── nest.cow
    └── testdir/
        └── test.cow
Download .txt
SYMBOL INDEX (145 symbols across 21 files)

FILE: balloon.go
  type border (line 11) | type border struct
  method borderType (line 18) | func (cow *Cow) borderType() border {
  type line (line 36) | type line struct
  type lines (line 41) | type lines
  method maxLineWidth (line 43) | func (cow *Cow) maxLineWidth(lines []*line) int {
  method getLines (line 56) | func (cow *Cow) getLines(phrase string) []*line {
  method canonicalizePhrase (line 69) | func (cow *Cow) canonicalizePhrase(phrase string) string {
  method Balloon (line 81) | func (cow *Cow) Balloon(phrase string) string {
  method writeBallon (line 92) | func (cow *Cow) writeBallon(lines []*line, maxWidth int) {
  method flush (line 144) | func (cow *Cow) flush(text, top, bottom fmt.Stringer) string {
  method padding (line 153) | func (cow *Cow) padding(line *line, maxWidth int) {

FILE: cmd/cowsay/main.go
  function main (line 11) | func main() {

FILE: cmd/cowthink/main.go
  function main (line 11) | func main() {

FILE: cmd/internal/cli/cli.go
  function init (line 26) | func init() {
  type options (line 41) | type options struct
  type CLI (line 65) | type CLI struct
    method program (line 73) | func (c *CLI) program() string {
    method Run (line 81) | func (c *CLI) Run(argv []string) int {
    method mow (line 99) | func (c *CLI) mow(argv []string) error {
    method parseOptions (line 130) | func (c *CLI) parseOptions(opts *options, argv []string) ([]string, er...
    method usage (line 145) | func (c *CLI) usage() []byte {
    method generateOptions (line 156) | func (c *CLI) generateOptions(opts *options) []cowsay.Option {
    method phrase (line 202) | func (c *CLI) phrase(opts *options, args []string) string {
    method mowmow (line 214) | func (c *CLI) mowmow(opts *options, args []string) error {
  function cowList (line 190) | func cowList() []string {
  function selectFace (line 248) | func selectFace(opts *options, o []cowsay.Option) []cowsay.Option {

FILE: cmd/internal/cli/cli_test.go
  function TestCLI_Run (line 14) | func TestCLI_Run(t *testing.T) {

FILE: cmd/internal/screen/buffer.go
  function Flush (line 15) | func Flush() string {
  type MoveWriter (line 21) | type MoveWriter struct
    method SetPosx (line 44) | func (m *MoveWriter) SetPosx(x int) {
    method Reset (line 50) | func (m *MoveWriter) Reset() {
    method Write (line 56) | func (m *MoveWriter) Write(bs []byte) (nn int, _ error) {
    method WriteString (line 88) | func (m *MoveWriter) WriteString(s string) (nn int, _ error) {
  function NewMoveWriter (line 34) | func NewMoveWriter(w io.Writer, x, y int) *MoveWriter {
  function getXY (line 120) | func getXY(x int, y int) (int, int) {
  function currentHeight (line 144) | func currentHeight() int {

FILE: cmd/internal/screen/screen.go
  function SaveState (line 15) | func SaveState() { Stdout.Write([]byte("\0337")) }
  function RestoreState (line 18) | func RestoreState() { Stdout.Write([]byte("\0338")) }
  function Clear (line 21) | func Clear() { Stdout.Write([]byte("\033[2J")) }
  function HideCursor (line 24) | func HideCursor() { Stdout.Write([]byte("\033[?25l")) }
  function UnHideCursor (line 27) | func UnHideCursor() { Stdout.Write([]byte("\033[?25h")) }
  function getSize (line 35) | func getSize() (int, int) {
  function Width (line 47) | func Width() int {
  function Height (line 53) | func Height() int {

FILE: cmd/internal/super/supercow.go
  function getNoSaidCow (line 19) | func getNoSaidCow(cow *cowsay.Cow, opts ...cowsay.Option) (string, error) {
  function RunSuperCow (line 29) | func RunSuperCow(phrase string, withBold bool, opts ...cowsay.Option) er...
  function createBlankSpace (line 74) | func createBlankSpace(balloon string) string {
  function maxLen (line 83) | func maxLen(cow []string) int {
  type cowLine (line 94) | type cowLine struct
    method Len (line 99) | func (c *cowLine) Len() int {
    method Slice (line 103) | func (c *cowLine) Slice(i, j int) string {
  function makeCowLines (line 110) | func makeCowLines(cow string) []*cowLine {
  type renderer (line 127) | type renderer struct
    method createFrames (line 168) | func (r *renderer) createFrames(cow *cowsay.Cow, withBold bool) {
    method render (line 214) | func (r *renderer) render() {
    method posX (line 230) | func (r *renderer) posX(i int) int {
    method newWriter (line 245) | func (r *renderer) newWriter(withBold bool) *Writer {
  function newRenderer (line 140) | func newRenderer(saidCow, notSaidCow string) *renderer {
  constant magic (line 162) | magic = 2
  constant span (line 164) | span    = 30 * time.Millisecond
  constant standup (line 165) | standup = 3 * time.Second
  type Writer (line 239) | type Writer struct
    method WriteString (line 263) | func (w *Writer) WriteString(s string) (int, error) { return w.dw.Writ...
    method Write (line 266) | func (w *Writer) Write(p []byte) (int, error) { return w.dw.Write(p) }
    method SetPosx (line 269) | func (w *Writer) SetPosx(x int) { w.mw.SetPosx(x) }
    method SetColorSeq (line 272) | func (w *Writer) SetColorSeq(colorSeq int) { w.dw.SetColorSeq(colorSeq) }
    method Reset (line 275) | func (w *Writer) Reset() {
    method String (line 280) | func (w *Writer) String() string {

FILE: cow.go
  type Cow (line 10) | type Cow struct
    method Say (line 44) | func (cow *Cow) Say(phrase string) (string, error) {
    method Clone (line 55) | func (cow *Cow) Clone(options ...Option) (*Cow, error) {
  function New (line 23) | func New(options ...Option) (*Cow, error) {
  type Option (line 68) | type Option
  function Eyes (line 72) | func Eyes(s string) Option {
  function Tongue (line 81) | func Tongue(s string) Option {
  function adjustTo2Chars (line 88) | func adjustTo2Chars(s string) string {
  function containCows (line 98) | func containCows(target string) (*CowFile, error) {
  type NotFound (line 113) | type NotFound struct
    method Error (line 119) | func (n *NotFound) Error() string {
  function Type (line 124) | func Type(s string) Option {
  function Thinking (line 142) | func Thinking() Option {
  function Thoughts (line 152) | func Thoughts(thoughts rune) Option {
  function Random (line 160) | func Random() Option {
  function pickCow (line 171) | func pickCow() (*CowFile, error) {
  function BallonWidth (line 188) | func BallonWidth(size uint) Option {
  function DisableWordWrap (line 197) | func DisableWordWrap() Option {

FILE: cow_test.go
  function TestCow_Clone (line 12) | func TestCow_Clone(t *testing.T) {
  function Test_adjustTo2Chars (line 122) | func Test_adjustTo2Chars(t *testing.T) {
  function TestNotFound_Error (line 158) | func TestNotFound_Error(t *testing.T) {

FILE: cowsay.go
  function init (line 14) | func init() {
  function Say (line 19) | func Say(phrase string, options ...Option) (string, error) {
  type LocationType (line 28) | type LocationType
  constant InBinary (line 32) | InBinary LocationType = iota
  constant InDirectory (line 35) | InDirectory
  type CowPath (line 39) | type CowPath struct
    method Lookup (line 51) | func (c *CowPath) Lookup(target string) (*CowFile, bool) {
  type CowFile (line 65) | type CowFile struct
    method ReadAll (line 77) | func (c *CowFile) ReadAll() ([]byte, error) {
  function Cows (line 88) | func Cows() ([]*CowPath, error) {
  function cowsFromCowPath (line 101) | func cowsFromCowPath() ([]*CowPath, error) {
  method GetCow (line 132) | func (cow *Cow) GetCow() (string, error) {

FILE: cowsay_test.go
  function TestCows (line 16) | func TestCows(t *testing.T) {
  function TestCowPath_Lookup (line 94) | func TestCowPath_Lookup(t *testing.T) {
  function TestCowFile_ReadAll (line 132) | func TestCowFile_ReadAll(t *testing.T) {
  constant defaultSay (line 159) | defaultSay = ` ________
  function TestSay (line 168) | func TestSay(t *testing.T) {

FILE: decoration/aurora.go
  method writeAsAurora (line 11) | func (w *Writer) writeAsAurora(b []byte) (nn int, err error) {
  method writeStringAsAurora (line 37) | func (w *Writer) writeStringAsAurora(s string) (nn int, err error) {
  constant freq (line 64) | freq = 0.01
  constant m (line 65) | m    = math.Pi / 3
  constant redPhase (line 67) | redPhase   = 0
  constant greenPhase (line 68) | greenPhase = 2 * m
  constant bluePhase (line 69) | bluePhase  = 4 * m
  function rgb (line 74) | func rgb(i float64) int64 {

FILE: decoration/bold.go
  method writeAsDefaultBold (line 10) | func (w *Writer) writeAsDefaultBold(b []byte) (nn int, err error) {
  method writeStringAsDefaultBold (line 30) | func (w *Writer) writeStringAsDefaultBold(s string) (nn int, err error) {

FILE: decoration/decoration.go
  type options (line 8) | type options struct
    method maybeBold (line 15) | func (o *options) maybeBold() string {
  type Option (line 23) | type Option
  function WithBold (line 26) | func WithBold() Option {
  function WithRainbow (line 33) | func WithRainbow() Option {
  function WithAurora (line 40) | func WithAurora(initialSeq int) Option {
  type Writer (line 48) | type Writer struct
    method SetColorSeq (line 72) | func (w *Writer) SetColorSeq(colorSeq int) {
    method Write (line 80) | func (w *Writer) Write(b []byte) (nn int, err error) {
    method WriteString (line 96) | func (w *Writer) WriteString(s string) (n int, err error) {
  function NewWriter (line 60) | func NewWriter(w io.Writer, opts ...Option) *Writer {

FILE: decoration/rainbow.go
  constant red (line 11) | red = iota + 31
  constant green (line 12) | green
  constant yellow (line 13) | yellow
  constant blue (line 14) | blue
  constant magenta (line 15) | magenta
  constant cyan (line 16) | cyan
  method writeAsRainbow (line 21) | func (w *Writer) writeAsRainbow(b []byte) (nn int, err error) {
  method writeStringAsRainbow (line 48) | func (w *Writer) writeStringAsRainbow(s string) (nn int, err error) {

FILE: embed.go
  function Asset (line 15) | func Asset(path string) ([]byte, error) {
  function AssetNames (line 20) | func AssetNames() []string {
  function CowsInBinary (line 38) | func CowsInBinary() []string {

FILE: examples/basic/main.go
  function main (line 9) | func main() {
  function simple (line 17) | func simple() {
  function complex (line 29) | func complex() {

FILE: examples/echo-server/main.go
  constant limit (line 16) | limit = 1000
  function main (line 18) | func main() {

FILE: split.go
  function splitPath (line 8) | func splitPath(s string) []string {

FILE: split_windows.go
  function splitPath (line 8) | func splitPath(s string) []string {
Condensed preview — 123 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (132K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 11,
    "preview": "* @Code-Hex"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 17,
    "preview": "github: Code-Hex\n"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 205,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n  -"
  },
  {
    "path": ".github/workflows/lgtm.yml",
    "chars": 392,
    "preview": "on:\n  pull_request_review:\n    types:\n      - submitted\n\njobs:\n  lgtm:\n    name: LGTM\n    runs-on: ubuntu-latest\n    if:"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 1171,
    "preview": "on:\n  push:\n    branches:\n      - \"master\"\n  pull_request:\n\njobs:\n  test:\n    strategy:\n      matrix:\n        os: [ubunt"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 884,
    "preview": "on:\n  push:\n    tags:\n      - \"v*.*.*\"\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n    steps:\n    - n"
  },
  {
    "path": ".gitignore",
    "chars": 315,
    "preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture spe"
  },
  {
    "path": ".goreleaser.yml",
    "chars": 2165,
    "preview": "builds:\n  - id: cowsay\n    dir: cmd\n    main: ./cowsay/main.go\n    binary: cowsay\n    env:\n      - CGO_ENABLED=0\n    ldf"
  },
  {
    "path": "LICENSE",
    "chars": 8893,
    "preview": "\t\t       The Artistic License 2.0\n\n\t    Copyright (c) 2000-2006, The Perl Foundation.\n\n     Everyone is permitted to cop"
  },
  {
    "path": "Makefile",
    "chars": 715,
    "preview": ".PHONY: build\nbuild: build/cowsay build/cowthink\n\n.PHONY: build/cowsay\nbuild/cowsay:\n\tCGO_ENABLED=0 cd cmd && go build -"
  },
  {
    "path": "README.md",
    "chars": 5221,
    "preview": "# Neo Cowsay\n\nNeo Cowsay is written in Go. This cowsay is extended the original cowsay. added fun more options, and you "
  },
  {
    "path": "balloon.go",
    "chars": 3259,
    "preview": "package cowsay\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\twordwrap \"github.com/Code-Hex/go-wordwrap\"\n\trunewidth \"github.com/mattn/go-"
  },
  {
    "path": "bin/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "cmd/cmd.go",
    "chars": 12,
    "preview": "package cmd\n"
  },
  {
    "path": "cmd/cowsay/main.go",
    "chars": 205,
    "preview": "package main\n\nimport (\n\t\"os\"\n\n\t\"github.com/Code-Hex/Neo-cowsay/cmd/v2/internal/cli\"\n)\n\nvar version string\n\nfunc main() {"
  },
  {
    "path": "cmd/cowthink/main.go",
    "chars": 204,
    "preview": "package main\n\nimport (\n\t\"os\"\n\n\t\"github.com/Code-Hex/Neo-cowsay/cmd/v2/internal/cli\"\n)\n\nvar version string\n\nfunc main() {"
  },
  {
    "path": "cmd/go.mod",
    "chars": 448,
    "preview": "module github.com/Code-Hex/Neo-cowsay/cmd/v2\n\ngo 1.16\n\nrequire (\n\tgithub.com/Code-Hex/Neo-cowsay/v2 v2.0.3\n\tgithub.com/C"
  },
  {
    "path": "cmd/go.sum",
    "chars": 6738,
    "preview": "github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=\ngithub.com/Code-Hex/go-wordwrap v"
  },
  {
    "path": "cmd/internal/cli/cli.go",
    "chars": 6285,
    "preview": "package cli\n\nimport (\n\t\"bufio\"\n\tcryptorand \"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"math/big\"\n\t\"math/rand\"\n\t\"os\"\n\t"
  },
  {
    "path": "cmd/internal/cli/cli_test.go",
    "chars": 3828,
    "preview": "package cli\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cm"
  },
  {
    "path": "cmd/internal/screen/buffer.go",
    "chars": 2717,
    "preview": "package screen\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n)\n\n// buffer is the global screen buffer\n// Its not recommende"
  },
  {
    "path": "cmd/internal/screen/screen.go",
    "chars": 1124,
    "preview": "package screen\n\nimport (\n\t\"os\"\n\t\"sync\"\n\n\tcolorable \"github.com/mattn/go-colorable\"\n\t\"golang.org/x/crypto/ssh/terminal\"\n)"
  },
  {
    "path": "cmd/internal/super/supercow.go",
    "chars": 5794,
    "preview": "package super\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/Code-Hex/Neo-cows"
  },
  {
    "path": "cmd/testdata/cowsay/W_option.txt",
    "chars": 163,
    "preview": " _____ \n/ foo \\\n| bar |\n\\ baz /\n ----- \n        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n         "
  },
  {
    "path": "cmd/testdata/cowsay/b_option.txt",
    "chars": 165,
    "preview": " ___________ \n< foobarbaz >\n ----------- \n        \\   ^__^\n         \\  (==)\\_______\n            (__)\\       )\\/\\\n       "
  },
  {
    "path": "cmd/testdata/cowsay/d_option.txt",
    "chars": 168,
    "preview": " ____________ \n< 0xdeadbeef >\n ------------ \n        \\   ^__^\n         \\  (xx)\\_______\n            (__)\\       )\\/\\\n    "
  },
  {
    "path": "cmd/testdata/cowsay/eyes_option.txt",
    "chars": 177,
    "preview": " _______________ \n< I'm not angry >\n --------------- \n        \\   ^__^\n         \\  (^^)\\_______\n            (__)\\       "
  },
  {
    "path": "cmd/testdata/cowsay/f_tux_option.txt",
    "chars": 173,
    "preview": " ________________ \n< what is macOS? >\n ---------------- \n   \\\n    \\\n        .--.\n       |o_o |\n       |:_/ |\n      //   "
  },
  {
    "path": "cmd/testdata/cowsay/g_option.txt",
    "chars": 177,
    "preview": " _______________ \n< give me money >\n --------------- \n        \\   ^__^\n         \\  ($$)\\_______\n            (__)\\       "
  },
  {
    "path": "cmd/testdata/cowsay/n_option.txt",
    "chars": 163,
    "preview": " _____ \n/ foo \\\n| bar |\n\\ baz /\n ----- \n        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n         "
  },
  {
    "path": "cmd/testdata/cowsay/p_option.txt",
    "chars": 189,
    "preview": " ___________________ \n< everyone hates me >\n ------------------- \n        \\   ^__^\n         \\  (@@)\\_______\n            "
  },
  {
    "path": "cmd/testdata/cowsay/s_option.txt",
    "chars": 174,
    "preview": " ______________ \n< I don't know >\n -------------- \n        \\   ^__^\n         \\  (**)\\_______\n            (__)\\       )\\/"
  },
  {
    "path": "cmd/testdata/cowsay/t_option.txt",
    "chars": 153,
    "preview": " _______ \n< tired >\n ------- \n        \\   ^__^\n         \\  (--)\\_______\n            (__)\\       )\\/\\\n                ||-"
  },
  {
    "path": "cmd/testdata/cowsay/tongue_option.txt",
    "chars": 156,
    "preview": " ________ \n< hungry >\n -------- \n        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n             :  "
  },
  {
    "path": "cmd/testdata/cowsay/wired_option.txt",
    "chars": 210,
    "preview": " __________________________ \n< Wanna Netflix and chill? >\n -------------------------- \n        \\   ^__^\n         \\  (OO)"
  },
  {
    "path": "cmd/testdata/cowsay/y_option.txt",
    "chars": 204,
    "preview": " ________________________ \n< I forgot my ID at home >\n ------------------------ \n        \\   ^__^\n         \\  (..)\\_____"
  },
  {
    "path": "cmd/testdata/cowthink/W_option.txt",
    "chars": 163,
    "preview": " _____ \n( foo )\n( bar )\n( baz )\n ----- \n        o   ^__^\n         o  (oo)\\_______\n            (__)\\       )\\/\\\n         "
  },
  {
    "path": "cmd/testdata/cowthink/b_option.txt",
    "chars": 165,
    "preview": " ___________ \n( foobarbaz )\n ----------- \n        o   ^__^\n         o  (==)\\_______\n            (__)\\       )\\/\\\n       "
  },
  {
    "path": "cmd/testdata/cowthink/d_option.txt",
    "chars": 168,
    "preview": " ____________ \n( 0xdeadbeef )\n ------------ \n        o   ^__^\n         o  (xx)\\_______\n            (__)\\       )\\/\\\n    "
  },
  {
    "path": "cmd/testdata/cowthink/eyes_option.txt",
    "chars": 177,
    "preview": " _______________ \n( I'm not angry )\n --------------- \n        o   ^__^\n         o  (^^)\\_______\n            (__)\\       "
  },
  {
    "path": "cmd/testdata/cowthink/f_tux_option.txt",
    "chars": 173,
    "preview": " ________________ \n( what is macOS? )\n ---------------- \n   o\n    o\n        .--.\n       |o_o |\n       |:_/ |\n      //   "
  },
  {
    "path": "cmd/testdata/cowthink/g_option.txt",
    "chars": 177,
    "preview": " _______________ \n( give me money )\n --------------- \n        o   ^__^\n         o  ($$)\\_______\n            (__)\\       "
  },
  {
    "path": "cmd/testdata/cowthink/n_option.txt",
    "chars": 163,
    "preview": " _____ \n( foo )\n( bar )\n( baz )\n ----- \n        o   ^__^\n         o  (oo)\\_______\n            (__)\\       )\\/\\\n         "
  },
  {
    "path": "cmd/testdata/cowthink/p_option.txt",
    "chars": 189,
    "preview": " ___________________ \n( everyone hates me )\n ------------------- \n        o   ^__^\n         o  (@@)\\_______\n            "
  },
  {
    "path": "cmd/testdata/cowthink/s_option.txt",
    "chars": 174,
    "preview": " ______________ \n( I don't know )\n -------------- \n        o   ^__^\n         o  (**)\\_______\n            (__)\\       )\\/"
  },
  {
    "path": "cmd/testdata/cowthink/t_option.txt",
    "chars": 153,
    "preview": " _______ \n( tired )\n ------- \n        o   ^__^\n         o  (--)\\_______\n            (__)\\       )\\/\\\n                ||-"
  },
  {
    "path": "cmd/testdata/cowthink/tongue_option.txt",
    "chars": 156,
    "preview": " ________ \n( hungry )\n -------- \n        o   ^__^\n         o  (oo)\\_______\n            (__)\\       )\\/\\\n             :  "
  },
  {
    "path": "cmd/testdata/cowthink/wired_option.txt",
    "chars": 210,
    "preview": " __________________________ \n( Wanna Netflix and chill? )\n -------------------------- \n        o   ^__^\n         o  (OO)"
  },
  {
    "path": "cmd/testdata/cowthink/y_option.txt",
    "chars": 204,
    "preview": " ________________________ \n( I forgot my ID at home )\n ------------------------ \n        o   ^__^\n         o  (..)\\_____"
  },
  {
    "path": "cow.go",
    "chars": 3788,
    "preview": "package cowsay\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n)\n\n// Cow struct!!\ntype Cow struct {\n\teyes            string\n\tto"
  },
  {
    "path": "cow_test.go",
    "chars": 2809,
    "preview": "package cowsay\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmp"
  },
  {
    "path": "cows/beavis.zen.cow",
    "chars": 584,
    "preview": "##\n## Beavis, with Zen philosophy removed.\n##\n$the_cow = <<EOC;\n   $thoughts         __------~~-,\n    $thoughts      ,' "
  },
  {
    "path": "cows/bong.cow",
    "chars": 286,
    "preview": "##\n## A cow with a bong, from lars@csua.berkeley.edu\n##\n$the_cow = <<EOC;\n         $thoughts\n          $thoughts\n       "
  },
  {
    "path": "cows/bud-frogs.cow",
    "chars": 310,
    "preview": "##\n## The Budweiser frogs\n##\n$the_cow = <<EOC;\n     $thoughts\n      $thoughts\n          oO)-.                       .-(O"
  },
  {
    "path": "cows/bunny.cow",
    "chars": 123,
    "preview": "##\n## A cute little wabbit\n##\n$the_cow = <<EOC;\n  $thoughts\n   $thoughts   \\\\\n        \\\\ /\\\\\n        ( )\n      .( o ).\nE"
  },
  {
    "path": "cows/cheese.cow",
    "chars": 480,
    "preview": "##\n## The cheese from milk & cheese\n##\n$the_cow = <<EOC;\n   $thoughts\n    $thoughts\n      _____   _________\n     /     \\"
  },
  {
    "path": "cows/cower.cow",
    "chars": 230,
    "preview": "##\n## A cowering cow\n##\n$the_cow = <<EOC;\n     $thoughts\n      $thoughts\n        ,__, |    | \n        (oo)\\\\|    |___\n  "
  },
  {
    "path": "cows/daemon.cow",
    "chars": 569,
    "preview": "##\n## 4.4 >> 5.4\n##\n$the_cow = <<EOC;\n   $thoughts         ,        ,\n    $thoughts       /(        )`\n     $thoughts   "
  },
  {
    "path": "cows/default.cow",
    "chars": 173,
    "preview": "$the_cow = <<EOC;\n        $thoughts   ^__^\n         $thoughts  ($eyes)\\\\_______\n            (__)\\\\       )\\\\/\\\\\n        "
  },
  {
    "path": "cows/deno.cow",
    "chars": 272,
    "preview": "## https://github.com/kawarimidoll/deno-cli-tools/blob/30107adad1dd7d00da8be08c76f843bbfd88b455/denosay/mod.ts#L64-L73\n$"
  },
  {
    "path": "cows/docker.cow",
    "chars": 344,
    "preview": "##\n## Docker Cow\n##\n$the_cow = <<EOC;\n    $thoughts\n     $thoughts\n      $thoughts\n                    ##         .\n    "
  },
  {
    "path": "cows/dragon-and-cow.cow",
    "chars": 1284,
    "preview": "##\n## A dragon smiting a cow, possible credit to kube@csua.berkeley.edu\n##\n$the_cow = <<EOC;\n                       $tho"
  },
  {
    "path": "cows/dragon.cow",
    "chars": 1000,
    "preview": "##\n## The Whitespace Dragon\n##\n$the_cow = <<EOC;\n      $thoughts                    / \\\\  //\\\\\n       $thoughts    |\\\\__"
  },
  {
    "path": "cows/elephant-in-snake.cow",
    "chars": 295,
    "preview": "##\n## Do we need to explain this?\n##\n$the_cow = <<EOC;\n   $thoughts\n    $thoughts              ....       \n           .."
  },
  {
    "path": "cows/elephant.cow",
    "chars": 284,
    "preview": "##\n## An elephant out and about\n##\n$the_cow = <<EOC;\n $thoughts     /\\\\  ___  /\\\\\n  $thoughts   // \\\\/   \\\\/ \\\\\\\\\n     ("
  },
  {
    "path": "cows/eyes.cow",
    "chars": 585,
    "preview": "##\n## Evil-looking eyes\n##\n$the_cow = <<EOC;\n    $thoughts\n     $thoughts\n                                   .::!!!!!!!:"
  },
  {
    "path": "cows/flaming-sheep.cow",
    "chars": 490,
    "preview": "##\n## The flaming sheep, contributed by Geordan Rosario (geordan@csua.berkeley.edu)\n##\n$the_cow = <<EOC;\n  $thoughts    "
  },
  {
    "path": "cows/ghostbusters.cow",
    "chars": 1018,
    "preview": "##\n## Ghostbusters!\n##\n$the_cow = <<EOC;\n          $thoughts\n           $thoughts\n            $thoughts          __---__"
  },
  {
    "path": "cows/gopher.cow",
    "chars": 441,
    "preview": "$the_cow = <<EOC;\n    $thoughts \n     $thoughts    ,_---~~~~~----._         \n  _,,_,*^____      _____``*g*\\\\\"*, \n / __/ "
  },
  {
    "path": "cows/head-in.cow",
    "chars": 257,
    "preview": "##\n## Go stick yer head in a cow.\n##\n$the_cow = <<EOC;\n    $thoughts\n     $thoughts\n    ^__^         /\n    ($eyes)\\\\____"
  },
  {
    "path": "cows/hellokitty.cow",
    "chars": 126,
    "preview": "##\n## Hello Kitty\n##\n$the_cow = <<EOC;\n  $thoughts\n   $thoughts\n      /\\\\_)o<\n     |      \\\\\n     | O . O|\n      \\\\_____"
  },
  {
    "path": "cows/kiss.cow",
    "chars": 637,
    "preview": "##\n## A lovers' empbrace\n##\n$the_cow = <<EOC;\n     $thoughts\n      $thoughts\n             ,;;;;;;;,\n            ;;;;;;;;"
  },
  {
    "path": "cows/kitty.cow",
    "chars": 296,
    "preview": "##\n## A kitten of sorts, I think\n##\n$the_cow = <<EOC;\n     $thoughts\n      $thoughts\n       (\"`-'  '-/\") .___..--' ' \"`-"
  },
  {
    "path": "cows/koala.cow",
    "chars": 162,
    "preview": "##\n## From the canonical koala collection\n##\n$the_cow = <<EOC;\n  $thoughts\n   $thoughts\n       ___  \n     {~._.~}\n      "
  },
  {
    "path": "cows/kosh.cow",
    "chars": 406,
    "preview": "##\n## It's a Kosh Cow!\n##\n$the_cow = <<EOC;\n    $thoughts\n     $thoughts\n      $thoughts\n  ___       _____     ___\n /   "
  },
  {
    "path": "cows/luke-koala.cow",
    "chars": 225,
    "preview": "##\n## From the canonical koala collection\n##\n$the_cow = <<EOC;\n  $thoughts\n   $thoughts          .\n       ___   //\n     "
  },
  {
    "path": "cows/meow.cow",
    "chars": 473,
    "preview": "##\n## A meowing tiger?\n##\n$the_cow = <<EOC;\n  $thoughts\n   $thoughts ,   _ ___.--'''`--''//-,-_--_.\n      \\\\`\"' ` || \\\\\\"
  },
  {
    "path": "cows/milk.cow",
    "chars": 439,
    "preview": "##\n## Milk from Milk and Cheese\n##\n$the_cow = <<EOC;\n $thoughts     ____________ \n  $thoughts    |__________|\n      /   "
  },
  {
    "path": "cows/moofasa.cow",
    "chars": 245,
    "preview": "##\n## MOOfasa.\n##\n$the_cow = <<EOC;\n       $thoughts    ____\n        $thoughts  /    \\\\\n          | ^__^ |\n          | ("
  },
  {
    "path": "cows/moose.cow",
    "chars": 203,
    "preview": "$the_cow = <<EOC;\n  $thoughts\n   $thoughts   \\\\_\\\\_    _/_/\n    $thoughts      \\\\__/\n           ($eyes)\\\\_______\n       "
  },
  {
    "path": "cows/mutilated.cow",
    "chars": 201,
    "preview": "##\n## A mutilated cow, from aspolito@csua.berkeley.edu\n##\n$the_cow = <<EOC;\n       $thoughts   \\\\_______\n v__v   $though"
  },
  {
    "path": "cows/ren.cow",
    "chars": 252,
    "preview": "##\n## Ren \n##\n$the_cow = <<EOC;\n   $thoughts\n    $thoughts\n    ____  \n   /# /_\\\\_\n  |  |/o\\\\o\\\\\n  |  \\\\\\\\_/_/\n / |_   | "
  },
  {
    "path": "cows/sage.cow",
    "chars": 290,
    "preview": "## http://www.chris.com/ascii/joan/www.geocities.com/SoHo/7373/men.html#confucious\n$the_cow = <<EOC;\n   $thoughts\n    $t"
  },
  {
    "path": "cows/satanic.cow",
    "chars": 186,
    "preview": "##\n## Satanic cow, source unknown.\n##\n$the_cow = <<EOC;\n     $thoughts\n      $thoughts  (__)  \n         (\\\\/)  \n  /-----"
  },
  {
    "path": "cows/sheep.cow",
    "chars": 234,
    "preview": "##\n## The non-flaming sheep.\n##\n$the_cow = <<EOC\n  $thoughts\n   $thoughts\n       __     \n      U${eyes}U\\\\.'\\@\\@\\@\\@\\@\\@"
  },
  {
    "path": "cows/skeleton.cow",
    "chars": 433,
    "preview": "##\n## This 'Scowleton' brought to you by one of \n## {appel,kube,rowe}@csua.berkeley.edu\n##\n$the_cow = <<EOC;\n          $"
  },
  {
    "path": "cows/small.cow",
    "chars": 165,
    "preview": "##\n## A small cow, artist unknown\n##\n$the_cow = <<EOC;\n       $thoughts   ,__,\n        $thoughts  ($eyes)____\n          "
  },
  {
    "path": "cows/sodomized.cow",
    "chars": 317,
    "preview": "##\n## A cow performing an unnatural act, artist unknown.\n##\n$the_cow = <<EOC;\n      $thoughts                _\n       $t"
  },
  {
    "path": "cows/squirrel.cow",
    "chars": 283,
    "preview": "$the_cow = <<EOC;\n   $thoughts\n    $thoughts\n                  _ _\n       | \\__/|  .~    ~.\n       /$eyes `./      .'\n  "
  },
  {
    "path": "cows/stegosaurus.cow",
    "chars": 854,
    "preview": "##\n## A stegosaur with a top hat?\n##\n$the_cow = <<EOC;\n    $thoughts                         .       .\n     $thoughts   "
  },
  {
    "path": "cows/stimpy.cow",
    "chars": 364,
    "preview": "##\n## Stimpy!\n##\n$the_cow = <<EOC;\n  $thoughts     .    _  .    \n   $thoughts    |\\\\_|/__/|    \n       / / \\\\/ \\\\  \\\\  \n"
  },
  {
    "path": "cows/supermilker.cow",
    "chars": 280,
    "preview": "##\n## A cow being milked, probably from Lars Smith (lars@csua.berkeley.edu)\n##\n$the_cow = <<EOC;\n  $thoughts   ^__^\n   $"
  },
  {
    "path": "cows/surgery.cow",
    "chars": 892,
    "preview": "##\n## A cow operation, artist unknown\n##\n$the_cow = <<EOC;\n          $thoughts           \\\\  / \n           $thoughts    "
  },
  {
    "path": "cows/telebears.cow",
    "chars": 333,
    "preview": "##\n## A cow performing an unnatural act, artist unknown.\n##\n$the_cow = <<EOC;\n      $thoughts                _\n       $t"
  },
  {
    "path": "cows/turkey.cow",
    "chars": 1302,
    "preview": "##\n## Turkey!\n##\n$the_cow = <<EOC;\n  $thoughts                                  ,+*^^*+___+++_\n   $thoughts             "
  },
  {
    "path": "cows/turtle.cow",
    "chars": 1105,
    "preview": "##\n## A mysterious turtle...\n##\n$the_cow = <<EOC;\n    $thoughts                                  ___-------___\n     $tho"
  },
  {
    "path": "cows/tux.cow",
    "chars": 215,
    "preview": "##\n## TuX\n## (c) pborys@p-soft.silesia.linux.org.pl \n##\n$the_cow = <<EOC;\n   $thoughts\n    $thoughts\n        .--.\n      "
  },
  {
    "path": "cows/vader-koala.cow",
    "chars": 213,
    "preview": "##\n## Another canonical koala?\n##\n$the_cow = <<EOC;\n   $thoughts\n    $thoughts        .\n     .---.  //\n    Y|o o|Y// \n  "
  },
  {
    "path": "cows/vader.cow",
    "chars": 279,
    "preview": "##\n## Cowth Vader, from geordan@csua.berkeley.edu\n##\n$the_cow = <<EOC;\n        $thoughts    ,-^-.\n         $thoughts   !"
  },
  {
    "path": "cows/www.cow",
    "chars": 248,
    "preview": "##\n## A cow wadvertising the World Wide Web, from lim@csua.berkeley.edu\n##\n$the_cow = <<EOC;\n        $thoughts   ^__^\n  "
  },
  {
    "path": "cowsay.go",
    "chars": 3737,
    "preview": "package cowsay\n\nimport (\n\t\"io/ioutil\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc ini"
  },
  {
    "path": "cowsay_test.go",
    "chars": 4728,
    "preview": "package cowsay\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/goog"
  },
  {
    "path": "decoration/aurora.go",
    "chars": 1675,
    "preview": "package decoration\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\nfunc (w *Writer) writeAsAurora(b []byte)"
  },
  {
    "path": "decoration/bold.go",
    "chars": 903,
    "preview": "package decoration\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\nfunc (w *Writer) writeAsDefaultBold(b []byte) (n"
  },
  {
    "path": "decoration/decoration.go",
    "chars": 2211,
    "preview": "package decoration\n\nimport (\n\t\"bytes\"\n\t\"io\"\n)\n\ntype options struct {\n\twithBold    bool\n\twithRainbow bool\n\twithAurora  bo"
  },
  {
    "path": "decoration/rainbow.go",
    "chars": 1291,
    "preview": "package decoration\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\nconst (\n\tred = iota + 31\n\tgreen\n\tyellow\n\tblue\n\tm"
  },
  {
    "path": "doc/cowsay.1",
    "chars": 5545,
    "preview": "'\\\" t\n.\\\"     Title: cowsay\n.\\\"    Author: [see the \"AUTHOR(S)\" section]\n.\\\" Generator: Asciidoctor 2.0.16\n.\\\"      Date"
  },
  {
    "path": "doc/cowsay.1.txt.tpl",
    "chars": 4653,
    "preview": "cowsay(1)\n=========\n\nName\n----\nNeo cowsay/cowthink - configurable speaking/thinking cow (and a bit more)\n\nSYNOPSIS\n-----"
  },
  {
    "path": "embed.go",
    "chars": 847,
    "preview": "package cowsay\n\nimport (\n\t\"embed\"\n\t\"sort\"\n\t\"strings\"\n)\n\n//go:embed cows/*\nvar cowsDir embed.FS\n\n// Asset loads and retur"
  },
  {
    "path": "examples/basic/go.mod",
    "chars": 161,
    "preview": "module github.com/Code-Hex/Neo-cowsay/v2/example\n\ngo 1.16\n\nrequire github.com/Code-Hex/Neo-cowsay/v2 v2.0.1\n\nreplace git"
  },
  {
    "path": "examples/basic/go.sum",
    "chars": 1108,
    "preview": "github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=\ngithub.com/Code-Hex/go-wordwrap v"
  },
  {
    "path": "examples/basic/main.go",
    "chars": 533,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\n\tcowsay \"github.com/Code-Hex/Neo-cowsay/v2\"\n)\n\nfunc main() {\n\tif false {\n\t\tsimple()\n\t} el"
  },
  {
    "path": "examples/echo-server/README.md",
    "chars": 418,
    "preview": "## echo server\n\n```\n$ go build\n$ ./echo-server\n2021/11/14 16:16:27 server addr => 127.0.0.1:54456\n```\n\n\n## client\n\nUse ["
  },
  {
    "path": "examples/echo-server/go.mod",
    "chars": 174,
    "preview": "module github.com/Code-Hex/Neo-cowsay/v2/examples/echo-server\n\ngo 1.16\n\nrequire github.com/Code-Hex/Neo-cowsay/v2 v2.0.1"
  },
  {
    "path": "examples/echo-server/go.sum",
    "chars": 1108,
    "preview": "github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=\ngithub.com/Code-Hex/go-wordwrap v"
  },
  {
    "path": "examples/echo-server/main.go",
    "chars": 1008,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"time\"\n\n\tcowsay \"github.com/Code-He"
  },
  {
    "path": "go.mod",
    "chars": 244,
    "preview": "module github.com/Code-Hex/Neo-cowsay/v2\n\nrequire (\n\tgithub.com/Code-Hex/go-wordwrap v1.0.0\n\tgithub.com/google/go-cmp v0"
  },
  {
    "path": "go.sum",
    "chars": 1108,
    "preview": "github.com/Code-Hex/go-wordwrap v1.0.0 h1:yl5fLyZEz3+hPGbpTRlTQ8mQJ1HXWcTq1FCNR1ch6zM=\ngithub.com/Code-Hex/go-wordwrap v"
  },
  {
    "path": "split.go",
    "chars": 142,
    "preview": "//go:build !windows\n// +build !windows\n\npackage cowsay\n\nimport \"strings\"\n\nfunc splitPath(s string) []string {\n\treturn st"
  },
  {
    "path": "split_windows.go",
    "chars": 140,
    "preview": "//go:build windows\n// +build windows\n\npackage cowsay\n\nimport \"strings\"\n\nfunc splitPath(s string) []string {\n\treturn stri"
  },
  {
    "path": "testdata/default.cow",
    "chars": 155,
    "preview": " ________ \n< hello! >\n -------- \n        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n                "
  },
  {
    "path": "testdata/nest.cow",
    "chars": 452,
    "preview": " ______________________________ \n/  ________                    \\\n| < cowsay >                   |\n|  --------          "
  },
  {
    "path": "testdata/testdir/test.cow",
    "chars": 173,
    "preview": "$the_cow = <<EOC;\n        $thoughts   ^__^\n         $thoughts  ($eyes)\\\\_______\n            (__)\\\\       )\\\\/\\\\\n        "
  }
]

About this extraction

This page contains the full source code of the Code-Hex/Neo-cowsay GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 123 files (112.2 KB), approximately 39.9k tokens, and a symbol index with 145 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!