Initial commit
commit
534eab9fac
|
@ -0,0 +1 @@
|
|||
atmosphere
|
|
@ -0,0 +1,131 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Forecast is a representation of the current state of the weather.
|
||||
type Forecast struct {
|
||||
raw string
|
||||
time TimeOfDay
|
||||
cloudiness Cloudiness
|
||||
raininess Raininess
|
||||
visibility Visibility
|
||||
windiness Windiness
|
||||
}
|
||||
|
||||
// NewForecast parses the output of ~iajrz's climate program.
|
||||
// TODO?: boolean randomize option to generate completely random weather as a demo mode?
|
||||
func NewForecast() (Forecast, error) {
|
||||
out, err := exec.Command("/home/iajrz/climate").Output()
|
||||
if err != nil {
|
||||
return Forecast{}, err
|
||||
}
|
||||
rawWeather := string(out)
|
||||
return Forecast{
|
||||
raw: rawWeather,
|
||||
time: TimeOfDay(findSubstring(rawWeather, timeStrings)),
|
||||
cloudiness: Cloudiness(findSubstring(rawWeather, cloudStrings)),
|
||||
raininess: Raininess(findSubstring(rawWeather, rainStrings)),
|
||||
visibility: Visibility(findSubstring(rawWeather, visibilityStrings)),
|
||||
windiness: Windiness(findSubstring(rawWeather, windStrings)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f Forecast) String() string {
|
||||
return f.raw
|
||||
}
|
||||
|
||||
func findSubstring(s string, substrings []string) int {
|
||||
for i := range substrings {
|
||||
if strings.Contains(s, substrings[i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type TimeOfDay int
|
||||
|
||||
const (
|
||||
EarlyMorning TimeOfDay = iota
|
||||
Morning
|
||||
Afternoon
|
||||
Night
|
||||
)
|
||||
|
||||
var timeStrings = []string{
|
||||
"early morning",
|
||||
"morning",
|
||||
"afternoon",
|
||||
"night",
|
||||
}
|
||||
|
||||
type Cloudiness int
|
||||
|
||||
const (
|
||||
ClearSky Cloudiness = iota
|
||||
AlmostClear
|
||||
PartlyCloudy
|
||||
MostlyCloudy
|
||||
Cloudy
|
||||
)
|
||||
|
||||
var cloudStrings = []string{
|
||||
"clear",
|
||||
"almost clear",
|
||||
"partly cloudy",
|
||||
"mostly cloudy",
|
||||
"cloudy",
|
||||
}
|
||||
|
||||
type Raininess int
|
||||
|
||||
const (
|
||||
NoRain Raininess = iota
|
||||
Drizzle
|
||||
LightShower
|
||||
Shower
|
||||
HeavyShower
|
||||
)
|
||||
|
||||
var rainStrings = []string{
|
||||
"no rain",
|
||||
"a drizzle",
|
||||
"a light shower",
|
||||
"a shower",
|
||||
"a heavy shower",
|
||||
}
|
||||
|
||||
type Visibility int
|
||||
|
||||
const (
|
||||
NoFog Visibility = iota
|
||||
Haze
|
||||
Mist
|
||||
Fog
|
||||
HeavyFog
|
||||
)
|
||||
|
||||
var visibilityStrings = []string{
|
||||
"visibility",
|
||||
"There's haze",
|
||||
"There's mist",
|
||||
"There's fog",
|
||||
"There's heavy fog",
|
||||
}
|
||||
|
||||
type Windiness int
|
||||
|
||||
const (
|
||||
NoWind Windiness = iota
|
||||
Breeze
|
||||
StiffWind
|
||||
)
|
||||
|
||||
var windStrings = []string{
|
||||
"no breeze",
|
||||
"light breeze",
|
||||
"stiff wind",
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/muesli/reflow/wordwrap"
|
||||
"github.com/muesli/termenv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := tea.NewProgram(model{startTime: time.Now()})
|
||||
if err := app.Start(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Queues the initial loading of the forecast and
|
||||
func (m model) Init() tea.Cmd {
|
||||
return tea.Batch(updateForecast, renderOften)
|
||||
}
|
||||
|
||||
var updateForecast = func() tea.Msg {
|
||||
forecast, err := NewForecast()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return forecast
|
||||
}
|
||||
|
||||
var updateForecastOften = tea.Tick(20*time.Second, func(t time.Time) tea.Msg {
|
||||
return updateForecast()
|
||||
})
|
||||
|
||||
var makeSceneMsg = func(f Forecast) func() tea.Msg {
|
||||
return func() tea.Msg {
|
||||
scene, err := NewScene("scene1", f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return scene
|
||||
}
|
||||
}
|
||||
|
||||
type fadeOut float32
|
||||
type fadeIn float32
|
||||
|
||||
// Used to update the progress of a fade out transition.
|
||||
var tickFadeOut = tea.Every(time.Millisecond*100, func(t time.Time) tea.Msg {
|
||||
return fadeOut(0.05)
|
||||
})
|
||||
|
||||
// Used to update the progress of a fade in transition.
|
||||
var tickFadeIn = tea.Every(time.Millisecond*100, func(t time.Time) tea.Msg {
|
||||
return fadeIn(0.05)
|
||||
})
|
||||
|
||||
type renderTick struct{}
|
||||
|
||||
// Used to update the screen at least once per second.
|
||||
var renderOften = tea.Tick(time.Second, func(t time.Time) tea.Msg {
|
||||
return renderTick{}
|
||||
})
|
||||
|
||||
// Update updates the internal state of the model and queues any events that
|
||||
// need to be scheduled.
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
cmds := []tea.Cmd{}
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "ctrl+d", "q":
|
||||
return m, tea.Quit
|
||||
case "esc":
|
||||
// TODO: Menu for options. Maybe 100% randomized weather?
|
||||
}
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
m.height = msg.Height
|
||||
|
||||
case Forecast:
|
||||
// Re-queue the forecast polling.
|
||||
cmds = append(cmds, updateForecastOften)
|
||||
|
||||
// No action required if the forecast hasn't changed.
|
||||
if msg == m.Forecast {
|
||||
break
|
||||
}
|
||||
|
||||
// If this isn't the initial startup forecast, we need to fade out the scene.
|
||||
if m.Forecast != (Forecast{}) {
|
||||
m.fading = true
|
||||
cmds = append(cmds, tickFadeOut)
|
||||
}
|
||||
|
||||
// In all cases, we need to load a scene with the forecast.
|
||||
m.Forecast = msg
|
||||
cmds = append(cmds, makeSceneMsg(m.Forecast))
|
||||
|
||||
case Scene:
|
||||
if m.Scene.foreground == nil {
|
||||
m.Scene = msg
|
||||
} else {
|
||||
m.nextScene = msg
|
||||
}
|
||||
|
||||
case fadeOut:
|
||||
m.fadeProgress += float32(msg)
|
||||
if m.fadeProgress >= 1.0 {
|
||||
m.fadeProgress = 1.0
|
||||
// To unfade, we need a Scene ready to rock. If we don't have one, stall.
|
||||
if m.nextScene.foreground == nil {
|
||||
cmds = append(cmds, tickFadeOut)
|
||||
break
|
||||
}
|
||||
|
||||
m.Scene = m.nextScene
|
||||
m.nextScene = Scene{}
|
||||
cmds = append(cmds, tickFadeIn)
|
||||
break
|
||||
}
|
||||
cmds = append(cmds, tickFadeOut)
|
||||
|
||||
case fadeIn:
|
||||
m.fadeProgress -= float32(msg)
|
||||
if m.fadeProgress <= 0.0 {
|
||||
m.fadeProgress = 0.0
|
||||
m.fading = false
|
||||
break
|
||||
}
|
||||
cmds = append(cmds, tickFadeIn)
|
||||
|
||||
case error:
|
||||
m.err = msg
|
||||
|
||||
case renderTick:
|
||||
cmds = append(cmds, renderOften)
|
||||
}
|
||||
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
// View lays out the screen and queries the Scene for its contents.
|
||||
// It also handles transitions when changing from Scene to Scene.
|
||||
func (m model) View() string {
|
||||
if m.err != nil {
|
||||
return m.err.Error()
|
||||
}
|
||||
|
||||
weather := wordwrap.String(m.Forecast.String(), m.width)
|
||||
m.height -= strings.Count(weather, "\n")
|
||||
weather = strings.TrimSpace(weather) // Trim trailing newline
|
||||
|
||||
output := ""
|
||||
lastStyle := Style{}
|
||||
profile := termenv.EnvColorProfile()
|
||||
|
||||
// Center scene in terminal
|
||||
xOff := (m.Scene.Width - m.width) / 2
|
||||
yOff := (m.Scene.Height - m.height) / 2
|
||||
|
||||
for y := yOff; y < yOff+m.height; y++ {
|
||||
for x := xOff; x < xOff+m.width; x++ {
|
||||
char, style := m.Scene.GetCell(x, y, int(time.Since(m.startTime).Seconds()))
|
||||
style = style.Convert(profile)
|
||||
|
||||
// For wipe transitions, replace character with blank space.
|
||||
if float32((x-xOff)/2+y-yOff) < m.fadeProgress*float32(m.width/2+m.height) {
|
||||
char = ' '
|
||||
style = Style{}
|
||||
}
|
||||
|
||||
// Only output formatting escape codes if the style's changed since the last cell.
|
||||
if lastStyle.String() != style.String() {
|
||||
output += style.String()
|
||||
lastStyle = style
|
||||
}
|
||||
|
||||
output += string(char)
|
||||
}
|
||||
output += "\n"
|
||||
}
|
||||
|
||||
output += termenv.CSI + termenv.ResetSeq + "m"
|
||||
output += weather
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
type model struct {
|
||||
Forecast
|
||||
Scene
|
||||
err error
|
||||
nextScene Scene
|
||||
fading bool
|
||||
fadeProgress float32
|
||||
width int
|
||||
height int
|
||||
startTime time.Time
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/muesli/termenv"
|
||||
"github.com/ojrac/opensimplex-go"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Style represents a pair of colors, foreground and background.
|
||||
type Style struct {
|
||||
fg termenv.Color
|
||||
bg termenv.Color
|
||||
}
|
||||
|
||||
// Convert is a wrapper for termenv.Profile.Convert, it converts the foreground
|
||||
// and background colors of a Style to be within a given terminal's Profile.
|
||||
func (s Style) Convert(profile termenv.Profile) Style {
|
||||
return Style{
|
||||
profile.Convert(s.fg),
|
||||
profile.Convert(s.bg),
|
||||
}
|
||||
}
|
||||
|
||||
// String fills the Stringer interface and returns an ANSI escape code
|
||||
// formatted to produce text in the specified Style.
|
||||
func (s Style) String() string {
|
||||
if s.fg == nil {
|
||||
s.fg = termenv.NoColor{}
|
||||
}
|
||||
if s.bg == nil {
|
||||
s.bg = termenv.NoColor{}
|
||||
}
|
||||
// TODO: Looks like the background color is overriding the foreground color. What's the proper way to do this?
|
||||
return fmt.Sprintf("%s%s;%sm", termenv.CSI, s.fg.Sequence(false), s.bg.Sequence(true))
|
||||
}
|
||||
|
||||
// Scene holds all the necessary information to make a dynamic, weather-y ASCII
|
||||
// landscape.
|
||||
type Scene struct {
|
||||
foreground [][]rune
|
||||
background [][]rune
|
||||
windground [][]rune
|
||||
depth [][]rune
|
||||
forecast Forecast
|
||||
|
||||
generator opensimplex.Noise
|
||||
|
||||
Width int
|
||||
Height int
|
||||
}
|
||||
|
||||
const (
|
||||
fgPath = "foreground.txt"
|
||||
depthPath = "depth.txt"
|
||||
windPath = "wind.txt"
|
||||
|
||||
earlyPath = "early.txt"
|
||||
morningPath = "morning.txt"
|
||||
afternoonPath = "afternoon.txt"
|
||||
nightPath = "night.txt"
|
||||
)
|
||||
|
||||
var timeToPath = []string{
|
||||
earlyPath,
|
||||
morningPath,
|
||||
afternoonPath,
|
||||
nightPath,
|
||||
}
|
||||
|
||||
// NewScene accepts a path to a folder containing foreground, windground,
|
||||
// depth, and background files and loads them from disk as needed to generate
|
||||
// imagery for the given forecast.
|
||||
func NewScene(scenePath string, forecast Forecast) (Scene, error) {
|
||||
var s Scene
|
||||
var err error
|
||||
|
||||
s.forecast = forecast
|
||||
s.generator = opensimplex.NewNormalized(0)
|
||||
|
||||
s.foreground, err = readRunesFromFile(path.Join(scenePath, fgPath))
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
s.depth, err = readRunesFromFile(path.Join(scenePath, depthPath))
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
s.windground, err = readRunesFromFile(path.Join(scenePath, windPath))
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
bgPath := timeToPath[forecast.time]
|
||||
s.background, err = readRunesFromFile(path.Join(scenePath, bgPath))
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
s.normalize()
|
||||
|
||||
/*m.depthData = make([][]uint8, 0)
|
||||
for i := range depthRunes {
|
||||
m.depthData = append(m.depthData, make([]uint8, 0))
|
||||
for j := range depthRunes[i] {
|
||||
m.depthData[i] = append(m.depthData[i], uint8(depthRunes[i][j])-48)
|
||||
}
|
||||
}*/
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// normalize adjusts the foreground, windground, depth map, and background to
|
||||
// have matching widths and heights. It adjusts by cropping to the shortest
|
||||
// number of lines between the four and adjusts each line to the shortest of
|
||||
// any lines in any of the four maps.
|
||||
func (s *Scene) normalize() {
|
||||
scenes := [...][][]rune{s.foreground, s.windground, s.depth, s.background}
|
||||
|
||||
s.Height = 999999999
|
||||
for i := range scenes {
|
||||
if len(scenes[i]) < s.Height {
|
||||
s.Height = len(scenes[i])
|
||||
}
|
||||
}
|
||||
|
||||
for i := range scenes {
|
||||
scenes[i] = scenes[i][:s.Height]
|
||||
}
|
||||
|
||||
s.Width = 999999999
|
||||
for j := 0; j < s.Height; j++ {
|
||||
for i := range scenes {
|
||||
if len(scenes[i][j]) < s.Width {
|
||||
s.Width = len(scenes[i][j])
|
||||
}
|
||||
}
|
||||
|
||||
for i := range scenes {
|
||||
scenes[i][j] = scenes[i][j][:s.Width]
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Change this to a map? Map can be iterated over and still referenced by name.
|
||||
s.foreground = scenes[0]
|
||||
s.windground = scenes[1]
|
||||
s.depth = scenes[2]
|
||||
s.background = scenes[3]
|
||||
}
|
||||
|
||||
func (s Scene) GetCell(x, y, time int) (rune, Style) {
|
||||
fx := float64(x)
|
||||
fy := float64(y)
|
||||
ftime := float64(time)
|
||||
fcloud := float64(s.forecast.cloudiness)
|
||||
fwind := float64(s.forecast.windiness)
|
||||
frain := float64(s.forecast.raininess)
|
||||
|
||||
char := ' '
|
||||
style := Style{
|
||||
termenv.ANSI256Color(255),
|
||||
termenv.ANSI256Color(232),
|
||||
}
|
||||
|
||||
// Out of bounds
|
||||
if y >= s.Height || y < 0 {
|
||||
return char, Style{}
|
||||
}
|
||||
if x >= s.Width || x < 0 {
|
||||
return char, Style{}
|
||||
}
|
||||
|
||||
depth := uint8(s.depth[y][x] - 48)
|
||||
|
||||
// Char selection
|
||||
char = s.foreground[y][x]
|
||||
// Pull from wind map if the current cell is windswept.
|
||||
if fwind > 0.0 && s.generator.Eval3(fx/40+fwind/8*ftime*2, fy/20, ftime/5+fwind/10*ftime/2) > 0.6 {
|
||||
char = s.windground[y][x]
|
||||
}
|
||||
// Depth 9 is considered "transparent," so use the char from the background.
|
||||
if depth == 9 {
|
||||
char = s.background[y][x]
|
||||
}
|
||||
if frain > 0.0 && 0.1+frain/20 > s.generator.Eval3(fx+ftime*fwind*3, fy-ftime*5, ftime/15) {
|
||||
char = '|'
|
||||
if fwind > 1.0 {
|
||||
char = '/'
|
||||
}
|
||||
}
|
||||
|
||||
// Style selection
|
||||
// Calculate fog
|
||||
fog := (depth - 1) + uint8(s.forecast.visibility-1)*2
|
||||
if s.forecast.visibility == 0 {
|
||||
fog = (depth + uint8(s.forecast.visibility)) / 2
|
||||
}
|
||||
// Don't show fog in the sky during the night.
|
||||
if depth == 9 && (s.forecast.time == Night || s.forecast.time == EarlyMorning) {
|
||||
fog = 0
|
||||
}
|
||||
|
||||
// Add clouds
|
||||
cloudiness := 0
|
||||
if depth > 8 && fcloud/5 > s.generator.Eval3(fx/50+ftime/24+ftime*(fwind/8), fy/12, 1000+ftime/80) {
|
||||
cloudiness += 10
|
||||
}
|
||||
if depth > 6 && fcloud/7 > s.generator.Eval3(fx/20+ftime/14+ftime*(fwind/8), fy/6, 0+ftime/80) {
|
||||
cloudiness += 10
|
||||
}
|
||||
|
||||
// At night, fog obscures distant objects with darkness.
|
||||
if s.forecast.time == Night || s.forecast.time == EarlyMorning {
|
||||
style.fg = termenv.ANSI256Color(255 - fog - fog/2)
|
||||
} else {
|
||||
// Merge fog with clouds during daytime.
|
||||
cloudiness += int(fog)
|
||||
}
|
||||
|
||||
if cloudiness > 23 {
|
||||
cloudiness = 23
|
||||
}
|
||||
|
||||
if cloudiness > 0 {
|
||||
style.bg = termenv.ANSI256Color(232 + cloudiness)
|
||||
} else {
|
||||
style.bg = termenv.ANSI256Color(232 + fog)
|
||||
}
|
||||
return char, style
|
||||
}
|
||||
|
||||
// readRunesFromFile reads the file at the given path and reads it character by
|
||||
// character, line by line into a slice of slices of runes.
|
||||
func readRunesFromFile(filepath string) ([][]rune, error) {
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
br := bufio.NewReader(file)
|
||||
img := make([][]rune, 0)
|
||||
img = append(img, make([]rune, 0))
|
||||
|
||||
for {
|
||||
r, s, err := br.ReadRune()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Invalid unicode characters are skipped.
|
||||
if r == unicode.ReplacementChar && s == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Start a new slice on newline, otherwise append character to current slice.
|
||||
if r == '\n' {
|
||||
img = append(img, make([]rune, 0))
|
||||
} else {
|
||||
img[len(img)-1] = append(img[len(img)-1], r)
|
||||
}
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
---___ | __------''''
|
||||
---__ ,.---., __---
|
||||
-__ ;/-'''-\; --'
|
||||
:|' `|:
|
||||
:|. ,|; --__ ___
|
||||
__--- ;\-___-/; ''-- --___
|
||||
'' , `'---'` -----____
|
||||
___---'' / ''
|
||||
'' ' \
|
||||
____-- , \
|
||||
'' /
|
||||
/ \
|
||||
__-- ' \
|
||||
\
|
||||
/
|
||||
/
|
||||
/
|
||||
'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
|
||||
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
|
||||
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999899
|
||||
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999988999999999999988888
|
||||
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999889999999999999999999999999999999998888888888899999888888888888
|
||||
9999999999999999999999999999999999998999999999999999999999999999999999999999999998888888888889999999999999999999999999888888888888888889998888888888888
|
||||
9999999999999999999999999999999999888889999988888888999999988889999998889998888888888888888888888888899999888889999888888888888888888888888888888888888
|
||||
9999999999999999999999999999999998888888888888888888888988888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
|
||||
9999999999999999999999999999998888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888555555555888
|
||||
9999999999999999999999999999988888888888888888888888888888888888888888888888888888888888888888888888855555555555888888888855555555555555555555555555555
|
||||
9999999999999999999999999988888888888888888888888888888888888888888888888888888888888888888888555555555555555555555535555555555555555555555555555555555
|
||||
9999999999999998889999999888888888888888888888888888888888888888888888888888888888888888885555555555555555555555555355555555555555555555555555555555555
|
||||
9999999999999988888899998888888888888888888888888888888888888888888888888888888888888885555555555555555555555555553555555555555555555555555555555555555
|
||||
9999988889999888888888888888888888888888888888888888888888888888888888888888555558888833333333333333333333553333335555555555555555555555555555555555555
|
||||
9888888888888888888888888888888888888888888888888888888888888888888888855555555555555333333333333333333333355555533555555555555555555555555555555555555
|
||||
8888888888888888888888888888888888888555555558888888888888555555555555555555555555533333333333333333333333335555535355555555555555533333333333333333333
|
||||
8888888888888888888888555588885555555555555555555555555555555555555555555555555555333333333333333333333333344444434434444444333333333333333333333333333
|
||||
8888888888888888855555555555555555555555555555555555555555555555555555555555555444433333333333333333333333344444434444444433333333333333333333333333333
|
||||
8888888855555555555555555555555555555555555555555555544444444444444444444444444444433333333333333333333333344433333333333333333333333333333333333333333
|
||||
5555555555555555555555555555555555555555555544444444444444443333333333333333333333333333333333333333333333333333333333333333333333333111111111111111111
|
||||
5555555555555555555555555555555555544444444444444444444444333333333333333333333333333333333333333333333333333333333333331111111111111111111111111111111
|
||||
5555555555555555544444444444444444444444444444444444443333333333333333333333333333333333333333333333333333333311111111111111111111111111111111111111111
|
||||
4444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333331111111111111111111111111111111111111111111111
|
||||
3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333111111111111111111111111111111111111111111111111
|
||||
3333333333333333333333333333333333333333333333333333333333333333333333333333333333332222222222222221111111111111111111111111111111111111111111111111111
|
||||
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222111111111111111111111111111111111111111111111111111111111111
|
||||
2222222222222222222222222222222222221212222222222222222222222222222222222211111111111111111111111111111111111111111111111111111111111111111111111111111
|
||||
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
||||
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
||||
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
||||
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
|
|
@ -0,0 +1,31 @@
|
|||
. *
|
||||
` * . `
|
||||
* ` .: TWA. *
|
||||
* . . / 0 Vm *
|
||||
, . 'B .
|
||||
* * * |' D
|
||||
` '| O P
|
||||
\\
|
||||
. ' `=____-'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
|
||||
.
|
||||
__ ./ \.
|
||||
__ ___.--'' \ _.--'\/
|
||||
. ___,.-" '-, _--'' \ / /
|
||||
./ \. /''\_.-. _-". .-. __.--'" '--.____ ___.. _-' '-/
|
||||
/ \_.-' \-. ,-" \_-""" \-" "---' \--"
|
||||
__/ ' ,----.___
|
||||
/ _._________ _______..------'' ''-
|
||||
.-' _.--''' ''--/-''''
|
||||
.__ / _-'` /
|
||||
/ '- / .-' __ /
|
||||
__.. / '--" _.--. /-----""----,-,_____ -----O '
|
||||
_.-' '--' __.-' `-__//-\___-' .' _ '. \ |\ '
|
||||
' _,-.,___ ____,,,,..../ ,-'|+|,- .' |+| '-,-" | \
|
||||
____ ,.----" \___,----''`` -,-- ---| | | \ .=
|
||||
..--' '--/ . - | == == | _ _ | |
|
||||
.--.___.' __ | === | |+| |+| | | '
|
||||
-'-.___/ ' _ - _ _ __ ___ __|__|||___|_____________|___ _|_ _
|
||||
' .- - '
|
||||
' -' - '
|
||||
' .
|
||||
_ . - - " ' && '
|
||||
' _..= - '
|
||||
' _.' - '
|
||||
' ' * * ' ' '
|
||||
*|*|* @&& , &&
|
||||
' &&&@& ' '
|
||||
' '
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
'--__ | __------
|
||||
--__ ,.---., __---
|
||||
-__ ;/-'''-\; --'
|
||||
:|' `|:
|
||||
:|. ,|; --__ ___
|
||||
;\-___-/; ''-- ____
|
||||
, `'---'` '----_____
|
||||
/ -------____
|
||||
' \ ____
|
||||
, \ '''--------
|
||||
/
|
||||
/ \
|
||||
/ \
|
||||
' \
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
. *
|
||||
` * . `
|
||||
* .: TWA. ` *
|
||||
/ 0 Vm * . . *
|
||||
, . 'B * .
|
||||
|' D * * *
|
||||
'| O P
|
||||
\\
|
||||
. `=____-' '
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
|
||||
.
|
||||
__ ./ \.
|
||||
__ ___.--'' \ _.--'\/
|
||||
. ___,.-" '-, _--'' \ / /
|
||||
./ \. /''\_.-. _-". .-. __.--'" '--.____ ___.. _-' '-/
|
||||
/ \_.-' \-. ,-" \_-""" \-" "---' \--"
|
||||
__/ ' ,----.___
|
||||
/ _._________ _______..------'' ''-
|
||||
.-' _.--''' ''--/-''''
|
||||
.__ / _-'` /
|
||||
/ '- / .-' __ /
|
||||
__.. / '--" _.--. /-----""----,-,_____ -----O `
|
||||
_.-' '--' __.-' `-__//-\___-' .' _ '. \ |\ `
|
||||
' _,-.,___ ____,,,,..../ ,-'|+|,- .' |+| '-,-" | \
|
||||
____ ,.----" \___,----''`` -,-- ---| | | \ .=
|
||||
..--' '--/ . - | == == | _ _ | |
|
||||
.--.___.' __ | === | |+| |+| | | `
|
||||
-'-.___/ ` _ - _ _ __ ___ __|__|||___|_____________|___ _|_ _
|
||||
` .- - '
|
||||
` -' - '
|
||||
' .
|
||||
_ . - - " ` && '
|
||||
' _..= - `
|
||||
' _.` - '
|
||||
` ` + + ` ` `
|
||||
+|+|+ @&& , &&
|
||||
' &&&@& ` `
|
||||
` `
|
||||
|
Loading…
Reference in New Issue