Changed . token to _dot

This change allows the dotfiles to work with chezmoi (e.g: on windows)
and improves grepability with neovim/telescope
This commit is contained in:
2024-11-07 13:52:17 +00:00
parent 83b02bd753
commit 896af887ca
2351 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,230 @@
# Modules
- [Modules](#modules)
- [after](#after)
- [api\_wrappers](#api_wrappers)
- [background\_task](#background_task)
- [base16](#base16)
- [coloring](#coloring)
- [data\_extraction](#data_extraction)
- [docker](#docker)
- [filesystem](#filesystem)
- [formats](#formats)
- [fun](#fun)
- [github](#github)
- [gitlab](#gitlab)
- [jc](#jc)
- [kubernetes](#kubernetes)
- [make\_release](#make_release)
- [maths](#maths)
- [network](#network)
- [nvim](#nvim)
- [progress\_bar](#progress_bar)
- [rbenv](#rbenv)
- [record](#record)
- [system](#system)
- [virtual\_environments](#virtual_environments)
- [weather](#weather)
- [webscraping](#webscraping)
## [after](./after)
Run a function after the given program (by PID)
## api_wrappers
Demo of various API wrappers:
- [Wolfram Alpha](../sourced/api_wrappers/wolframalpha.nu)
- [AWS]()
## background_task
make nushell "support" background task feature.
see [README](./background_task/)
## base16
Base16 theme generator (for Linux, might work for other OS)
see [README](./base16/)
## coloring
These scripts are used to demonstrate the `ansi` command using `ansi` coloring. This is mainly a demo area where we have taken typical `bash` scripts and ported them to nushell scripts. It would be nice if all scripts here showed the "other" version of script and the ported nushell version. We can show "other" flavors of scripts by including them as comments in the nushell scripts or by naming the nushell script and the other script the same basename.
## data_extraction
- [Ultimate Extractor](./data_extraction/ultimate_extractor.nu) - Extract any compressed archive, UE will call the proper program under the hood 😎
## [docker](./docker/)
An extensive example of a wrapper for docker operations, with nushell completions.
## filesystem
- [bm](./filesystem/bm.nu) - A Simple bookmarking module. It uses `XGD_DATA_HOME` to save bookmarks.
- [expand](./filesystem/expand.nu) - expansion module that implements bashes brace expansion.
The expansion uses a list inside of braces separated by `,` to expand into a list of multiple string variations like:
```
expand a/{b,c}/d{e,f,g}.nu{,on}
```
parses into:
```
╭────┬─────────────╮
│ 0 │ a/b/de.nu │
│ 1 │ a/c/de.nu │
│ 2 │ a/b/df.nu │
│ 3 │ a/c/df.nu │
│ 4 │ a/b/dg.nu │
│ 5 │ a/c/dg.nu │
│ 6 │ a/b/de.nuon │
│ 7 │ a/c/de.nuon │
│ 8 │ a/b/df.nuon │
│ 9 │ a/c/df.nuon │
│ 10 │ a/b/dg.nuon │
│ 11 │ a/c/dg.nuon │
╰────┴─────────────╯
```
## formats
Examples of input/output formatters:
- [from-cpuinfo](./formats/from-cpuinfo.nu)
- [from-dmidecode](./formats/from-dmidecode.nu)
- [to-ini](./formats/to-ini.nu)
- [remove-diacritics](./formats/remove-diacritics.nu) - Turns `Zażółć gęślą jaźń` into `Zazolc gesla jazn`
## fun
- [spark](../sourced/fun/spark.nu) - send an array into spark and get a sparkline out:
```console
> let v = [2, 250, 670, 890, 2, 430, 11, 908, 123, 57]
> spark $v
▁▂▆▇▁▄▁█▁▁
```
- [website-builder](../sourced/fun/website_builder.nu) - converts markdown into their equivalent html pages
- [wordle](./fun/wordle.nu) - A Terminal Wordle game. The code is based on this [gist](https://gist.github.com/huytd/6a1a6a7b34a0d0abcac00b47e3d01513), but slightly personalized.
## github
- [branch-protections](../sourced/github/branch-protections/) - Do you have hundreds or thousands of GitHub repositories in your organization? Are you tired of manually managing their branch protection rules? Don't! Let nushell do it for you! see [README](../sourced/github/branch-protections/README.md)
- [merged-branches](../sourced/github/merged-branches/) - Do your developers often forget to delete their branches after merging PRs? Are you tired of manually going into every repository and deleting them? Don't! Let nushell do it for you! see [README](../sourced/github/merged-branches/README.md)
## [gitlab](../sourced/gitlab/)
Search files on your GitLab server
## [jc](./jc/)
Converts the output of many common external commands into nushell data structures.
Example:
```nushell
: jc ping -4 -c 2 google.com
╭──────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────╮
│ destination_ip │ 216.58.209.46 │
│ data_bytes │ 56 │
│ pattern │ │
│ destination │ google.com │
│ duplicates │ 0 │
│ packets_transmitted │ 2 │
│ packets_received │ 2 │
│ packet_loss_percent │ 0.00 │
│ time_ms │ 1001.00 │
│ round_trip_ms_min │ 3.87 │
│ round_trip_ms_avg │ 4.04 │
│ round_trip_ms_max │ 4.21 │
│ round_trip_ms_stddev │ 0.17 │
│ │ ╭───┬───────┬───────────┬───────┬───────────────┬──────────┬─────┬─────────┬───────────╮ │
│ responses │ │ # │ type │ timestamp │ bytes │ response_ip │ icmp_seq │ ttl │ time_ms │ duplicate │ │
│ │ ├───┼───────┼───────────┼───────┼───────────────┼──────────┼─────┼─────────┼───────────┤ │
│ │ │ 0 │ reply │ │ 64 │ 216.58.209.46 │ 1 │ 120 │ 4.21 │ false │ │
│ │ │ 1 │ reply │ │ 64 │ 216.58.209.46 │ 2 │ 120 │ 3.87 │ false │ │
│ │ ╰───┴───────┴───────────┴───────┴───────────────┴──────────┴─────┴─────────┴───────────╯ │
╰──────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────╯
```
```nushell
: (jc ping -4 -c 2 google.com).round_trip_ms_avg
6.054
```
For supported commands see [JC parsers documentation](https://kellyjonbrazil.github.io/jc/#parsers)
Installation:
1. Install the `jc` command line: https://kellyjonbrazil.github.io/jc/#installation
2. Import this module in your `config.nu`: `import ~/.local/share/nu_scripts/modules/jc/`
## [kubernetes](./kubernetes/)
???
## [make_release](../make_release/)
???
## [maths](./maths/)
- [math_functions] - module with the following commands:
- `root` - root with a custom denominator
- `croot` - cube root
- `aroot` - root with a custom scaler and denominator
- `delta` - calculate the delta of the quadratic function
- `fact` - factorial of the given number
- `q_roots` - calculare roots of the quadratic function: ax^2+bx+x
- `isprime` - check if integer is prime
- `primelist` - list primes until given number
- `mtable` - multiplication table of n till max
- `isleap` - check if year is leap
- `gcd` - greatest common divisor between 2 integers
- `lcm` - least commoin multiple between 2 integers
- `dec2base` - decimal number to custom base representation
- `scale-minmax` - scale list to `[a,b]` interval
- `scale-minmax-table` - Scale every column of a table (separately) to `[a,b]` interval
- `math exp` - exp function
## network
- [remoting](./network/remoting/) - This module provide convenient way to manage multiple remote clients. see [README](./network/remoting)
- [sockets](./network/sockets/) - The `sockets` command returns a table containing information on network sockets and the processes they belong to.
It is basically a join of the tables produced by the `lsof` command, and the nushell `ps` command.
<img width="1486" alt="image" src="https://user-images.githubusercontent.com/52205/196287615-00e46f8e-06ed-45ce-8fe7-a5c5f38afaaa.png">
- [ssh](./network/ssh.nu) wrapper that provides the following commands:
- `ssh`
- `scp`
- `ssh-list`
- `parse-ssh-file`
- `str max-length`
- `ensure-index`
## [nvim](./nvim/)
??? (not sure how universal this is) Mix of hooks, defs and alias wrapper around neovim.
## [progress_bar](../sourced/progress_bar/)
??? (make a module out of these scripts?) - Collection of progress bars
## [rbenv](./rbenv/)
??? (not sure how universal this is) This script provides minimal working rbenv setup.
## [record](../stdlib-candidate/record/)
A module to manipulate nu's record
## [system](./system/)
Currently holds the `clip` command which was previously incorrectly in the standard library of Nushell.
```nushell
use modules/system * # will bring `clip` into scope
```
## [virtual_environments](./virtual_environments/)
The scripts in this directory activate virtual environments for Conda environments.
## [weather](./weather/)
These scripts should be used to demonstrate how get your local weather and/or weather forecasts.
## [webscraping](../sourced/webscraping/)
Simple scripts to demonstrate how to scrape websites in nushell. Requires `query web` plugin

View File

@@ -0,0 +1,21 @@
def "nu-complete ps" [] {
ps -l | each {|x| { value: $"($x.pid)", description: $x.command } }
}
# after <pid> {|| do something ... }
export def main [
pid: string@"nu-complete ps"
action
] {
do -i { tail --pid $pid -f /dev/null }
do $action
}
# before {|| do something ... } <pid>
export def before [
action
pid: string@"nu-complete ps"
] {
do -i { tail --pid $pid -f /dev/null }
do $action
}

View File

@@ -0,0 +1,127 @@
export def get-sign [cmd] {
let x = (scope commands | where name == $cmd).signatures?.0?.any?
mut s = []
mut n = {}
mut p = []
mut pr = []
mut r = []
for it in $x {
if $it.parameter_type == 'switch' {
if ($it.short_flag | is-not-empty) {
$s ++= $it.short_flag
}
if ($it.parameter_name | is-not-empty) {
$s ++= $it.parameter_name
}
} else if $it.parameter_type == 'named' {
if ($it.parameter_name | is-empty) {
$n = ($n | upsert $it.short_flag $it.short_flag)
} else if ($it.short_flag | is-empty) {
$n = ($n | upsert $it.parameter_name $it.parameter_name)
} else {
$n = ($n | upsert $it.short_flag $it.parameter_name)
}
} else if $it.parameter_type == 'positional' {
if $it.is_optional == false {
$p ++= $it.parameter_name
} else {
$pr ++= $it.parameter_name
}
} else if $it.parameter_type == 'rest' {
$r ++= $it.parameter_name
}
}
{ switch: $s, name: $n, positional: ($p ++ $pr), rest: $r }
}
# "test -h [123 (3213 3)] 123 `a sdf` --cd --ef sadf -g" | token
export def token [] {
let s = ($in | split row '' | range 1..-2)
let s = if ($s | last) == ' ' { $s } else { $s | append ' ' }
mut par = []
mut res = []
mut cur = ''
mut esc = false
for c in $s {
if $c == '\' {
$esc = true
} else {
if $esc {
$cur ++= $c
$esc = false
} else {
if $c == ' ' and ($par | length) == 0 {
$res ++= [$cur]
$cur = ''
} else {
if $c in ['{' '[' '('] {
$par ++= $c
}
if $c in ['}' ']' ')'] {
$par = ($par | range ..-2)
}
if $c in ['"' "'" '`'] {
if ($par | length) > 0 and ($par | last) == $c {
$par = ($par | range ..-2)
} else {
$par ++= $c
}
}
$cur ++= $c
}
}
}
}
return $res
}
export def parse [] {
let token = ($in | token)
let sign = (get-sign $token.0)
mut sw = ''
mut pos = []
mut opt = {}
for c in $token {
if ($sw | is-empty) {
if ($c | str starts-with '-') {
let c = if ($c | str substring 1..<2) != '-' {
let k = ($c | str substring 1..)
if $k in $sign.name {
$'($sign.name | get $k)'
} else {
$k
}
} else {
$c | str substring 2..
}
if $c in $sign.switch {
$opt = ($opt | upsert $c true)
} else {
$sw = $c
}
} else {
$pos ++= [$c]
}
} else {
$opt = ($opt | upsert $sw $c)
$sw = ''
}
}
$opt._args = $pos
let p = $pos | range 1..($sign.positional | length)
let rest = $pos | range (($sign.positional | length) + 1)..-1
$opt._pos = ( $p | enumerate
| reduce -f {} {|it, acc|
$acc | upsert ($sign.positional | get $it.index) $it.item
} )
if ($sign.rest | length) > 0 {
$opt._pos = ($opt._pos | upsert $sign.rest.0 $rest)
}
$opt
}
# def test [a b x? ...y --cd(-c) --ef(-e):string -g -h:int --ij --lm:bool] {}
# (scope commands | where name == test).signatures?.0?.any?
# get-sign test | to yaml
# "test -h 111 123 'asdf' --cd --ef sadf -g -h 222" | cmd parse | to yaml

View File

@@ -0,0 +1,45 @@
# This alias lets you choose your aws environment variables with ease.
#
# Dependencies:
# * fzf
#
# Installation:
# 1. store in ~/.config/nushell/select-aws-profile.nu
# 2. add to your config.nu: `use ~/.config/nushell/select-aws-profile.nu *`
#
# Usage:
# select-aws-profile
export def --env main [] {
hide AWS_REGION
do {
let creds = open ($env.HOME + "/.aws/credentials") | from toml
let selected_profile = $creds
| transpose name creds
| get name
| str join "\n"
| fzf
if $selected_profile != "" {
let out = {
AWS_PROFILE: $selected_profile,
AWS_ACCESS_KEY_ID: ($creds | get $selected_profile | get "aws_access_key_id"),
AWS_SECRET_ACCESS_KEY: ($creds | get $selected_profile | get "aws_secret_access_key"),
}
let region = ($creds | get $selected_profile | get -i "region")
if $region != null {
$out | insert AWS_REGION $region
} else {
$out
}
}
} | load-env
{
AWS_PROFILE: $env.AWS_PROFILE,
AWS_ACCESS_KEY_ID: $env.AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY: $env.AWS_SECRET_ACCESS_KEY,
AWS_REGION: $env.AWS_REGION
}
}

View File

@@ -0,0 +1,68 @@
# Background tasks with pueue
Makes Nushell "support" background tasks.
## Prerequisite
Install [pueue](https://github.com/Nukesor/pueue) and make sure `pueued` is running and that `pueue` is in `PATH`.
## Usage
You will get tab completions and suggestions when you install the module.
Please check those.
To install the module, copy the `task.nu` to the `$env.NU_LIB_DIRS` directory, then do:
```nu
use task.nu
```
In your Nushell config under `~/.config/nushell`.
## Q&A
### How can I pass data to a background task?
You can use environment variables, since they
are inherited from the parent when spawning a process.
```nu
$env.FOO = 123
task spawn {
echo $env.FOO
}
```
If you want to pass serialized data, you can do this:
```nu
let foo = { a: 1 b: 2 c: 3 }
with-env { FOO: ($foo | to json) } {
task spawn {
let foo = ($env.FOO | from json)
echo $foo
}
}
```
### How can I reuse custom commands in a background task?
You can define these commands in a separate module, like so:
```nu
# --- in foo.nu ---
export def bar [] { echo bar }
# --- in main.nu ---
task spawn {
use foo.nu
foo bar
}
```
## Troubleshooting
- On some setups (e.g. NixOS with `nu` installed as a binary in user's `$HOME`), `sh` (which `pueue` delegates tasks to run) might fail to find `nu` in the `$PATH`. In this case hard-coding the location of your nu binary in the `task spawn` function definition in `task.nu` can solve the issue.

View File

@@ -0,0 +1,434 @@
# Spawn a task to run in the background, even when the shell is closed.
#
# Note that a fresh Nushell interpreter is spawned to execute the
# given task, so it won't inherit the current scope's variables,
# custom commands and alias definitions.
#
# It will only inherit environment variables which can be converted to a string.
#
# Note that the closure can't take arguments.
#
# Example usage: task spawn { echo "Hello, World!" }
export def spawn [
command: closure # The closure to run.
--working-directory (-w): directory # Specify the working directory the task will be run in.
--immediate (-i) # Immediately start the task.
--stashed (-s) # Create the task in Stashed state. Useful to avoid immediate execution if the queue is empty
--delay (-d): duration # Queue the task for execution only after the duration.
--group (-g): string # The group to spawn the task under.
--after (-a): int # Start the task once all specified tasks have successfully finished. As soon as one of the dependencies fails, this task will fail as well.
--priority (-o): string # Start this task with a higher priority. The higher the number, the faster it will be processed.
--label (-l): string # Label the task. This string will be shown in the `status` column of `task status`.
] -> int {
mut args = []
if $working_directory != null {
$args = ($args | prepend ["--working-directory", $working_directory])
}
if $immediate {
$args = ($args | prepend "--immediate")
}
if $stashed {
$args = ($args | prepend "--stashed")
}
if $delay != null {
$args = ($args | prepend ["--delay" ($delay | format duration sec | parse "{secs} {_}" | get 0.secs)])
}
if $group != null {
$args = ($args | prepend ["--group" $group])
}
if $after != null {
$args = ($args | prepend ["--after" $after])
}
if $priority != null {
$args = ($args | prepend ["--priority" $priority])
}
if $label != null {
$args = ($args | prepend ["--label" $label])
}
let source_path = mktemp --tmpdir --suffix "-nu-task"
(
view source $command
| str trim --left --char "{"
| str trim --right --char "}"
)
| save --force $source_path
(pueue add --print-task-id ...$args $"nu --config '($nu.config-path)' --env-config '($nu.env-path)' ($source_path)")
}
# Remove tasks from the queue.
# Running or paused tasks need to be killed first.
export def remove [
...ids: int # IDs of the tasks to remove from the status list.
] {
pueue remove ...$ids
}
# Switches the queue position of two tasks.
# Only works for queued or stashed tasks.
export def switch [
task_id_1: int # The first task ID.
task_id_2: int # The second task ID.
] {
pueue switch $task_id_1 $task_id_2
}
# Stash a task that is not currently running.
#
# Stashed tasks won't be automatically started.
# You will have to queue them or start them by hand.
export def stash [
...ids: int # IDs of the tasks to stash.
] {
pueue stash ...$ids
}
# Queue stashed tasks for execution.
export def queue [
...ids: int # IDs of the tasks to queue.
--delay (-d): duration # Queue only after the specified delay.
] {
let args = if $delay != null {
["--delay" ($delay | format duration sec | parse '{secs} {_}' | get 0.secs)]
} else {
[]
}
pueue enqueue ...$args ...$ids
}
# Resume operation of specific tasks or groups of tasks.
#
# By default, this resumes the default group and all its tasks.
# It can also be used force-start specific tasks or start whole groups.
export def start [
...ids: int # IDs of the tasks to start. By default all the tasks in the default group will be started.
--group (-g): string # Resume a specific group and all paused tasks in it. The group will be set to running and its paused tasks will be resumed.
--all (-a) # Resume all groups. All groups will be set to running and paused tasks will be resumed.
] {
mut args = []
if $group != null {
$args = ($args | prepend ["--group" $group])
}
if $all {
$args = ($args | prepend "--all")
}
pueue start ...$args
}
# Restart failed or successful task(s).
#
# By default, identical tasks will be created and
# enqueued, but it's possible to restart in-place.
#
# You can also edit a few properties, such as
# the path and the command of the task, before restarting.
export def restart [
...ids: int # IDs of the tasks to restart.
--all-failed (-a) # Restart all failed tasks across all groups. Nice to use in combination with `--in-place/i`.
--failed-in-group (-g): string # Like `--all-failed`, but only restart tasks failed tasks of a specific group. The group will be set to running and its paused tasks will be resumed.
--start-immediately (-k) # Immediately start the tasks, no matter how many open slots there are. This will ignore any dependencies tasks may have.
--stashed (-s) # Set the restarted task to a "Stashed" state. Useful to avoid immediate execution.
--in-place (-i) # Restart the tasks by reusing the already existing tasks.
--not-in-place (-n) # Opposite of `--in-place`. This is already the default unless you have `restart_in_place` set to true.
--edit (-e) # Edit the tasks' commands before restarting
--edit-path (-p) # Edit the tasks' paths before restarting
--edit-label (-l) # Edit the tasks' labels before restarting
] {
mut args = []
if $all_failed {
$args = ($args | prepend "--all-failed")
}
if $failed_in_group != null {
$args = ($args | prepend "--failed-in-group")
}
if $start_immediately {
$args = ($args | prepend "--start-immediately")
}
if $stashed {
$args = ($args | prepend "--stashed")
}
if $in_place {
$args = ($args | prepend "--in-place")
}
if $not_in_place {
$args = ($args | prepend "--not-in-place")
}
if $edit {
$args = ($args | prepend "--edit")
}
if $edit_path {
$args = ($args | prepend "--edit-path")
}
if $edit_label {
$args = ($args | prepend "--edit-label")
}
pueue restart ...$args ...$ids
}
# Either pause a running tasks or a specific groups of tasks.
#
# By default, pauses the default group and all its tasks.
#
# A paused group won't start any new tasks automatically.
export def pause [
...ids: int # IDs of the tasks to pause.
--group (-g) # Pause a specific group
--all (-a) # Pause all groups.
--wait (-w) # Only pause the specified group and let already running tasks finish by themselves
] {
mut args = []
if $group != null {
$args = ($args | prepend "--group")
}
if $all != null {
$args = ($args | prepend "--all")
}
if $wait != null {
$args = ($args | prepend "--wait")
}
pueue pause ...$args ...$ids
}
# Kill specific running tasks or whole task groups.
#
# Kills all tasks of the default group when no ids or a specific group are provided.
export def kill [
...ids: int # IDs of the tasks to kill.
--group (-g): string # Kill all running tasks in a group. This also pauses the group.
--all (-a) # Kill all running tasks across ALL groups. This also pauses all groups.
--signal (-s): string # Send a UNIX signal instead of simply killing the process. DISCLAIMER: This bypasses Pueue's process handling logic! You might enter weird invalid states, use at your own descretion.
] {
mut args = []
if $group != null {
$args = ($args | prepend ["--group" $group])
}
if $all {
$args = ($args | prepend "--all")
}
if $signal != null {
$args = ($args | prepend ["--signal" $signal])
}
pueue kill ...$args ...$ids
}
# Send something to a task. Useful for sending confirmations such as "y\n".
export def send [
id: int # ID of the task to send something to.
input: string # The input that should be sent to the process.
] {
pueue send $id $input
}
# Edit the command, path or label of a stashed or queued task.
#
# By default only the command is edited.
#
# Multiple properties can be added in one go.
export def edit [
id: int # ID of the task to edit.
--command (-c) # Edit the task's command
--path (-p) # Edit the task's path
--label (-l) # Edit the task's label
] {
mut args = []
if $command {
$args = ($args | prepend "--command")
}
if $path {
$args = ($args | prepend "--path")
}
if $label {
$args = ($args | prepend "--label")
}
pueue edit ...$args $id
}
# Use this to add or remove groups.
#
# By default, this will simply display all known groups.
export def group [] {
pueue group --json | from json
}
# Create a new group with a name.
export def "group add" [
name: string # The name of the new group.
--parallel (-p): int # The amount of parallel tasks the group can run at one time.
] {
let args = if $parallel != null {
["--parallel" $parallel]
} else {
[]
}
pueue group add ...$args $name
}
# Remove a group with a name.
export def "group remove" [
name: string # The name of the group to be removed.
] {
pueue group remove $name
}
# Display the current status of all tasks.
export def status [
--detailed (-d) # Return a table with more detailed information.
] {
let output = (
pueue status --json
| from json
| get tasks
| transpose --ignore-titles status
| flatten
)
# TODO: Rename the Done column to done.
if not $detailed {
$output | select id label group Done? status? start? end?
} else {
$output
}
}
# Display the output of tasks.
#
# Only the last few lines will be shown by default for multiple tasks.
# If you want to follow the output, use `--tail/-t`.
export def log [
...ids: int # The tasks to check the outputs of.
--last (-l): int # Only print the last N lines of each task's output. This is done by default if you're looking at multiple tasks.
--tail (-t) # Follow the output as it is printing. Only works with 1 task. When used in conjunction with `--last`, the last N lines will be printed before starting to wait for output.
--detailed (-d) # Include all fields, don't simplify output.
] {
def process_raw [raw: string] {
let full = (
$raw
| from json
| transpose -i info
| flatten --all
| flatten --all
)
if $detailed {
$full
} else {
$full | select id label group Done? status? start? end?
}
}
if (($ids | length) == 1) {
if $tail {
let args = if $last != null {
["--lines" $last]
} else {
[]
}
pueue follow ...$ids
} else {
let args = if $last != null {
["--lines" $last]
} else {
[]
}
process_raw (pueue log --full --json ...$args ...$ids)
| first
}
} else {
if $tail {
echo $"(ansi red)--tail can only be used with one task.(ansi reset)"
return
}
let args = if $last != null {
["--lines" $last]
} else {
[]
}
process_raw (pueue log --full --json ...$args ...$ids)
}
}
# Wait until the provided tasks are finished.
#
# This is like join() or await in many languages.
export def wait [
...ids: int # IDs of the tasks to wait for.
--group (-g): string # Wait for all tasks in a specific group.
--all (-a) # Wait for all tasks across all groups and the default group.
--quiet (-q) # Don't show any log output while waiting.
--status (-s): string # Wait for tasks to reach a specific task status.
] {
mut args = []
if $group != null {
$args = ($args | prepend ["--group" $group])
}
if $all {
$args = ($args | prepend $all)
}
if $quiet {
$args = ($args | prepend $quiet)
}
if $status != null {
$args = ($args | prepend ["--status" $status])
}
pueue wait ...$args ...$ids
}
# Remove tasks from the status list.
export def clean [
--successful-only (-s) # Only clean tasks that finished successfully
--group (-g): string # Only clean tasks of a specific group
] {
mut args = []
if $successful_only {
$args = ($args | prepend "--successful-only")
}
if $group != null {
$args = ($args | prepend ["--group" $group])
}
pueue clean ...$args
}
# Shutdown pueue and thus this module.
export def shutdown [] {
pueue shutdown
}
# Set the maximum parallel tasks for a group.
#
# Note that no tasks will be stopped if the number is lowered.
# The limit only applies when schelduing.
export def set-parallel-limit [
max: int # The maximum parallel tasks allowed for a group when schelduing.
--group (-g): string # The group to set the limit for. By default this is `default`.
] {
let args = if $group != null {
["--group" $group]
} else {
[]
}
pueue parallel ...$args $max
}

View File

@@ -0,0 +1,48 @@
# Base16 themes integration
This folder contains a couple of files that let you configure Nushell and other terminal tools to use base16 themes.
## Requirements
Assumes a Linux system with an X-based window manager.
Specific packages and environment variable requirements are listed in each file.
## Files explanation
* **base16.nu** - Main module -- see comments inside
* **auto_base16.nu** - Generates a base16 theme from a wallpaper
* **alacritty_colors.template** - Template for Alacritty terminal colors
## Example integration
Fist, set up base16 theme generation from a wallpaper:
```
# ~/.xinitrc
...
[ -f ~/.auto_base16.nu ] && ~/.auto_base16.nu &
```
This will generate a base16 theme to a file from a current wallpaper.
You can combine this with a random wallpaper generation using the fehbg.nu
script for more chaos fun.
Next, set up Nushell config, assuming the base16 colors are generated
```
# config.nu
use ~/.config/nushell/base16.nu
# File containing base16 colors
$env.BASE16_TXT = "/tmp/base16.txt"
let config = {
color_config: (base16 build-nu-config $env.BASE16_TXT)
}
```
To select a new wallpaper and regenerate the base16 config:
```
> base16 new-wallpaper
> source ~/.config/nushell/config.nu
```

View File

@@ -0,0 +1,52 @@
# Base16 template for Alacritty, 256 colors
#
# Adapted from :
# github.com/aarowill/base16-alacritty/blob/master/templates/default-256.mustache
#
# The "{{baseXX-hex}}" strings will be replaced with a Nushell script and saved
# as ~/.config/alacritty/alacritty_colors.yml. The main config (alacritty.yml)
# should be configured to load the generated file.
#
# I'm setting only the background and the foreground but in the comments is the
# full config for reference.
colors:
# Default colors
primary:
background: '{{base00-hex}}'
foreground: '{{base05-hex}}'
# Colors the cursor will use if `custom_cursor_colors` is true
# cursor:
# text: '{{base00-hex}}'
# cursor: '{{base05-hex}}'
# Normal colors
# normal:
# black: '{{base00-hex}}'
# red: '{{base08-hex}}'
# green: '{{base0b-hex}}'
# yellow: '{{base0a-hex}}'
# blue: '{{base0d-hex}}'
# magenta: '{{base0e-hex}}'
# cyan: '{{base0c-hex}}'
# white: '{{base05-hex}}'
# Bright colors
# bright:
# black: '{{base03-hex}}'
# red: '{{base08-hex}}'
# green: '{{base0b-hex}}'
# yellow: '{{base0a-hex}}'
# blue: '{{base0d-hex}}'
# magenta: '{{base0e-hex}}'
# cyan: '{{base0c-hex}}'
# white: '{{base07-hex}}'
# indexed_colors:
# - { index: 16, color: '{{base09-hex}}' }
# - { index: 17, color: '{{base0f-hex}}' }
# - { index: 18, color: '{{base01-hex}}' }
# - { index: 19, color: '{{base02-hex}}' }
# - { index: 20, color: '{{base04-hex}}' }
# - { index: 21, color: '{{base06-hex}}' }

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env engine-q
#
# ~/.auto_base16.nu
#
# This is a wrapper around fehbg.nu that on top of setting a random wallpaper
# also generates a base16 theme from it.
#
# This script is intended to run on desktop startup, e.g., by calling it in
# ~/.xinitrc.
#
# Requirements:
# 1. go, Python 3, fehbg.nu
# 2. Install schemer2 from https://github.com/makuto/auto-base16-theme and put
# it into your PATH
# 3. Expected environment variables:
# * WALLPAPER_IMG - The wallpaper used for generating the base16 scheme
# * BASE16_TXT - Target file to store the generated base16 scheme
# 4. Both this script and fehbg.nu are expected to be in the home directory as
# '~/.auto_base16.nu' and '~/.fehbg.nu'.
schemer2 -format img::colors -in $env.WALLPAPER_IMG -out $env.BASE16_TXT

View File

@@ -0,0 +1,150 @@
# Build a color config for engine-q based on generated base16 file
#
# The input file is supposed to have 16 lines, each base16 colors on a separate
# line like this:
#
# ```
# #base00-hex
# #base01-hex
# ...etc.
# #base0f-hex
# ```
export def build-nu-config [base_txt: path] {
let b16 = (from-file $base_txt)
{
separator: $b16.base03
leading_trailing_space_bg: $b16.base04
header: $b16.base0b
date: $b16.base0e
filesize: $b16.base0d
row_index: $b16.base0c
bool: $b16.base08
int: $b16.base0b
duration: $b16.base08
range: $b16.base08
float: $b16.base08
string: $b16.base04
nothing: $b16.base08
binary: $b16.base08
cellpath: $b16.base08
hints: dark_gray
# base16 white on red
flatshape_garbage: { fg: $b16.base07 bg: $b16.base08 attr: b}
# if you like the regular white on red for parse errors:
# flatshape_garbage: { fg: "#FFFFFF" bg: "#FF0000" attr: b}
flatshape_bool: $b16.base0d
flatshape_int: { fg: $b16.base0e attr: b}
flatshape_float: { fg: $b16.base0e attr: b}
flatshape_range: { fg: $b16.base0a attr: b}
flatshape_internalcall: { fg: $b16.base0c attr: b}
flatshape_external: $b16.base0c
flatshape_externalarg: { fg: $b16.base0b attr: b}
flatshape_literal: $b16.base0d
flatshape_operator: $b16.base0a
flatshape_signature: { fg: $b16.base0b attr: b}
flatshape_string: $b16.base0b
flatshape_filepath: $b16.base0d
flatshape_globpattern: { fg: $b16.base0d attr: b}
flatshape_variable: $b16.base0e
flatshape_flag: { fg: $b16.base0d attr: b}
flatshape_custom: {attr: b}
}
}
# Generate Alacritty color config to be included in the main Alacritty config
#
# It injects the base16 colors into the Alacritty config template
export def build-alacritty-config [base_txt: path] {
let base16 = (from-file-table $base_txt)
let template = (
open "~/.config/nushell/alacritty_colors.mustache" |
decode utf-8
)
# TODO: need a save command:
# | save --raw "~/.config/alacritty/alacritty_colors.yml"
let conf = ($base16 | apply-base16-mustache $template)
$env.ALACRITTY_CONFIG = $conf
nu -c "$nu.env.ALACRITTY_CONFIG | save --raw '~/.config/alacritty/alacritty_colors.yml'"
}
# Generate LS_COLORS value
export def build-lscolors [base_txt: path] {
# TODO
}
# Show the current base16 colors
export def show [base_txt: path] {
from-file $base_txt | each { |it|
{ $it.column: $"(ansi -e { fg: ($it.value) bg: ($it.value) })($it.value)(ansi reset)" }
}
}
# Regenerate the wallpaper, its base16 theme, and apply it to external tools
export def new-wallpaper [] {
~/.fehbg.nu
~/.auto_base16.nu
build-alacritty-config $env.BASE16_TXT
}
# Get base16 as a record from an input file
export def from-file [base_txt: path] {
let base16_lines = (open $base_txt | lines | where ($it | str length) > 0)
{
base00 : $base16_lines.0 # Default Background
base01 : $base16_lines.1 # Lighter Background (Used for status bars, line number and folding marks)
base02 : $base16_lines.2 # Selection Background
base03 : $base16_lines.3 # Comments, Invisibles, Line Highlighting
base04 : $base16_lines.4 # Dark Foreground (Used for status bars)
base05 : $base16_lines.5 # Default Foreground, Caret, Delimiters, Operators
base06 : $base16_lines.6 # Light Foreground (Not often used)
base07 : $base16_lines.7 # Light Background (Not often used)
base08 : $base16_lines.8 # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
base09 : $base16_lines.9 # Integers, Boolean, Constants, XML Attributes, Markup Link Url
base0a : $base16_lines.10 # Classes, Markup Bold, Search Text Background
base0b : $base16_lines.11 # Strings, Inherited Class, Markup Code, Diff Inserted
base0c : $base16_lines.12 # Support, Regular Expressions, Escape Characters, Markup Quotes
base0d : $base16_lines.13 # Functions, Methods, Attribute IDs, Headings
base0e : $base16_lines.14 # Keywords, Storage, Selector, Markup Italic, Diff Changed
base0f : $base16_lines.15 # Deprecated, Opening/Closing Embedded Language Tags, e.g. <?php ?>
}
}
# Get base16 as a table from an input file
export def from-file-table [base_txt: path] {
let base16_lines = (open $base_txt | lines | where ($it | str length) > 0)
[
[ name color ];
[ base00 $base16_lines.0 ] # Default Background
[ base01 $base16_lines.1 ] # Lighter Background (Used for status bars, line number and folding marks)
[ base02 $base16_lines.2 ] # Selection Background
[ base03 $base16_lines.3 ] # Comments, Invisibles, Line Highlighting
[ base04 $base16_lines.4 ] # Dark Foreground (Used for status bars)
[ base05 $base16_lines.5 ] # Default Foreground, Caret, Delimiters, Operators
[ base06 $base16_lines.6 ] # Light Foreground (Not often used)
[ base07 $base16_lines.7 ] # Light Background (Not often used)
[ base08 $base16_lines.8 ] # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
[ base09 $base16_lines.9 ] # Integers, Boolean, Constants, XML Attributes, Markup Link Url
[ base0a $base16_lines.10 ] # Classes, Markup Bold, Search Text Background
[ base0b $base16_lines.11 ] # Strings, Inherited Class, Markup Code, Diff Inserted
[ base0c $base16_lines.12 ] # Support, Regular Expressions, Escape Characters, Markup Quotes
[ base0d $base16_lines.13 ] # Functions, Methods, Attribute IDs, Headings
[ base0e $base16_lines.14 ] # Keywords, Storage, Selector, Markup Italic, Diff Changed
[ base0f $base16_lines.15 ] # Deprecated, Opening/Closing Embedded Language Tags, e.g. <?php ?>
]
}
# Replace {{baseXX-hex}} with proper colors, such as #ffeedd
def apply-base16-mustache [template: string] {
reduce -f $template { |it|
let subs = $"\{\{($it.item.name)-hex\}\}" # regex
let color = $it.item.color
$it.acc | str replace -a $subs $color
}
}

View File

@@ -0,0 +1,64 @@
# Clone all
Do you want to automate cloning a list repos into a folder? This script is for you!
## Requirements:
- [`gh` cli](https://github.com/cli/cli)
## How to use it
Load the script:
- if you have cloned the repo before:
```nushell env.nu
source ~/your/directory/to/nu_scripts/modules/clone-all/clone-all.nu
```
or if you have the file, and you want it to use in a nushell session:
```nushell
use clone-all.nu *
# and it's ready to use in the current prompt!
```
Then, create a list of github routes to repositories `ORGANIZATION_NAME/REPO`
like this:
```nu
let list_of_repos = [
"nushell/nushell"
"nushell/nu_scripts"
"nushell/vscode-nushell-lang"
]
```
And then you need to pass that variable and a destination folder
```nu
clone all $list_of_repos $"($env.home)/other-repos/nu_repos"
```
## Tips
I (@AucaCoyan) use it for cloning both org repos and my forks
```nushell
let nushell_repos = [
"nushell/nushell"
"nushell/nu_scripts"
"nushell/vscode-nushell-lang"
]
clone all $nushell_repos $"($env.home)/other-repos/nu"
let nushell_forks = [
"AucaCoyan/nushell"
"AucaCoyan/nu_scripts"
"AucaCoyan/vscode-nushell-lang"
]
clone all $nushell_forks $"($env.home)/repos"
```
and do that with every gh org (work or open source!)

View File

@@ -0,0 +1,47 @@
# grabs the repo name of a github (ORG/repo) string
#
# for example
# grab repo name "organization/my_special_repo"
# returns "myspecial_repo"
# Grabs the repo name of a github (ORG/repo) string
def "grab repo name" [ghrepo: string]: [string -> string] {
$ghrepo | split column "/" | get column2 | last
}
# Generic fn to clone all repos of one organization into a specific folder
#
# # Parameters
# `list_of_repos` is a list of <ORG/REPO> from github
# for example:
# ```nu
# let list_of_repos = [
# "nushell/nushell"
# "nushell/nu_scripts"
# "nushell/vscode-nushell-lang"
# ]
#
# and destination is the location where those repos are cloned
# $ use clone-all.nu *
# $ clone all ['nushell/nu_scripts'] /home/my-dir/
# equals
# gh repo clone nushell/nu_scripts /home/my-dir/nu_scripts
# (note that it doesn't create the organization folder)
# Clones all the `list_of_repos` into `destination` folder
export def "clone all" [list_of_repos: list<string>, destination: path] {
print $" creating ($destination) folder"
mkdir $destination
for $repo in $list_of_repos {
let repo_name = grab repo name $repo
let single_repo_dir = $"($destination)/($repo_name)"
if ($single_repo_dir | path exists) {
print $"\n repo ($single_repo_dir) exists, skipping"
continue
} else {
print $"\n cloning ($repo)"
gh repo clone $repo $single_repo_dir
}
}
}

View File

@@ -0,0 +1,37 @@
export def draw [] {
let term_cols = ((term size).columns - 1)
# let's itertate through each of the columns of our terminal
0..$term_cols | each { |col|
let r = (255 - ($col * 255 / $term_cols) | math round)
let g = ($col * 510 / $term_cols | math round)
let b = ($col * 255 / $term_cols | math round)
if $g > 255 {
let g = (510 - $g)
build-colorstr $r $g $b $col
} else {
build-colorstr $r $g $b $col
}
} | str join
}
def build-colorstr [
r:int # Red
g:int # Green
b:int # Blue
c:int # Column
] {
# Heavy use of string interpolation below
let bg = $"(ansi rgb_bg)($r);($g);($b)m"
let fg = $"(ansi rgb_fg)(255 - $r);(255 - $g);(255 - $b)m"
let idx = ($c mod 2)
let slash_str = (if $idx == 0 {
$'/(ansi reset)'
} else {
$'\(ansi reset)'
})
$"($bg)($fg)($slash_str)"
# sleep 10ms | ignore
}
draw

View File

@@ -0,0 +1,169 @@
def contrast_colour [ colour:int ] {
# The first 16 colors
if $colour < 16 {
if $colour == 0 {
15
} else {
0
}
} else {
# The gray colors
if $colour > 231 {
if $colour < 244 {
15
} else {
0
}
} else {
# The rest
let r = ($colour - 16) / 36
let g = (($colour - 16) mod 36) / 6
let b = ($colour - 16) mod 6
let luminance = ($r * 299) + ($g * 587) + ($b * 114)
if $luminance > 2500 {
0
} else {
15
}
}
}
}
def print_colour [ colour:int ] {
let contrast = (contrast_colour $colour)
let bg_color = $"(ansi idx_bg)($colour)m" # Start block of colour
let fg_color = $"(ansi idx_fg)($contrast)m" # In contrast, print number
let text = $"($colour | into string | fill -c ' ' -w 3 -a r)(ansi reset)"
$bg_color + $fg_color + $text + " "
}
let printable_colours = 256
def print_run [start:int, amount:int] {
$start..<($start + $amount) | each { |i|
if $i < $printable_colours {
print_colour $i
} else {
""
}
} | append " " | str join
}
def print_blocks [start:int, end:int, block_cols:int, block_rows:int, blocks_per_line:int] {
let block_length = ($block_cols * $block_rows)
let end = (($end - $start) / (($blocks_per_line) * $block_length)) | math round
0..<$end | each { |i|
0..<$block_rows | each { |row|
0..<$blocks_per_line | each { |block|
print_run ($start + $block * $block_length + $row * $block_cols + $i * $block_length * $blocks_per_line) $block_cols
} | append (char nl) | str join
} | str join
} | str join
}
print (print_run 0 16) # The first 16 colours are spread over the whole spectrum
print "" # Single line
print (print_blocks 16 123 6 6 3) # 6x6x6 colour cube between 16 and 123 inclusive
print (print_blocks 124 231 6 6 3) # 6x6x6 colour cube between 124 and 231 inclusive
print (print_blocks 232 255 12 2 1) # Not 50, but 24 Shades of Grey
# bash:
# #!/bin/bash
#
# # Tom Hale, 2016. MIT Licence.
# # Print out 256 colours, with each number printed in its corresponding colour
# # See http://askubuntu.com/questions/821157/print-a-256-color-test-pattern-in-the-terminal/821163#821163
#
# set -eu # Fail on errors or undeclared variables
#
# printable_colours=256
#
# # Return a colour that contrasts with the given colour
# # Bash only does integer division, so keep it integral
# function contrast_colour {
# local r g b luminance
# colour="$1"
#
# if (( colour < 16 )); then # Initial 16 ANSI colours
# (( colour == 0 )) && printf "15" || printf "0"
# return
# fi
#
# # Greyscale # rgb_R = rgb_G = rgb_B = (number - 232) * 10 + 8
# if (( colour > 231 )); then # Greyscale ramp
# (( colour < 244 )) && printf "15" || printf "0"
# return
# fi
#
# # All other colours:
# # 6x6x6 colour cube = 16 + 36*R + 6*G + B # Where RGB are [0..5]
# # See http://stackoverflow.com/a/27165165/5353461
#
# # r=$(( (colour-16) / 36 ))
# g=$(( ((colour-16) % 36) / 6 ))
# # b=$(( (colour-16) % 6 ))
#
# # If luminance is bright, print number in black, white otherwise.
# # Green contributes 587/1000 to human perceived luminance - ITU R-REC-BT.601
# (( g > 2)) && printf "0" || printf "15"
# return
#
# # Uncomment the below for more precise luminance calculations
#
# # # Calculate percieved brightness
# # # See https://www.w3.org/TR/AERT#color-contrast
# # # and http://www.itu.int/rec/R-REC-BT.601
# # # Luminance is in range 0..5000 as each value is 0..5
# # luminance=$(( (r * 299) + (g * 587) + (b * 114) ))
# # (( $luminance > 2500 )) && printf "0" || printf "15"
# }
#
# # Print a coloured block with the number of that colour
# function print_colour {
# local colour="$1" contrast
# contrast=$(contrast_colour "$1")
# printf "\e[48;5;%sm" "$colour" # Start block of colour
# printf "\e[38;5;%sm%3d" "$contrast" "$colour" # In contrast, print number
# printf "\e[0m " # Reset colour
# }
#
# # Starting at $1, print a run of $2 colours
# function print_run {
# local i
# for (( i = "$1"; i < "$1" + "$2" && i < printable_colours; i++ )) do
# print_colour "$i"
# done
# printf " "
# }
#
# # Print blocks of colours
# function print_blocks {
# local start="$1" i
# local end="$2" # inclusive
# local block_cols="$3"
# local block_rows="$4"
# local blocks_per_line="$5"
# local block_length=$((block_cols * block_rows))
#
# # Print sets of blocks
# for (( i = start; i <= end; i += (blocks_per_line-1) * block_length )) do
# printf "\n" # Space before each set of blocks
# # For each block row
# for (( row = 0; row < block_rows; row++ )) do
# # Print block columns for all blocks on the line
# for (( block = 0; block < blocks_per_line; block++ )) do
# print_run $(( i + (block * block_length) )) "$block_cols"
# done
# (( i += block_cols )) # Prepare to print the next row
# printf "\n"
# done
# done
# }
#
# print_run 0 16 # The first 16 colours are spread over the whole spectrum
# printf "\n"
# print_blocks 16 231 6 6 3 # 6x6x6 colour cube between 16 and 231 inclusive
# print_blocks 232 255 12 2 1 # Not 50, but 24 Shades of Grey

View File

@@ -0,0 +1,5 @@
# Coloring Scripts
### Definition
These scripts are used to demonstrate the `ansi` command using `ansi` coloring. This is mainly a demo area where we have taken typical `bash` scripts and ported them to nushell scripts. It would be nice if all scripts here showed the "other" version of script and the ported nushell version. We can show "other" flavors of scripts by including them as comments in the nushell scripts or by naming the nushell script and the other script the same basename.

View File

@@ -0,0 +1,94 @@
def make_header [hi] {
if $hi == true {
let ansi100m = ('100m' | fill -a l -w 11 -c ' ')
let ansi101m = ('101m' | fill -a l -w 9 -c ' ')
let ansi102m = ('102m' | fill -a l -w 9 -c ' ')
let ansi103m = ('103m' | fill -a l -w 9 -c ' ')
let ansi104m = ('104m' | fill -a l -w 9 -c ' ')
let ansi105m = ('105m' | fill -a l -w 9 -c ' ')
let ansi106m = ('106m' | fill -a l -w 9 -c ' ')
let ansi107m = ('107m' | fill -a l -w 9 -c ' ')
$"(char newline)($ansi100m)($ansi101m)($ansi102m)($ansi103m)($ansi104m)($ansi105m)($ansi106m)($ansi107m)(char newline)"
} else {
let ansi40m = ('40m' | fill -a l -w 10 -c ' ')
let ansi41m = ('41m' | fill -a l -w 8 -c ' ')
let ansi42m = ('42m' | fill -a l -w 8 -c ' ')
let ansi43m = ('43m' | fill -a l -w 8 -c ' ')
let ansi44m = ('44m' | fill -a l -w 8 -c ' ')
let ansi45m = ('45m' | fill -a l -w 8 -c ' ')
let ansi46m = ('46m' | fill -a l -w 8 -c ' ')
let ansi47m = ('47m' | fill -a l -w 8 -c ' ')
$"(char newline)($ansi40m)($ansi41m)($ansi42m)($ansi43m)($ansi44m)($ansi45m)($ansi46m)($ansi47m)(char newline)"
}
}
# mk_header and make_header do the same thing in different ways
# make_header is far easier to read and understand
# mk_header is more convoluted but less repetitive
def mk_header [color_range:range] {
let min_rng = (echo $color_range | math min)
let hi_start_pad = 11
let hi_regular_pad = 9
let lo_start_pad = 10
let lo_regular_pad = 8
echo $color_range | each { |color|
let ansi_color = $"($color)m"
if $color == $min_rng {
if $min_rng == 100 {
($ansi_color | fill -a l -w $hi_start_pad -c ' ')
} else {
($ansi_color | fill -a l -w $lo_start_pad -c ' ')
}
} else {
if $min_rng >= 100 {
($ansi_color | fill -a l -w $hi_regular_pad -c ' ')
} else {
($ansi_color | fill -a l -w $lo_regular_pad -c ' ')
}
}
} | str join
echo (char newline)
}
def color_row_range [num:int bg_rg:range] {
let reset = (ansi reset)
let row_header = $"($num)m ($reset)"
let row_data = (echo $bg_rg | each { |back|
let row_name = $"($num);($back)m"
let ansi_color = (ansi -e $row_name)
$"($ansi_color) ($row_name) ($reset)"
} | append (char newline) | str join)
$"($row_header)($row_data)"
}
def create_color_tables [fg_range:range bg_range:range] {
echo $fg_range | each { |fg|
color_row_range $fg $bg_range
} | str join
}
def color_table [] {
[
# make_header $false
(mk_header 40..47)
(create_color_tables 30..37 40..47)
# put a line between tables
(char newline)
#make_header $true
(mk_header 100..107)
(create_color_tables 90..97 100..107)
] | str join
}
color_table

View File

@@ -0,0 +1,23 @@
# Bash script
# for x in {0..8}; do
# for i in {30..37}; do
# for a in {40..47}; do
# echo -ne "\e[$x;$i;$a""m\\\e[$x;$i;$a""m\e[0;37;40m "
# done
# echo
# done
# echo
# done
# echo ""
0..8 | each {|x|
let row = (30..37 | each {|i|
let row = (40..47 | each {|a|
let color = $"($x);($i);($a)"
$"(ansi -e $color)m\\e[($color)(ansi -e '0;37;40')m "
} | str join)
$"($row)(char newline)"
} | str join)
$"($row)(char newline)"
} | str join

View File

@@ -0,0 +1,82 @@
# this script will print a blue gradient on the screen
# We can get the terminal width and height now with term size
# but we like to use the script as a benchmark, so let's keep
# it a constant size for now
let height = 40 # really need to get the terminal height here
let width = 160 # really need to get the terminal width here
let stamp = 'Nu'
def iter_inc [incr mult iter] {
$incr + $mult * $iter
}
seq 0 $height | each {
let row_data = (seq 0 $width | each { |col|
let fgcolor = (iter_inc 2 2 $col)
if $fgcolor > 200 and $fgcolor < 210 {
$"(ansi -e '48;2;0;0;')($fgcolor)m($stamp)(ansi -e '0m')"
} else {
$"(ansi -e '48;2;0;0;')($fgcolor)m(char sp)(ansi -e '0m')"
}
} | str join)
$"($row_data)(char newline)"
} | str join
# python:
#
# #!/usr/bin/env python
# from colors import *
#
# def iter_inc(incr, mult, it):
# return incr + mult * it
#
# height = 40
# width = 160
# stamp = "py"
#
# for line in range(0, height):
# row_data = ""
#
# for col in range(0, width):
# fgcolor = iter_inc(2, 2, col)
# if fgcolor > 200 and fgcolor < 210:
# row_data = row_data + color(stamp, bg='rgb(0, 0, %d)' % fgcolor)
# else:
# fg = fgcolor % 256
# row_data = row_data + color(' ', bg='rgb(0, 0, %d)' % fg)
#
# print(row_data)
# powershell:
# function Set-Cursor {
# [CmdletBinding()]
# param ([int] $x, [int] $y)
# $Host.UI.RawUI.CursorPosition = @{x = $x; y = $y }
# }
#
# function Get-Character {
# [CmdletBinding()]
# param ([int]$index)
# $mystring = ' Trevor Sullivan'
# return $index -ge ($mystring.Length) ? ' ' : $mystring[$index]
# }
#
# function main {
#
# for ($y = 0; $y -le ($host.ui.RawUI.BufferSize.Height - 1); $y++) {
# $Color = 25
# Set-Cursor -x $PSItem -y $y
# 0..($Host.UI.RawUI.BufferSize.Width - 1) | ForEach-Object {
# Write-Host -Object ("`e[48;2;0;0;$Color`m{0}" -f (Get-Character -Index $PSItem)) -NoNewline
# $Color += 2
# }
# }
# Start-Sleep -Seconds 5
# }
#
# main

View File

@@ -0,0 +1,56 @@
export def combine [txt: string, fg: record, bg: record] {
{
txt: $txt,
fg: $fg.fg,
bg: $bg.fg,
bli: ($fg.bli or $bg.bli),
bol: ($fg.bol or $bg.bol),
dim: ($fg.dim or $bg.dim),
hid: ($fg.hid or $bg.hid),
ita: ($fg.ita or $bg.ita),
rev: ($fg.rev or $bg.rev),
stk: ($fg.stk or $bg.stk),
und: ($fg.und or $bg.und)
}
}
export def create [txt: string,
fg = "default", bg = "default",
bli = false, bol = false, dim = false, hid = false,
ita = false, rev = false, stk = false, und = false] {
{
txt: $txt,
fg: $fg,
bg: $bg,
bli: $bli,
bol: $bol,
dim: $dim,
hid: $hid,
ita: $ita,
rev: $rev,
stk: $stk,
und: $und
}
}
export def render [obj: record] {
let attr = ""
let attr = $"($attr)(if $obj.bli {'l'})"
let attr = $"($attr)(if $obj.bol {'b'})"
let attr = $"($attr)(if $obj.dim {'d'})"
let attr = $"($attr)(if $obj.hid {'h'})"
let attr = $"($attr)(if $obj.ita {'i'})"
let attr = $"($attr)(if $obj.rev {'r'})"
let attr = $"($attr)(if $obj.stk {'s'})"
let attr = $"($attr)(if $obj.und {'u'})"
let color = {fg: $obj.fg, bg: $obj.bg, attr: $attr}
$"(ansi $color)($obj.txt)(ansi reset)"
}
export def reverse [obj: record] {
let r = ($obj | update fg $obj.bg)
let r = ($r | update bg $obj.fg)
$r
}

View File

@@ -0,0 +1,149 @@
# these are common colors from https://en.wikipedia.org/wiki/web_colors
let aliceblue = "#f0f8ff"
let antiquewhite = "#faebd7"
let aqua = "#00ffff"
let aquamarine = "#7fffd4"
let azure = "#f0ffff"
let beige = "#f5f5dc"
let bisque = "#ffe4c4"
let black = "#000000"
let blanchedalmond = "#ffebcd"
let blue = "#0000ff"
let blueviolet = "#8a2be2"
let brown = "#a52a2a"
let burlywood = "#deb887"
let cadetblue = "#5f9ea0"
let chartreuse = "#7fff00"
let chocolate = "#d2691e"
let coral = "#ff7f50"
let cornflowerblue = "#6495ed"
let cornsilk = "#fff8dc"
let crimson = "#dc143c"
let cyan = "#00ffff"
let darkblue = "#00008b"
let darkcyan = "#008b8b"
let darkgoldenrod = "#b8860b"
let darkgray = "#a9a9a9"
let darkgrey = "#a9a9a9"
let darkgreen = "#006400"
let darkkhaki = "#bdb76b"
let darkmagenta = "#8b008b"
let darkolivegreen = "#556b2f"
let darkorange = "#ff8c00"
let darkorchid = "#9932cc"
let darkred = "#8b0000"
let darksalmon = "#e9967a"
let darkseagreen = "#8fbc8f"
let darkslateblue = "#483d8b"
let darkslategray = "#2f4f4f"
let darkslategrey = "#2f4f4f"
let darkturquoise = "#00ced1"
let darkviolet = "#9400d3"
let deeppink = "#ff1493"
let deepskyblue = "#00bfff"
let dimgray = "#696969"
let dimgrey = "#696969"
let dodgerblue = "#1e90ff"
let firebrick = "#b22222"
let floralwhite = "#fffaf0"
let forestgreen = "#228b22"
let fuchsia = "#ff00ff"
let gainsboro = "#dcdcdc"
let ghostwhite = "#f8f8ff"
let gold = "#ffd700"
let goldenrod = "#daa520"
let gray = "#808080"
let grey = "#808080"
let green = "#008000"
let greenyellow = "#adff2f"
let honeydew = "#f0fff0"
let hotpink = "#ff69b4"
let indianred = "#cd5c5c"
let indigo = "#4b0082"
let ivory = "#fffff0"
let khaki = "#f0e68c"
let lavender = "#e6e6fa"
let lavenderblush = "#fff0f5"
let lawngreen = "#7cfc00"
let lemonchiffon = "#fffacd"
let lightblue = "#add8e6"
let lightcoral = "#f08080"
let lightcyan = "#e0ffff"
let lightgoldenrodyellow = "#fafad2"
let lightgray = "#d3d3d3"
let lightgrey = "#d3d3d3"
let lightgreen = "#90ee90"
let lightpink = "#ffb6c1"
let lightsalmon = "#ffa07a"
let lightseagreen = "#20b2aa"
let lightskyblue = "#87cefa"
let lightslategray = "#778899"
let lightslategrey = "#778899"
let lightsteelblue = "#b0c4de"
let lightyellow = "#ffffe0"
let lime = "#00ff00"
let limegreen = "#32cd32"
let linen = "#faf0e6"
let magenta = "#ff00ff"
let maroon = "#800000"
let mediumaquamarine = "#66cdaa"
let mediumblue = "#0000cd"
let mediumorchid = "#ba55d3"
let mediumpurple = "#9370d8"
let mediumseagreen = "#3cb371"
let mediumslateblue = "#7b68ee"
let mediumspringgreen = "#00fa9a"
let mediumturquoise = "#48d1cc"
let mediumvioletred = "#c71585"
let midnightblue = "#191970"
let mintcream = "#f5fffa"
let mistyrose = "#ffe4e1"
let moccasin = "#ffe4b5"
let navajowhite = "#ffdead"
let navy = "#000080"
let oldlace = "#fdf5e6"
let olive = "#808000"
let olivedrab = "#6b8e23"
let orange = "#ffa500"
let orangered = "#ff4500"
let orchid = "#da70d6"
let palegoldenrod = "#eee8aa"
let palegreen = "#98fb98"
let paleturquoise = "#afeeee"
let palevioletred = "#d87093"
let papayawhip = "#ffefd5"
let peachpuff = "#ffdab9"
let peru = "#cd853f"
let pink = "#ffc0cb"
let plum = "#dda0dd"
let powderblue = "#b0e0e6"
let purple = "#800080"
let rebeccapurple = "#663399"
let red = "#ff0000"
let rosybrown = "#bc8f8f"
let royalblue = "#4169e1"
let saddlebrown = "#8b4513"
let salmon = "#fa8072"
let sandybrown = "#f4a460"
let seagreen = "#2e8b57"
let seashell = "#fff5ee"
let sienna = "#a0522d"
let silver = "#c0c0c0"
let skyblue = "#87ceeb"
let slateblue = "#6a5acd"
let slategray = "#708090"
let slategrey = "#708090"
let snow = "#fffafa"
let springgreen = "#00ff7f"
let steelblue = "#4682b4"
let tan = "#d2b48c"
let teal = "#008080"
let thistle = "#d8bfd8"
let tomato = "#ff6347"
let turquoise = "#40e0d0"
let violet = "#ee82ee"
let wheat = "#f5deb3"
let white = "#ffffff"
let whitesmoke = "#f5f5f5"
let yellow = "#ffff00"
let yellowgreen = "#9acd32"

View File

@@ -0,0 +1,15 @@
def show_index_colors [] {
let prefix = "48;5;"
1..256 | each { |idx|
let color = $"(ansi -e $prefix)($idx)m"
let padded_number = ($"($idx)" | fill -a l -w 3 -c '0')
let cr = ($idx mod 16)
if $cr == 0 {
$"($color)($padded_number) (ansi -e 0m)(char newline)"
} else {
$"($color)($padded_number) (ansi -e 0m)"
}
} | str join
}
show_index_colors

View File

@@ -0,0 +1,27 @@
# this script uses foreground ansi index colors to print
# a table of 16 rows by 16 colums where each item is a
# different color
def show_index_colors [] {
let prefix = "38;5;"
echo 1..256 | each { |idx|
let cr = (($idx) mod 16)
let color = ($"(ansi -e $prefix)($idx)m")
let padded_number = ($"($idx)" | fill -a l -w 3 -c '0')
if $cr == 0 {
$"($color)($padded_number) (char newline)"
} else {
$"($color)($padded_number) "
}
} | str join
}
# one-liner version that just prints
# it all on one line which wraps in
# your terminal
def one_liner [] {
0..255 | each {|fg| [(ansi -e '38;5;') ($fg | into string) 'm' ($fg | into string) ' ']} | flatten | str join
}
show_index_colors

View File

@@ -0,0 +1,29 @@
# This is the python script
# import sys
# for i in range(0, 16):
# for j in range(0, 16):
# code = str(i * 16 + j)
# sys.stdout.write(u"\u001b[38;5;" + code + "m " + code.ljust(4))
# print u"\u001b[0m"
# Foreground Colors
print (0..16 | each { |col|
let row = (echo 0..16 | each { |row|
let code = ($col * 16 + $row)
if $code < 256 {
$"(ansi -e '38;5;')($code | into string)m($code | into string | fill -a l -w 4 -c ' ')(ansi reset)"
}
} | str join)
$"($row)(char newline)"
} | str join)
# Background Colors
print (0..16 | each { |col|
let row = (echo 0..16 | each { |row|
let code = ($col * 16 + $row)
if $code < 256 {
$"(ansi -e '48;5;')($code | into string)m($code | into string | fill -a l -w 4 -c ' ')(ansi reset)"
}
} | str join)
$"($row)(char newline)"
} | str join)

View File

@@ -0,0 +1,51 @@
# This script will print a table 8 rows by 36 columns
# of background colors using ansi index coloring
# #!/bin/bash
# echo -en "\n + "
# for i in {0..35}; do
# printf "%2b " $i
# done
# printf "\n\n %3b " 0
# for i in {0..15}; do
# echo -en "\033[48;5;${i}m \033[m "
# done
# #for i in 16 52 88 124 160 196 232; do
# for i in {0..6}; do
# let "i = i*36 +16"
# printf "\n\n %3b " $i
# for j in {0..35}; do
# let "val = i+j"
# echo -en "\033[48;5;${val}m \033[m "
# done
# done
# echo -e "\n"
# This prints the column headers
let nl = (char newline)
let plus = $"($nl) + "
let cols = (seq 0 35 | each { |col| $"($col)" | fill -a l -c ' ' -w 3 } | str join)
print $"($plus)($cols)"
let ansi_bg = (ansi -e '48;5;')
let ansi_reset = (ansi reset)
print $"($nl)($nl)"
# This prints the row headers
let row_header = ' 0 '
let row_data = (seq 0 15 | each { |row|
$"($ansi_bg)($row)m ($ansi_reset)"
} | str join)
print $"($row_header)($row_data)($nl)($nl)"
# This is the meat of the script that prints the little squares of color
seq 0 6 | each { |row_idx|
let r = ($row_idx * 36 + 16)
let row_header = (echo $r | into string -d 0 | fill -a l -c ' ' -w 4)
let row_data = (seq 0 35 | each { |row|
let val = (($r + $row) | into string -d 0)
$"($ansi_bg)($val)m (ansi -e 'm') "
} | str join)
$"($row_header) ($row_data)($nl)($nl)"
} | str join

View File

@@ -0,0 +1,46 @@
# Background Colors
[40..47 100..107 49] | each { flatten } | flatten | each { |clbg|
# Foreground Colors
[30..37 90..97 39] | each { flatten } | flatten | each { |clfg|
# 0 Normal
# 1 Bold or increased intensity
# 2 Faint or decreased intensity
# 3 Italic (not widely supported)
# 4 Underline
# 5 Slow Blink < 150 per minute
# 6 Rapid Blink > 150 per minute
# 7 Reverse Video
# 8 Conceal (not widely supported)
# 9 Strike-through
let row = (0..9 | each { |attr|
let ansi_str = $"($attr);($clbg);($clfg)m"
$"(ansi -e $ansi_str) ($ansi_str) (ansi reset)"
} | str join)
$"($row)(char newline)"
} | str join
} | str join
# Bash Script
# #!/bin/bash
#
# # This program is free software. It comes without any warranty, to
# # the extent permitted by applicable law. You can redistribute it
# # and/or modify it under the terms of the Do What The Fuck You Want
# # To Public License, Version 2, as published by Sam Hocevar. See
# # http://sam.zoy.org/wtfpl/COPYING for more details.
#
# #Background
# for clbg in {40..47} {100..107} 49 ; do
# #Foreground
# for clfg in {30..37} {90..97} 39 ; do
# #Formatting
# for attr in 0 1 2 4 5 7 ; do
# #Print the result
# echo -en "\033[${attr};${clbg};${clfg}m ^[${attr};${clbg};${clfg}m \033[0m"
# done
# echo #Newline
# done
# done
#
# exit 0

View File

@@ -0,0 +1,189 @@
source ../stdlib_candidate/nu_style.nu
# # Regular Colors
$" Regular Colors (char newline) (char newline)"
# | Value | Color |
# | -------- | ------ |
# | \e[0;30m | Black |
# | \e[0;31m | Red |
# | \e[0;32m | Green |
# | \e[0;33m | Yellow |
# | \e[0;34m | Blue |
# | \e[0;35m | Purple |
# | \e[0;36m | Cyan |
# | \e[0;37m | White |
$"| Value | Color | Name | (char newline)"
$"| ----- | ----- | --------- | (char newline)"
$"| (fg_black)0;30m(relet) | Black | fg_black | (char newline)"
$"| (fg_red)0;31m(relet) | Red | fg_red | (char newline)"
$"| (fg_green)0;32m(relet) | Green | fg_green | (char newline)"
$"| (fg_yellow)0;33m(relet) | Yellow | fg_yellow | (char newline)"
$"| (fg_blue)0;34m(relet) | Blue | fg_blue | (char newline)"
$"| (fg_purple)0;35m(relet) | Purple | fg_purple | (char newline)"
$"| (fg_cyan)0;36m(relet) | Cyan | fg_cyan | (char newline)"
$"| (fg_white)0;37m(relet) | White | fg_white | (char newline)"
char newline
# # Bold
$" Bold Colors (char newline) (char newline)"
# | Value | Color |
# | -------- | -------- |
# | \e[1;30m | Black |
# | \e[1;31m | Red |
# | \e[1;32m | Green |
# | \e[1;33m | Yellow |
# | \e[1;34m | Blue |
# | \e[1;35m | Purple |
# | \e[1;36m | Cyan |
# | \e[1;37m | White |
# | \e[1m | No Color |
$"| Value | Color | (char newline)"
$"| ----- | ----- | (char newline)"
$"| (fg_black)(bold_on)1;30m(relet) | Black | (char newline)"
$"| (fg_red)(bold_on)1;31m(relet) | Red | (char newline)"
$"| (fg_green)(bold_on)1;32m(relet) | Green | (char newline)"
$"| (fg_yellow)(bold_on)1;33m(relet) | Yellow | (char newline)"
$"| (fg_blue)(bold_on)1;34m(relet) | Blue | (char newline)"
$"| (fg_purple)(bold_on)1;35m(relet) | Purple | (char newline)"
$"| (fg_cyan)(bold_on)1;36m(relet) | Cyan | (char newline)"
$"| (fg_white)(bold_on)1;37m(relet) | White | (char newline)"
char newline
# # Underline
$" Underline Colors (char newline) (char newline)"
# | Value | Color |
# | -------- | -------- |
# | \e[4;30m | Black |
# | \e[4;31m | Red |
# | \e[4;32m | Green |
# | \e[4;33m | Yellow |
# | \e[4;34m | Blue |
# | \e[4;35m | Purple |
# | \e[4;36m | Cyan |
# | \e[4;37m | White |
# | \e[4m | No Color |
$"| Value | Color | (char newline)"
$"| ----- | ----- | (char newline)"
$"| (fg_black)(underline_on)4;30m(relet) | Black | (char newline)"
$"| (fg_red)(underline_on)4;31m(relet) | Red | (char newline)"
$"| (fg_green)(underline_on)4;32m(relet) | Green | (char newline)"
$"| (fg_yellow)(underline_on)4;33m(relet) | Yellow | (char newline)"
$"| (fg_blue)(underline_on)4;34m(relet) | Blue | (char newline)"
$"| (fg_purple)(underline_on)4;35m(relet) | Purple | (char newline)"
$"| (fg_cyan)(underline_on)4;36m(relet) | Cyan | (char newline)"
$"| (fg_white)(underline_on)4;37m(relet) | White | (char newline)"
char newline
# # Background
$" Background Colors (char newline) (char newline)"
# | Value | Color |
# | ------ | ------ |
# | \e[40m | Black |
# | \e[41m | Red |
# | \e[42m | Green |
# | \e[43m | Yellow |
# | \e[44m | Blue |
# | \e[45m | Purple |
# | \e[46m | Cyan |
# | \e[47m | White |
$"| Value | Color | (char newline)"
$"| ----- | ----- | (char newline)"
$"| (bg_black)0;40m(relet)| Black | (char newline)"
$"| (bg_red)0;41m(relet)| Red | (char newline)"
$"| (bg_green)0;42m(relet)| Green | (char newline)"
$"| (bg_yellow)0;43m(relet)| Yellow | (char newline)"
$"| (bg_blue)0;44m(relet)| Blue | (char newline)"
$"| (bg_purple)0;45m(relet)| Purple | (char newline)"
$"| (bg_cyan)0;46m(relet)| Cyan | (char newline)"
$"| (bg_white)0;47m(relet)| White | (char newline)"
char newline
# # Expand Background Horizontally
# | Value | Color |
# | ----- | -------- |
# | \e[K | No Color |
# # High Intensty
$" High Intensity (char newline) (char newline)"
# | Value | Color |
# | -------- | ------ |
# | \e[0;90m | Black |
# | \e[0;91m | Red |
# | \e[0;92m | Green |
# | \e[0;93m | Yellow |
# | \e[0;94m | Blue |
# | \e[0;95m | Purple |
# | \e[0;96m | Cyan |
# | \e[0;97m | White |
$"| Value | Color | (char newline)"
$"| ----- | ----- | (char newline)"
$"| (fg_light_black)0;90m(relet) | Black | (char newline)"
$"| (fg_light_red)0;91m(relet) | Red | (char newline)"
$"| (fg_light_green)0;92m(relet) | Green | (char newline)"
$"| (fg_light_yellow)0;93m(relet) | Yellow | (char newline)"
$"| (fg_light_blue)0;94m(relet) | Blue | (char newline)"
$"| (fg_light_purple)0;95m(relet) | Purple | (char newline)"
$"| (fg_light_cyan)0;96m(relet) | Cyan | (char newline)"
$"| (fg_light_white)0;97m(relet) | White | (char newline)"
char newline
# # Bold High Intensty
$" Bold High Intensity (char newline) (char newline)"
# | Value | Color |
# | -------- | ------ |
# | \e[1;90m | Black |
# | \e[1;91m | Red |
# | \e[1;92m | Green |
# | \e[1;93m | Yellow |
# | \e[1;94m | Blue |
# | \e[1;95m | Purple |
# | \e[1;96m | Cyan |
# | \e[1;97m | White |
$"| Value | Color | (char newline)"
$"| ----- | ----- | (char newline)"
$"| (fg_light_black)(bold_on)1;90m(relet) | Black | (char newline)"
$"| (fg_light_red)(bold_on)1;91m(relet) | Red | (char newline)"
$"| (fg_light_green)(bold_on)1;92m(relet) | Green | (char newline)"
$"| (fg_light_yellow)(bold_on)1;93m(relet) | Yellow | (char newline)"
$"| (fg_light_blue)(bold_on)1;94m(relet) | Blue | (char newline)"
$"| (fg_light_purple)(bold_on)1;95m(relet) | Purple | (char newline)"
$"| (fg_light_cyan)(bold_on)1;96m(relet) | Cyan | (char newline)"
$"| (fg_light_white)(bold_on)1;97m(relet) | White | (char newline)"
char newline
# # High Intensty backgrounds
$" High Intensity backgrounds (char newline) (char newline)"
# | Value | Color |
# | --------- | ------ |
# | \e[0;100m | Black |
# | \e[0;101m | Red |
# | \e[0;102m | Green |
# | \e[0;103m | Yellow |
# | \e[0;104m | Blue |
# | \e[0;105m | Purple |
# | \e[0;106m | Cyan |
# | \e[0;107m | White |
$"| Value | Color | (char newline)"
$"| ----- | ----- | (char newline)"
$"| (bg_light_black)0;100m(relet) | Black | (char newline)"
$"| (bg_light_red)0;101m(relet) | Red | (char newline)"
$"| (bg_light_green)0;102m(relet) | Green | (char newline)"
$"| (bg_light_yellow)0;103m(relet) | Yellow | (char newline)"
$"| (bg_light_blue)0;104m(relet) | Blue | (char newline)"
$"| (bg_light_purple)0;105m(relet) | Purple | (char newline)"
$"| (bg_light_cyan)0;106m(relet) | Cyan | (char newline)"
$"| (bg_light_white)0;107m(relet) | White | (char newline)"
char newline
# # Reset
# | Value | Color |
# | ----- | ------ |
# | \e[0m | Reset |

View File

@@ -0,0 +1,183 @@
export def 'from tree' [
schema
--cmd-len(-c) = 1
--selector = {value: 'value', description: 'description', next: 'next'}
] {
let ctx = $in
let argv = $ctx.0
| str substring 0..$ctx.1
| split row -r '\s+'
| range $cmd_len..
| where not ($it | str starts-with '-')
let menu = $argv
| reduce -f {schema: $schema, path: []} {|x, acc|
let acc = $acc | update path ($acc.path | append $x)
if ($x | is-empty) {
$acc
} else {
match ($acc.schema | describe -d | get type) {
record => {
if $x in $acc.schema {
$acc | merge { schema: ($acc.schema | get $x) }
} else {
$acc
}
}
list => {
let fst = $acc.schema.0? | describe -d | get type
if not ($fst in ['list', 'record']) {
$acc
} else {
let r = $acc.schema | filter {|i| ($i | get $selector.value) == $x}
if ($r | is-empty) {
$acc
} else {
$acc | merge { schema: ($r | first | get $selector.next) }
}
}
}
_ => {
$acc
}
}
}
| update schema {|x|
if ($x.schema | describe -d | get type) == 'closure' {
do $x.schema $x.path
} else {
$x.schema
}
}
}
match ($menu.schema | describe -d | get type) {
record => {
$menu.schema
| transpose k v
| each {|i|
if ($i.v | describe -d | get type) == 'string' {
{ value: $i.k, description: $i.v }
} else {
$i.k
}
}
}
list => {
if ($menu.schema.0? | describe -d | get type) == 'record' {
$menu.schema
| each {|x| {$selector.value: null, $selector.description: null} | merge $x }
| select $selector.value $selector.description
| rename value description
} else {
$menu.schema
}
}
}
}
export def flare [...args:string@comflare] {
print ($args | str join ' -> ')
}
def comflare [...context] {
if not ('~/.cache/flare.json' | path exists) {
http get https://gist.githubusercontent.com/curran/d2656e98b489648ab3e2071479ced4b1/raw/9f2499d63e971c2110e52b3fa2066ebed234828c/flare-2.json
| to json
| save ~/.cache/flare.json
}
let data = open ~/.cache/flare.json
$context | from tree -c 2 --selector {value: name, description: value, next: children } [$data]
}
export def math [...args:string@commath] {
print ($args | str join ' -> ')
}
def commath [...context] {
$context | from tree -c 2 [
{
value: Count
description: closure
next: {|path| $path}
}
{
value: PureMathematics
next: {
NumberSystems: [
{ value: NaturalNumbers, description: '1, 2, 3, 4, 5', next: [Arithmetic ] }
{ value: Integer, description: '-2, -1, 0, 1, 2' }
{ value: RationalNumbers, description: '-7, 1/2, 2.32' }
{ value: RealNumbers, description: '-4pi, sqrt(2), e' }
{ value: ComplexNumbers, description: '3, i, 4+3i, -4i' }
]
Structures: {
Algebra: {
Equation: null
LinearAlgebra: [ Vector Matrices ]
}
NumberTheory: null
Combinatorics: [Tree Graph]
GroupTheory: null
OrderTheory: null
}
Space: {
Geometry: {
Trigonometry: null
FractalGeometry: null
}
Topology: null
MeasureTheory: null
DifferentialGeometry: null
}
Changes: {
Calculus: {
Differentials: null
Integrals: null
Gradients: null
}
VectorCalculus: null
DynamicalSystems: {
FluidFlows: null
Ecosystems: null
ChaosTheory: null
}
ComplexAnalysis: null
}
}
}
{
value: AppiledMathematics
next: {
Physics: {
TheoreticalPhysics: null
}
MathematicalChemistry: null
Biomathematics: null
Engineering : {
ControlTheory: null
}
NumericalAnalysis: null
GameTheory: null
Economics: null
Probability: null
Statistics: null
MathematicalFinance: null
Optimization: null
ComputerScience: {
MachineLearning: null
}
Cryptography: null
}
}
{
value: Foundations
next: {
FundamentalRules: { GodelIncompletenessTheorems: null }
MathematicalLogic: null
SetTheory: null
CategoryTheory: null
TheoryOfComputation: null
}
}
]
}

View File

@@ -0,0 +1,113 @@
def __cwdhist_menu [] {
{
name: cwdhist_menu
only_buffer_difference: true
marker: "| "
type: {
layout: list
page_size: 10
}
style: {
text: green
selected_text: green_reverse
description_text: yellow
}
source: { |buffer, position|
#$"[($position)]($buffer);(char newline)" | save -a ~/.cache/cwdhist.log
let t = ($buffer | split row ' ' | last)
if $env.cwd_history_full {
open $nu.history-path | query db $"
select cwd as value, count\(*) as cnt
from history
where cwd like '%($t)%'
group by cwd
order by cnt desc
limit 50
;"
} else {
open $env.cwd_history_file | query db $"
select cwd as value, count
from cwd_history
where cwd like '%($t)%'
order by count desc
limit 50
;"
}
}
}
}
def __cwdhist_keybinding [] {
{
name: cwdhist_menu
modifier: alt
keycode: char_o
mode: [emacs, vi_normal, vi_insert]
event: [
{ send: menu name: cwdhist_menu }
]
}
}
def __cwdhist_switching [] {
{
name: cwdhist_switching
modifier: shift_alt
keycode: char_o
mode: [emacs, vi_normal, vi_insert]
event: [
{ send: ExecuteHostCommand, cmd: '$env.cwd_history_full = (not $env.cwd_history_full)' }
]
}
}
export def empty-sqlite [] {
# sqlite3 empty.db "VACUUM;"; cat empty.db | gzip | encode base64
'H4sIAAAAAAAAAwsO9MksSVVIyy/KTSxRMGYQYGBkZHBQUGBgYGCEYhhAZhMLGBn0ihbwglgCZOgeBaNgFIyCUTAKRsEoGAWjYBSMglEwCkYBVQAANHgbMAAQAAA='
| decode base64 --binary | gzip -d
}
export def 'cwd history delete' [cwd] {
open $env.cwd_history_file
| query db $"delete from cwd_history where cwd = '($cwd)';"
}
export-env {
$env.cwd_history_full = false
$env.cwd_history_file = '~/.cache/nu_cwd_history.sqlite'
if not ($env.cwd_history_file | path exists) {
empty-sqlite | save -f $env.cwd_history_file
open $env.cwd_history_file | query db "create table if not exists cwd_history (
cwd text primary key,
count int default 1,
recent datetime default (datetime('now', 'localtime'))
);"
}
let __cwdhist_hook = {|_, dir|
if $dir == $nu.home-path { return }
let suffix = (do --ignore-errors { $dir | path relative-to $nu.home-path })
let path = if ($suffix | is-empty) {
$dir
} else {
['~', $suffix] | path join
}
open $env.cwd_history_file
| query db $"
insert into cwd_history\(cwd)
values \('($path)')
on conflict\(cwd)
do update set
count = count + 1,
recent = datetime\('now', 'localtime');"
}
$env.config = ($env.config
| update hooks.env_change.PWD ($env.config.hooks.env_change.PWD | append $__cwdhist_hook ))
$env.config = ($env.config
| upsert menus ($env.config.menus | append (__cwdhist_menu))
| upsert keybindings ($env.config.keybindings | append [(__cwdhist_keybinding) (__cwdhist_switching)])
)
}

View File

@@ -0,0 +1,26 @@
# Function to extract archives with different extensions.
export def extract [name:string] {
let handlers = [ [extension command];
['tar\.bz2|tbz|tbz2' 'tar xvjf']
['tar\.gz|tgz' 'tar xvzf']
['tar\.xz|txz' 'tar xvf']
['tar\.Z' 'tar xvZf']
['bz2' 'bunzip2']
['deb' 'ar x']
['gz' 'gunzip']
['pkg' 'pkgutil --expand']
['rar' 'unrar x']
['tar' 'tar xvf']
['xz' 'xz --decompress']
['zip|war|jar|nupkg' 'unzip']
['Z' 'uncompress']
['7z' '7za x']
]
let maybe_handler = ($handlers | where $name =~ $'\.(($it.extension))$')
if ($maybe_handler | is-empty) {
error make { msg: "unsupported file extension" }
} else {
let handler = ($maybe_handler | first)
nu -c ($handler.command + ' ' + $name)
}
}

View File

@@ -0,0 +1,30 @@
export def "bud img" [] {
buildah images
| from ssv -a
| rename repo tag id created size
| upsert size { |i| $i.size | into filesize }
}
export def "bud ls" [] {
buildah list
| from ssv -a
| rename id builder image-id image container
}
export def "bud ps" [] {
buildah ps
| from ssv -a
| rename id builder image-id image container
}
def "nu-complete bud ps" [] {
bud ps
| select 'CONTAINER ID' "CONTAINER NAME"
| rename value description
}
export def "bud rm" [
id: string@"nu-complete bud ps"
] {
buildah rm $id
}

View File

@@ -0,0 +1,522 @@
export-env {
for c in [nerdctl podman docker] {
if (which $c | is-not-empty) {
$env.docker-cli = $c
break
}
}
}
def --wrapped container [...flag] {
^$env.docker-cli ...$flag
}
def --wrapped with-flag [...flag] {
if ($in | is-empty) { [] } else { [...$flag $in] }
}
def "nu-complete docker ns" [] {
if $env.docker-cli == 'nerdctl' {
^$env.docker-cli namespace list
| from ssv -a
| each {|x| { value: $x.NAMES }}
} else {
[]
}
}
# list containers
export def container-list [
-n: string@"nu-complete docker ns"
container?: string@"nu-complete docker containers"
--all(-a)
] {
let cli = $env.docker-cli
if ($container | is-empty) {
let fmt = '{"id":"{{.ID}}", "image": "{{.Image}}", "name":"{{.Names}}", "cmd":{{.Command}}, "port":"{{.Ports}}", "status":"{{.Status}}", "created":"{{.CreatedAt}}"}'
let fmt = if $cli == 'podman' { $fmt | str replace '{{.Command}}' '"{{.Command}}"' | str replace '{{.CreatedAt}}' '{{.Created}}' } else { $fmt }
let all = if $all {[-a]} else {[]}
^$cli ps ...$all --format $fmt
| lines
| each {|x|
let r = $x | from json
let t = $r.created | into datetime
$r | upsert created $t
}
} else {
let r = ^$cli ...($n | with-flag -n) inspect $container
| from json
| get 0
let image = $r.Image
let img = ^$cli ...($n | with-flag -n) inspect $image
| from json
| get 0
let imgCmd = $img.Config.Cmd?
let imgEnv = $img.Config.Env?
| reduce -f {} {|i, a|
let x = $i | split row '='
$a | upsert $x.0 $x.1?
}
let m = $r.Mounts
| reduce -f {} {|i, a|
if $i.Type == 'bind' {
$a | upsert $i.Source? $i.Destination?
} else { $a }
}
let p = $r.NetworkSettings.Ports? | default {} | transpose k v
| reduce -f {} {|i, a| $a | upsert $i.k $"($i.v.HostIp?.0?):($i.v.HostPort?.0?)"}
{
name: $r.Name?
hostname: $r.Config.Hostname?
id: $r.Id
status: $r.State.Status?
image: $image
created: ($r.Created | into datetime)
ports: $p
env: $imgEnv
mounts: $m
entrypoint: $r.Path?
cmd: $imgCmd
args: $r.Args
}
}
}
def parse-img [] {
let n = $in | split row ':'
let tag = $n.1? | default 'latest'
let repo = $n.0 | split row '/'
let image = $repo | last
let repo = $repo | range 0..-2 | str join '/'
{image: $image, tag: $tag, repo: $repo}
}
# select image
export def image-select [name] {
let n = $name | parse-img
let imgs = (image-list)
let fs = [image tag repo]
for i in 2..0 {
let r = $imgs | filter {|x|
$fs | range 0..$i | all {|y| ($n | get $y) == ($x | get $y) }
}
if ($r | is-not-empty) {
return ($r | sort-by -r created | first | get name)
}
}
$name
}
# list images
export def image-list [
-n: string@"nu-complete docker ns"
image?: string@"nu-complete docker images"
] {
if ($image | is-empty) {
let fmt = '{"id":"{{.ID}}", "repo": "{{.Repository}}", "tag":"{{.Tag}}", "size":"{{.Size}}" "created":"{{.CreatedAt}}"}'
^$env.docker-cli ...($n | with-flag -n) images --format $fmt
| lines
| each {|x|
let x = $x | from json
let img = $x.repo | parse-img
{
name: $"($x.repo):($x.tag)"
id: $x.id
created: ($x.created | into datetime)
size: ($x.size | into filesize)
repo: $img.repo
image: $img.image
tag: $x.tag
}
}
} else {
let r = ^$env.docker-cli ...($n | with-flag -n) inspect $image
| from json
| get 0
let e = $r.Config.Env?
| reduce -f {} {|i, a|
let x = $i | split row '='
$a | upsert $x.0 $x.1?
}
let id = if $env.docker-cli == 'nerdctl' {
$r.RepoDigests.0? | split row ':' | get 1 | str substring 0..12
} else {
$r.Id | str substring 0..12
}
{
id: $id
created: ($r.Created | into datetime)
author: $r.Author
arch: $r.Architecture
os: $r.Os
size: $r.Size
labels: $r.Labels?
user: $r.Config.User?
env: $e
entrypoint: $r.Config.Entrypoint?
cmd: $r.Config.Cmd?
}
}
}
def "nu-complete docker ps" [] {
^$env.docker-cli ps
| from ssv -a
| each {|x| {description: $x.NAMES value: $x.'CONTAINER ID'}}
}
def "nu-complete docker containers" [] {
^$env.docker-cli ps -a
| from ssv -a
| each {|i|
let st = if ($i.STATUS | str starts-with 'Up') { ' ' } else { '!' }
{ id: $i.'CONTAINER ID', name: $i.NAMES, status: $st }
}
| group-by name
| transpose k v
| each {|i|
let s = ($i.v | length) == 1
$i.v | each {|i|
if $s {
{value: $i.name, description: $"($i.status) ($i.id)"}
} else {
{value: $i.id, description: $"($i.status) ($i.name)"}
}
}
}
| flatten
}
# TODO: filter by description
def "nu-complete docker containers b" [] {
^$env.docker-cli ps -a
| from ssv -a
| each {|i|
let s = if ($i.STATUS | str starts-with 'Up') { ' ' } else { '!' }
{ value: $i.'CONTAINER ID', description: $"($s) ($i.NAMES)" }
}
}
def "nu-complete docker images" [] {
^$env.docker-cli images
| from ssv
| each {|x| $"($x.REPOSITORY):($x.TAG)"}
}
# container log
export def container-log [
container: string@"nu-complete docker containers"
-l: int = 100 # line
-n: string@"nu-complete docker ns" # namespace
] {
let l = if $l == 0 { [] } else { [--tail $l] }
^$env.docker-cli ...($n | with-flag -n) logs -f ...$l $container
}
export def container-log-trunc [
container: string@"nu-complete docker containers"
-n: string@"nu-complete docker ns" # namespace
] {
if $env.docker-cli == 'podman' {
print -e $'(ansi yellow)podman(ansi dark_gray) isnt supported(ansi reset)'
} else {
let f = ^$env.docker-cli ...($n | with-flag -n) inspect --format='{{.LogPath}}' $container
truncate -s 0 $f
}
}
# attach container
export def --wrapped container-attach [
container: string@"nu-complete docker containers"
-n: string@"nu-complete docker ns"
...args
] {
let ns = $n | with-flag -n
if ($args|is-empty) {
^$env.docker-cli ...$ns exec -it $container /bin/sh -c "[ -e /bin/zsh ] && /bin/zsh || [ -e /bin/bash ] && /bin/bash || /bin/sh"
} else {
^$env.docker-cli ...$ns exec -it $container ...$args
}
}
def "nu-complete docker cp" [cmd: string, offset: int] {
let argv = $cmd | str substring ..$offset | split row ' '
let p = if ($argv | length) > 2 { $argv | get 2 } else { $argv | get 1 }
let container = ^$env.docker-cli ps
| from ssv -a
| each {|x| {description: $x.'CONTAINER ID' value: $"($x.NAMES):" }}
let n = $p | split row ':'
if $"($n | get 0):" in ($container | get value) {
^$env.docker-cli exec ($n | get 0) sh -c $"ls -dp ($n | get 1)*"
| lines
| each {|x| $"($n | get 0):($x)"}
} else {
let files = do -i {
ls -a ($"($p)*" | into glob)
| each {|x| if $x.type == dir { $"($x.name)/"} else { $x.name }}
}
$files | append $container
}
}
# copy file
export def container-copy-file [
lhs: string@"nu-complete docker cp",
rhs: string@"nu-complete docker cp"
] {
^$env.docker-cli cp $lhs $rhs
}
# remove container
export def container-remove [container: string@"nu-complete docker containers" -n: string@"nu-complete docker ns"] {
let cs = ^$env.docker-cli ...($n | with-flag -n) ps -a | from ssv -a | get NAMES
if $container in $cs {
^$env.docker-cli ...($n | with-flag -n) container rm -f $container
} else {
print -e $"(ansi grey)container (ansi yellow)($container)(ansi grey) not exist(ansi reset)"
}
}
# history
export def container-history [image: string@"nu-complete docker images" -n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) history --no-trunc $image | from ssv -a
}
# save images
export def image-save [-n: string@"nu-complete docker ns" ...image: string@"nu-complete docker images"] {
^$env.docker-cli ...($n | with-flag -n) save ...$image
}
# load images
export def image-load [-n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) load
}
# system prune
export def system-prune [-n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) system prune -f
}
# system prune all
export def system-prune-all [-n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) system prune --all --force --volumes
}
# remove image
export def image-remove [image: string@"nu-complete docker images" -n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) rmi $image
}
# add new tag
export def image-tag [from: string@"nu-complete docker images" to: string -n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) tag $from $to
}
# push image
export def image-push [
image: string@"nu-complete docker images"
--tag(-t): string
-n: string@"nu-complete docker ns" -i
] {
let $insecure = if $i {[--insecure-registry]} else {[]}
if ($tag | is-empty) {
^$env.docker-cli ...($n | with-flag -n) ...$insecure push $image
} else {
^$env.docker-cli ...($n | with-flag -n) tag $image $tag
do -i {
^$env.docker-cli ...($n | with-flag -n) ...$insecure push $tag
}
^$env.docker-cli ...($n | with-flag -n) rmi $tag
}
}
# pull image
export def image-pull [image -n: string@"nu-complete docker ns" -i] {
let $insecure = if $i {[--insecure-registry]} else {[]}
^$env.docker-cli ...($n | with-flag -n) ...$insecure pull $image
}
### list volume
export def volume-list [-n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) volume ls | from ssv -a
}
def "nu-complete docker volume" [] {
^$env.docker-cli volume ls
| from ssv -a
| get 'VOLUME NAME'
}
# create volume
export def volume-create [name: string -n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) volume create $name
}
# inspect volume
export def volume-inspect [name: string@"nu-complete docker volume" -n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) volume inspect $name
}
# remove volume
export def volume-remove [...name: string@"nu-complete docker volume" -n: string@"nu-complete docker ns"] {
^$env.docker-cli ...($n | with-flag -n) volume rm ...$name
}
# dump volume
export def volume-dump [
name: string@"nu-complete docker volume"
--image(-i): string='debian'
-n: string@"nu-complete docker ns"
] {
let id = random chars -l 6
^$env.docker-cli ...($n | with-flag -n) ...[
run --rm
-v $"($name):/tmp/($id)"
$image
sh -c $'cd /tmp/($id); tar -zcf - *'
]
}
# restore volume
export def volume-restore [
name: string@"nu-complete docker volume"
--from(-f): string
--image(-i): string='debian'
-n: string@"nu-complete docker ns"
] {
let id = random chars -l 6
let src = random chars -l 6
^$env.docker-cli ...($n | with-flag -n) ...[
run --rm
-v $"($name):/tmp/($id)"
-v $"(host-path $from):/tmp/($src)"
$image
sh -c $'cd /tmp/($id); tar -zxf /tmp/($src)'
]
}
### run
def "nu-complete docker run vol" [] {
[
$"($env.PWD):/world"
$"($env.PWD):/app"
$"($env.PWD):/srv"
$"($env.HOME)/.config/nvim:/etc/nvim"
]
}
def "nu-complete docker run sshkey" [ctx: string, pos: int] {
(do { cd ~/.ssh; ls **/*.pub } | get name)
}
def "nu-complete docker run proxy" [] {
let hostaddr = do -i { hostname -I | split row ' ' | get 0 }
[ $"http://($hostaddr):7890" $"http://($hostaddr):" ]
}
def host-path [path] {
match ($path | str substring ..1) {
'/' => { $path }
'=' => { $path | str substring 1.. }
'~' => { [ $env.HOME ($path | str substring 2..) ] | path join }
'$' => { $env | get ($path | str substring 1..) }
_ => { [ $env.PWD $path ] | path join }
}
}
# run
export def container-create [
--debug(-x)
--appimage
--netadmin
--proxy: string@"nu-complete docker run proxy" # proxy
--ssh(-s): string@"nu-complete docker run sshkey" # specify ssh key
--sshuser: string=root # default root
--cache(-c): string # cache
--mnt(-m): string@"nu-complete docker run vol" # mnt
--vols(-v): any # { host: container }
--ports(-p): any # { 8080: 80 }
--envs(-e): any # { FOO: BAR }
--daemon(-d)
--attach(-a): string@"nu-complete docker containers" # attach
--workdir(-w): string # workdir
--entrypoint: string # entrypoint
--dry-run
--with-x
--privileged(-P)
--namespace(-n): string@"nu-complete docker ns"
image: string@"nu-complete docker images" # image
...cmd # command args
] {
let ns = $namespace | with-flag -n
let entrypoint = $entrypoint | with-flag --entrypoint
let daemon = if $daemon { [-d] } else { [--rm -it] }
let mnt = $mnt | with-flag -v
let workdir = if ($workdir | is-empty) {[]} else {[-w $workdir -v $"($env.PWD):($workdir)"]}
let vols = if ($vols|is-empty) { [] } else { $vols | transpose k v | each {|x| [-v $"(host-path $x.k):($x.v)"]} | flatten }
let envs = if ($envs|is-empty) { [] } else { $envs | transpose k v | each {|x| [-e $"($x.k)=($x.v)"]} | flatten }
let ports = if ($ports|is-empty) { [] } else { $ports | transpose k v | each {|x| [-p $"($x.k):($x.v)"] } | flatten }
let debug = if $debug {[--cap-add=SYS_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined]} else {[]}
#let appimage = if $appimage {[--device /dev/fuse --security-opt apparmor:unconfined]} else {[]}
let privileged = if $privileged {[--privileged]} else {[]}
let appimage = if $appimage {[--device /dev/fuse]} else {[]}
let netadmin = if $netadmin {[--cap-add=NET_ADMIN --device /dev/net/tun]} else {[]}
let with_x = if $with_x {[
-e $"DISPLAY=($env.DISPLAY)"
-v /tmp/.X11-unix:/tmp/.X11-unix
]} else {[]}
let ssh = if ($ssh|is-empty) { [] } else {
let sshkey = cat ([$env.HOME .ssh $ssh] | path join) | split row ' ' | get 1
[-e $"ed25519_($sshuser)=($sshkey)"]
}
let proxy = if ($proxy|is-empty) { [] } else {
[-e $"http_proxy=($proxy)" -e $"https_proxy=($proxy)"]
}
let attach = if ($attach|is-empty) { [] } else {
let c = $"container:($attach)"
[--uts $c --ipc $c --pid $c --network $c]
}
let cache = $cache | with-flag -v
let args = [
$privileged $entrypoint $attach $daemon
$ports $envs $ssh $proxy
$debug $appimage $netadmin $with_x
$mnt $vols $workdir $cache
] | flatten
let name = $"($image | split row '/' | last | str replace ':' '-')_(date now | format date %m%d%H%M)"
if $dry_run {
echo ([docker $ns run --name $name $args $image $cmd] | flatten | str join ' ')
} else {
^$env.docker-cli ...$ns run --name $name ...$args $image ...($cmd | flatten)
}
}
export alias d = container
export alias dp = container-list
export alias di = image-list
export alias dl = container-log
export alias dlt = container-log-trunc
export alias da = container-attach
export alias dcp = container-copy-file
export alias dcr = container-remove
export alias dh = container-history
export alias dsv = image-save
export alias dld = image-load
export alias dsp = system-prune
export alias dspall = system-prune-all
export alias drmi = image-remove
export alias dt = image-tag
export alias dps = image-push
export alias dpl = image-pull
export alias dvl = volume-list
export alias dvc = volume-create
export alias dvi = volume-inspect
export alias dvr = volume-remove
export alias dr = container-create
export use registry.nu *
export use buildah.nu *

View File

@@ -0,0 +1,68 @@
def "nu-complete registry show" [cmd: string, offset: int] {
let new = $cmd | str ends-with ' '
let cmd = $cmd | split row ' '
let url = $cmd.3?
let reg = $cmd.4?
let tag = $cmd.5?
let auth = if ($env.REGISTRY_TOKEN? | is-not-empty) {
[-H $"Authorization: Basic ($env.REGISTRY_TOKEN)"]
} else {
[]
}
if ($tag | is-empty) and (not $new) or ($reg | is-empty) {
curl -sSL ...$auth $"($url)/v2/_catalog"
| from json | get repositories
} else {
curl -sSL ...$auth $"($url)/v2/($reg)/tags/list"
| from json | get tags
}
}
### docker registry show
export def "docker registry show" [
url: string
reg?: string@"nu-complete registry show"
tag?: string@"nu-complete registry show"
] {
let header = if ($env.REGISTRY_TOKEN? | is-not-empty) {
[-H $"Authorization: Basic ($env.REGISTRY_TOKEN)"]
} else {
[]
}
| append [-H 'Accept: application/vnd.oci.image.manifest.v1+json']
if ($reg | is-empty) {
curl -sSL ...$header $"($url)/v2/_catalog" | from json | get repositories
} else if ($tag | is-empty) {
curl -sSL ...$header $"($url)/v2/($reg)/tags/list" | from json | get tags
} else {
curl -sSL ...$header $"($url)/v2/($reg)/manifests/($tag)" | from json
}
}
### docker registry delete
export def "docker registry delete" [
url: string
reg: string@"nu-complete registry show"
tag: string@"nu-complete registry show"
] {
let header = if ($env.REGISTRY_TOKEN? | is-not-empty) {
[-H $"Authorization: Basic ($env.REGISTRY_TOKEN)"]
} else {
[]
}
| append [-H 'Accept: application/vnd.oci.image.manifest.v1+json']
#| append [-H 'Accept: application/vnd.docker.distribution.manifest.v2+json']
let digest = do -i {
curl -sSI ...$header $"($url)/v2/($reg)/manifests/($tag)"
| rg docker-content-digest
| split row ' '
| get 1
| str trim
}
print -e $digest
if ($digest | is-not-empty) {
curl -sSL -X DELETE ...$header $"($url)/v2/($reg)/manifests/($digest)"
} else {
'not found'
}
}

View File

@@ -0,0 +1,5 @@
# Duplicates Scripts
### Definition
These scripts are used to show how `group-by` can be used to identify duplicate rows. The example shows how that can be used to heuristically find duplicate files.

View File

@@ -0,0 +1,15 @@
# duplicates example
use mod.nu *
let info = "[{name: "John", lastname: "Doe"}, {name: "John", lastname: "Roe"}, {name: "Jane", lastname: "Soe"}]"
print ($info | from json)
print ($info | from json | duplicates name)
#duplicates files example
echo A | save A.txt
echo A | save B.txt
# note that if I used "echo B | save B.txt" the function will give a false positive
echo ABC | save C.txt
print (ls)
print (duplicates files)
rm A.txt B.txt C.txt --permanent

View File

@@ -0,0 +1,22 @@
# duplicates returns the rows that correspond to duplicates of the given column.
export def duplicates [
column: string # Column to look duplicates at
--count(-c) # set it to display the number of times the value is repeated.
] {
group-by {get $column | into string} |
transpose |
insert count { $in.column1 | flatten | length } |
where count > 1 |
reject column0 |
if ($count | is-empty) { reject count } else { each { $in } } |
flatten |
flatten
}
# duplicates files recursively finds duplicate files in the current working folder.
# It uses a heuristic based on duplicate files having the same size.
export def "duplicates files" [] {
do -i {ls **/*} | duplicates size
}

View File

@@ -0,0 +1,127 @@
# simple bookmark module
# Prints general information about bm.
export def main [] {
print -n (help bm)
print (
[
$"(ansi green)Environment(ansi reset):"
$" (ansi cyan)BM_PATH(ansi reset) - path to save bookmarks to with ('add' | nu-highlight). Alternatively searches for (ansi cyan)XDG_DATA_HOME(ansi reset) or (ansi cyan)~/.local/share/(ansi reset)"
] |
str join "\n" |
nu-highlight
)
}
# List all bookmarked paths
export def list [] {
let bm_path = (get_path)
if (not ($bm_path | path exists)) {
[] | save $bm_path
}
open ($bm_path)
}
def os_home [] {
if ($nu.os-info.name == "windows" ) {
($env.USERPROFILE)
} else {
($env.HOME)
}
}
def get_path [] {
$env.BM_PATH? |
default (
$env.XDG_DATA_HOME? |
default (
if $nu.os-info.name == windows {
($env.USERPROFILE? | path join "bm")
} else {
($env.HOME? | path join ".local" "share")
}
)
) |
if (not ($in | path exists)) {
mkdir $in
$in
} else {
$in
}|
path join "bookmarks.nuon"
}
def save_path [] {
$in |
update path { str replace (os_home) '~' } |
save -f (get_path)
}
# Reset the bookmarks
export def reset [] {
list |
where name == "prev" |
save -f (get_path)
}
# Add a new bookmark with an optional name
export def add [
pth: path # Path to bookmark to.
name?: string # Optional name to give to it
] {
if (($pth | path type) == "dir") and ($pth | path exists) {
list |
append {name: ($name), path: ($pth)} |
save_path
}
}
# remove one or more bookmarks
export def remove [] {
let rm_these = (
list |
where name != "prev" |
input list -m
)
list | where {|it|
not $it in $rm_these
} |
print
}
def marks [] {
list | each {|it|
{
value: $it.path,
description: $it.name
}
}
}
# Goto your bookmark
export def --env goto [
pth: path@marks # Path to "go to"
] {
let prev = $env.PWD
cd $pth
change_prev $prev
}
# Experimental use of `input` instead of completion
export def --env goto_alternative [] {
let prev = $env.PWD
list | input list -f | cd $in.path
change_prev $prev
}
def change_prev [new_path: path] {
( list |
where name != "prev"
) |
append {name: prev, path: $new_path} |
save_path
}

View File

@@ -0,0 +1,64 @@
# A bash like quick string manipulation script
# the script works by creating a list from brace contents, separated by a brace.
# Expand the given string into a list on braces like bashes brace expansion
export def main [
input: string # the string to expand.
] {
listify $input
}
def listify [lst] {
try {
($lst
| parse -r '(?P<left>.*)(?<!\\){(?P<list>.*)(?<!\\)}(?P<right>.*)'
| get 0
| upsert list { |l|
$l.list
| split row ","
| str trim
}
| each { |it|
$it.list
| each { |l|
listify $"($it.left)($l)($it.right)"
}})
| flatten
} catch {
$lst
}
}
export def help [] {
print -n ( main -h )
print (
[
$"(ansi green)Examples(ansi reset):"
$" > (ansi light_green)expand (ansi green)a/{b,c}/d(ansi reset)"
$"╭───┬───────╮\n│ 0 │ a/b/d │\n│ 1 │ a/c/d │\n╰───┴───────╯"
$" > (ansi light_green)expand (ansi green)\"my {beautiful,ugly} duckling\"(ansi reset)"
$"╭───┬────────────────────────╮\n│ 0 │ my beautiful duckling │\n│ 1 │ my ugly duckling │\n╰───┴────────────────────────╯"
$" > (ansi light_green)expand (ansi green).config/nushell/config.nu{,on}(ansi reset)"
$"╭───┬─────────────────────────────╮\n│ 0 │ .config/nushell/config.nu │\n│ 1 │ .config/nushell/config.nuon │\n╰───┴─────────────────────────────╯"
$" > (ansi light_green)expand (ansi green)a/{b,c}/{d,e,f,g} (ansi reset)(ansi purple)|(ansi reset)(ansi light_green) each(ansi reset) (ansi light_green){ |d| (ansi reset)(ansi light_green) mkdir(ansi reset) (ansi purple)$d (ansi reset)(ansi light_green)}(ansi reset);(ansi light_green)tree(ansi reset)"
$".
`-- a
|-- b
| |-- d
| |-- e
| |-- f
| `-- g
`-- c
|-- d
|-- e
|-- f
`-- g
12 directories, 0 files"
] |
str join "\n" |
nu-highlight
)
}

View File

@@ -0,0 +1,15 @@
# Fast Node Manager (fnm)
Enables Nushell support for [Fast Node Manager (fnm)](https://github.com/Schniz/fnm), a fast and simple Node.js version manager. Based on [this GitHub issue](https://github.com/Schniz/fnm/issues/463) and [fnm-nushell](https://github.com/Southclaws/fnm-nushell).
Requires `fnm` to be installed separately.
## Install
Clone this repo or copy the `fnm.nu` file wherever your prefer to keep your Nushell scripts.
Edit your Nushell config file (`$nu.config-path`) and add the line:
```nu
use /path/to/fnm.nu
```

View File

@@ -0,0 +1,39 @@
export-env {
def fnm-env [] {
mut env_vars = {}
let pwsh_vars = (
^fnm env --shell power-shell |
lines |
parse "$env:{key} = \"{value}\""
)
# fnm-prefixed vars
for v in ($pwsh_vars | range 1..) {
$env_vars = ($env_vars | insert $v.key $v.value)
}
# path
let env_used_path = ($env | columns | where {str downcase | $in == "path"} | get 0)
let path_value = ($pwsh_vars | get 0.value | split row (char esep))
$env_vars = ($env_vars | insert $env_used_path $path_value)
return $env_vars
}
if not (which fnm | is-empty) {
fnm-env | load-env
if (not ($env | default false __fnm_hooked | get __fnm_hooked)) {
$env.__fnm_hooked = true
$env.config = ($env | default {} config).config
$env.config = ($env.config | default {} hooks)
$env.config = ($env.config | update hooks ($env.config.hooks | default {} env_change))
$env.config = ($env.config | update hooks.env_change ($env.config.hooks.env_change | default [] PWD))
$env.config = ($env.config | update hooks.env_change.PWD ($env.config.hooks.env_change.PWD | append { |before, after|
if ('FNM_DIR' in $env) and ([.nvmrc .node-version] | path exists | any { |it| $it }) {
(^fnm use); (fnm-env | load-env)
}
}))
}
}
}

View File

@@ -0,0 +1,5 @@
# Formatting scripts
### Definition
The scripts in this folder are used to help formatting nicely inputs/outputs of nushell.

View File

@@ -0,0 +1,22 @@
# Convert from contents of /proc/cpuinfo to structured data
export def "from cpuinfo" [] {
lines
| split list ''
| each {
split column ':'
| str trim
| update column1 {
get column1
| str replace -a ' ' '_'
}
| transpose -r -d
| update flags {
get flags
| split row ' '
}
| update bugs {
get bugs
| split row ' '
}
}
}

View File

@@ -0,0 +1,36 @@
# Convert from output of dmidecode to structured data
export def "from dmidecode" [] {
lines
| skip until {|x|
$x starts-with 'Handle'
}
| split list ''
| each {|entry|
let parsed_entry = (
$entry
| get 0
| parse 'Handle {handle}, DMI type {type}, {bytes} bytes'
| get 0
| insert description ($entry|get 1)
| insert values {
if ($entry|length) > 2 {
if ($entry|get 2|str trim) == 'Header and Data:' {
{'header_and_data': ($entry|skip 3|str trim)}
} else {
$entry
| skip 2
| split column ':'
| str trim
| str downcase column1
| str replace -a ' ' '_' column1
| transpose -r -d
}
} else {
{}
}
}
)
$parsed_entry
}
}

View File

@@ -0,0 +1,11 @@
# Converts a .env file into a record
# may be used like this: open .env | load-env
# works with quoted and unquoted .env files
def "from env" []: string -> record {
lines
| split column '#' # remove comments
| get column1
| parse "{key}={value}"
| str trim value -c '"' # unquote values
| transpose -r -d
}

View File

@@ -0,0 +1,45 @@
#diacritics map for Polish but the function is universal provided diacritics_map contains mappings for specific language
# Usage: (remove-diacritics 'Zażółć gęślą jaźń') == Zazolc gesla jazn
export def main [
arg: string
] {
let diacritics_map = {
# Polish
"Ą": "A",
"ą": "a",
"Ć": "C",
"ć": "c",
"Ę": "E",
"ę": "e",
"Ł": "L",
"ł": "l",
"Ń": "N",
"ń": "n",
"Ó": "O",
"ó": "o",
"Ś": "S",
"ś": "s",
"Ż": "Z",
"ż": "z",
"Ź": "Z",
"ź": "z",
# German
"ä": "ae",
"Ä": "Ae",
"ö": "oe",
"Ö": "Oe",
"ü": "ue",
"Ü": "Ue",
"ß": "ss"
}
$arg
|split chars
|each {|char|
$diacritics_map
|get -i -s $char
|default $char
}
|str join ''
}

View File

@@ -0,0 +1,13 @@
# converts records into .ini files
export def "to ini" [] {
transpose key value
| update value {|row|
$row.value
| transpose key value
| format pattern "{key}={value}"
| prepend $"[($row.key)]"
| str join (char nl)
}
| get value
| str join (char nl)
}

View File

@@ -0,0 +1,68 @@
export def number-format [
num # Number to format
--thousands_delim (-t) = ' ' # Thousands delimiter: number-format 1000 -t ': 1'000
--whole_part_length (-w) = 0 # Length of padding whole-part digits: number-format 123 -w 6: 123
--decimal_digits (-d) = 0 # Number of digits after decimal delimiter: number-format 1000.1234 -d 2: 1000.12
--denom (-D) = "" # Denom `--denom "Wt": number-format 1000 --denom 'Wt': 1000Wt
] {
let parts = (
$num
| into string
| split row "."
)
let whole_part = (
$parts.0
| split chars
| reverse
| reduce -f [] {
|it, acc| if ((($it.index + 1) mod 3) == 0) {
$acc.item
| append $it.item
| append $thousands_delim
} else {
$acc.item
| append $it.item
}
}
| reverse
)
let whole_part2 = (
if ($whole_part | first) == $thousands_delim {
($whole_part | skip 1)
} else {
$whole_part
}
| str join ''
)
let whole_part3 = (
if $whole_part_length == 0 {
$whole_part2
} else {
$whole_part2
| fill -w $whole_part_length -c ' ' -a r
}
)
let dec_part = (
if ($parts | length) == 1 {
"0"
} else {
$parts.1
}
)
let dec_part2 = (
if $decimal_digits == 0 {
""
} else {
$".($dec_part)" | fill -w ($decimal_digits + 1) -c '0' -a l
}
)
let out = $"(ansi green)($whole_part3)($dec_part2)(ansi reset)(ansi green_bold)($denom)(ansi reset)"
$out
}

View File

@@ -0,0 +1,75 @@
def alive [x_pos: int, y_pos: int, $grid] {
let width = ($grid | get width)
let height = ($grid | get height)
let data = ($grid | get data)
let $left_x = (if $x_pos == 0 { $width - 1} else { $x_pos - 1})
let $right_x = (if $x_pos == ($width - 1) { 0 } else { $x_pos + 1})
let $up_y = (if $y_pos == 0 { $height - 1} else { $y_pos - 1})
let $down_y = (if $y_pos == ($height - 1) { 0 } else { $y_pos + 1})
let $n = ($data | get ($x_pos + $up_y * $width) | into int)
let $nw = ($data | get ($left_x + $up_y * $width) | into int)
let $w = ($data | get ($left_x + $y_pos * $width) | into int)
let $sw = ($data | get ($left_x + $down_y * $width) | into int)
let $s = ($data | get ($x_pos + $down_y * $width) | into int)
let $se = ($data | get ($right_x + $down_y * $width) | into int)
let $e = ($data | get ($right_x + $y_pos * $width) | into int)
let $ne = ($data | get ($right_x + $up_y * $width) | into int)
let total = $n + $nw + $w + $sw + $s + $se + $e + $ne
let $curr = ($data | get ($x_pos + $y_pos * $width))
if ($total == 3) or ($total == 2 and $curr) {
true
} else {
false
}
}
def generation [$grid] {
let width = ($grid | get width)
let height = ($grid | get height)
let data = ($grid | get data)
let next_generation = (
0..<$height | each {|y|
0..<$width | each {|x|
alive $x $y $grid
}
}
) | flatten
{ width: $width, height : $height, data: $next_generation }
}
def print-grid [$grid] {
$grid.data | flatten | group ($grid | get width) | each {|x|
$x | each {|item|
if $item {
"*"
} else {
"."
}
} | append (char nl) | str join
} | str join ""
}
def main [] {
let width = 15
let height = 15
let data = (0..<($width * $height) | each {
random bool
})
let grid = { width: $width, height : $height, data: $data }
print (print-grid $grid)
1..100 | reduce --fold ($grid) {|it acc|
let next_grid = (generation $acc)
print $"(char -u '1b')[2J" (print-grid $next_grid)
$next_grid
} | ignore
}

View File

@@ -0,0 +1,67 @@
# yay! the nyancat in nushell
# based off this C code https://github.com/klange/nyancat
# each frame has the nyancat with stars flying by and the rainbow waving as it animates
let frame0 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>,,,,,,,,>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,>>&&&&&&&&>>>>>>>>&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,&&++++++++&&&&&&&&'''++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,++++++++++++++++++**''+'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,++++++++++++++++++'**'''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,++########++++++++''**''@$$$$$$-'*************',,,,,,,,,,,,,,,,,###################''**'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,####################''''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,##========########====''@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,======================='@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,==;;;;;;;;.=======;;;;'''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''''',,,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;'**'','*',,,,,'*','**',,,,,,,,,,,,,,,,,,,,,;;,,,,,.,,;;;.;;;;,,,'''',,'',,,,,,,'',,'',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame1 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>,,,,,,,,>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,>>&&&&&&&&>>>>>>>>&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,&&++++++++&&&&&&&&+++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,+++++++++++++++++++'+++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,++++++++++++++++++'*'++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,++########++++++++'*''''@$$$$$$-$'*************',,,,,,,,,,,,,,,,###################****'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,###################''**'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,##========########==='''@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,======================='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,==;;;;;;;;========;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;'**','*',,,,,,**','**',,,,,,,,,,,,,,,,,,,,;;,,,.,,,,;;;;;;;;,,,,''',,,'',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame2 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.>>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,&&>>>>>>>&&&&&&&&>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,++&&&&&&&++++++++&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,##+++++++########++++++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,######################''@$$$$$$-$'*************',,,,,,,,,,,,,,,,###################'''''@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,==#######========#'****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,==================='''='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,;;=======;;;;;;;;======'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,;.;;;;;;;;;;;;;;;;;;;;;'*'''''''''''''''''''',,,,,,,,,,,,,,,,,,,.,.;;;;;;,,,,,,,,;;;;;;'**',**',,,,,,**','**',,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame3 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,>>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,&&>>>>>>>&&&&&&&&>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,++&&&&&&&++++++++&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,##+++++++########++++++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,#####################'''@$$$$$$-$'*************',,,,,,,,,,,,,,,,###################''**'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,==#######========##****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,=================='*'=='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,;;=======;;;;;;;;=='==='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,;;;;;;;,,,,,,,,;;;;;'**','*',,,,,,'*','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,'',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame4 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,>>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>&&&&&&&&>>>>>>>>&&&&&'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,&&++++++++&&&&&&&&+++++'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,++++++++++++++++++'''++'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,++########+++++++'**''''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,#################'****''@$$$$$$-'*************',,,,,,,,,,,,,,,,,##################''''*'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,##========########==='''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,======================='@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,==;;;;;;;;========;;;;''@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;''''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;'***'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,;;,,,,,,,,;;;;;;;;,,'**','**,,,,,,'**,'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,'',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame5 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>&&&&&&&&>>>>>>>>&&&&&'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$''$$$@@','',,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$'**'-$$@''**',,,,,,,,,,,,,,,,,,&&++++++++&&&&&&&&+++++'@$$$$$$$$'***$$$@'***',,,,,,,,,,,,,,,,,,+++++++++++++++++++'+++'@$$$$$-$$'***''''****',,,,,,,,,,,,,,,,,,++++++++++++++++++'*'++'@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,++########++++++++'*''''@$$$$$$$'*************',,,,,,,,,,,,,,,,,###################****'@$$$$$$-'***.'****.'**',,,,,,,,,,,,,,,,,###################''**'@$-$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,##========########==='''@$$$$$$$'*%%********%%',,,,,,,,,,,,,,,,,======================='@@$$$-$$$'***''''''**',,,,,,,,,,,,,,,,,,==;;;;;;;;========;;;;''@@@$$$$$$$'*********',,,,,,,,,,,,,,,,,,.;;;;;;;;;;;;;;;;;;;;;'*''@@@@@@@@@@''''''''',,,,,,,,,,,,,,,,,,,.;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''*',,,,,,,,,,,,,,,,,,,,,,;;,,,,,,,,;;;;;;;;,,'**','**,,,,,,'**,'**',,,,,,,,,,,,,,,,,,..,.,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame6 = ".,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>,,,,,,,>>>>>>>>,,,,,,,'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&>>>>>>>&&&&&&&&>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,++&&&&&&&++++++++&'''&&'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,++++++++++++++++++'*''+'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,++++++++++++++++++'**'''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,##+++++++########++'**''@$$$$$$-'*************',,,,,,,,,,,,,,,,,###################''**'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,####################''''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,==#######========#####''@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,======================='@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,;;=======;;;;;;;;====='''@@@@@@@@@'*********',,,,,,,,,,,.,,,,,,,;;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''''',,,,,,,,,,.,,,.,,,,,;;;;;;;;;;;;;;;;;;;;;'**'','*',,,,,'**,'**',,,,,,,,,,,,,,,,,,,,,,,;;;;;;;,,,,,,,,;;;;'''',,'',,,,,,,'',,'',,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame7 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>,,,,,,,>>>>>>>>,,,,,,,'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&>>>>>>>&&&&&&&&>>>>>>'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,++&&&&&&&++++++++&&&&&&'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,+++++++++++++++++++'+++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,++++++++++++++++++'*'++'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,##+++++++########+'*''''@$$$$$$-$'*************',,,,,,,,,,,,,,,,###################****'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,###################''**'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,==#######========####'''@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,======================='@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,;;=======;;;;;;;;======''@@@@@@@@@@'*********',,,.,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;'**','*',,,,,,**','**',,,,,,,,,,,,,,,,,,,,,,;;;;;;;,,,,,,,,;;;;;''',,,'',,,,,,''',,''',,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame8 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..,...,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>&&&&&&&&>>>>>>>>&&&&&'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,&&++++++++&&&&&&&&+++++'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,++########++++++++#####'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,######################''@$$$$$$-$'*************',,,,,,,,,,,,,,,,###################'''''@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,##========########'****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,==================='''='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,==;;;;;;;;========;;;;;'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;'*'''''''''''''''''''',,,,,,,,,,,,,,,,,,,;;,,,,,,,,;;;;;;;;,,,,,'**',**',,,,,,**'.'**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,"
let frame9 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>,,,,,,,,>>>>>>>''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,>>&&&&&&&&>>>>>>>>&&&&&'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$$''-$$@',,'',,,,,,,,,,,,,,,,,,&&++++++++&&&&&&&&+++++'@$$$$$$$$$'**'$$@','**',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$-$$$'***$$@''***',,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,++########++++++++#####'@$$$$$$$$$'***********',,,,,,,,,,,,,,,,,#####################'''@$$$$$$-$'*************',,,,,,,,,,,,,,,,###################''**'@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,##========########=****'@$$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,=================='*'=='@@$$$-$$$'*%%********%%',,,,,,,,,,,,,,,,==;;;;;;;;========;';;;'@@@$$$$$$$'***''''''**',,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;''@@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;'**'''''''''''''''''''',,,,,,,,,,,,,,,,,,,;;,,,,,,,,;;;;;;;;,,,,'**','*',,..,.**','**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,.,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,"
let frame10 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,&&>>>>>>>&&&&&&&&>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$-$$$$@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$$''$-$$@','',,,,,,,,,,,,,,,,,,,++&&&&&&&++++++++&&&&&&'@$$$$$$$$'**'$$$@''**',,,,,,,,,,,,,,,,,,+++++++++++++++++++++++'@$$$$$-$$'***$$$@'***',,,,,,,,,,,,,,,,,,++++++++++++++++++'''++'@$$$$$$$$'***''''****',,,,,,,,,,,,,,,,,,##+++++++########'**''''@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,#################'****''@$$$$$$-'*************',,,,,,,,,,,,,,,,,##################''''*'@$-$$$$$'***.'****.'**',,,,,,,,,,,,,,,,,==#######========####'''@$$$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,======================='@@$$$-$$'*%%********%%',,,,,,,,,,,,,,,,,;;=======;;;;;;;;=====''@@@$$$$$$'***''''''**',,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;''''@@@@@@@@@'*********',,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;'***'''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,;;;;;;;,,,,,,,,;;;'**'.'**..,,,,'**''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''',,,'',,,,,,,''',''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
let frame11 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>>,,,,,,,>>>>>>>>,,,,,,,,''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,>>>>>>>>>>>>>>>>>>>>>>>>'@@@@@@@@@@@@@@@',,,,,,,,,,,,,,,,,,,,,,,&&>>>>>>>&&&&&&&&>>>>>>'@@@$$$$$$$$$$$@@@',,,,,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@@$$$$$-$$''$$$@@','',,,,,,,,,,,,,,,,,,,&&&&&&&&&&&&&&&&&&&&&&&'@$$-$$$$$'**'-$$@''**',,,,,,,,,,,,,,,,,,++&&&&&&&++++++++&&&&&&'@$$$$$$$$'***$$$@'***',,,,,,,,,,,,,,,,,,+++++++++++++++++++'+++'@$$$$$-$$'***''''****',,,,,,,,,,,,,,,,,,++++++++++++++++++'*'++'@$$$$$$$$'***********',,,,,,,,,,,,,,,,,,##+++++++########+'*''''@$$$$$$$'*************',,,,,,,,,,,,,,,,,###################****'@$$$$$$-'***.'****.'**',,,,,,,,,,,,,,,,,###################''**'@$-$$$$$'***''**'*''**',,,,,,,,,,,,,,,,,==#######========####'''@$$$$$$$'*%%********%%',,,,,,,,,,,,,,,,,======================='@@$$$-$$$'***''''''**',,,,,,,,,,,,,,,,,,;;=======;;;;;;;;=.===''@@@$$$$$$$'*********',,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;.'*''@@@@@@@@@@''''''''',,,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;'***''''''''''''''''*',,,,,,,,,,,,,,,,,,,,,,,,;;;;;;;,,,,,,,.;;;'**','**,,,,,,'**''**',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,''',,''',,,,,,''',,''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
# this is how to map characters to colors
let map = [[symbol color description];
[',' '48;5;17m' Blue_background]
[. '48;5;231m' White_stars]
['\' '48;5;16m' Black_border]
['@' '48;5;230m' Tan_poptart]
['$' '48;5;175m' Pink_poptart]
['-' '48;5;162m' Red_poptart]
['>' '48;5;196m' Red_rainbow]
['&' '48;5;214m' Orange_rainbow]
['+' '48;5;226m' Yellow_Rainbow]
['#' '48;5;118m' Green_rainbow]
['=' '48;5;33m' Light_blue_rainbow]
[';' '48;5;19m' Dark_blue_rainbow]
['*' '48;5;240m' Gray_cat_face]
['%' '48;5;175m' Pink_cheeks]
["'" '48;5;175m' single_quote]
]
# setup the frames and order we want to draw them
let frames = [
$frame0
$frame1
$frame2
$frame3
$frame4
$frame5
$frame6
$frame7
$frame8
$frame9
$frame10
$frame11
]
# let's animate
# make sure you have your font small like 10 or 12 pt and screen maximized.
# you may need to play with the font size to get it working right
# it's a little slow - maybe 1 fps but still firmly in the 'fun' category
print (ansi cursor_off)
for frame in $frames {
let frame = (echo $frame | split chars | enumerate | each {|char| if $char.index mod 64 == 0 { $"(ansi -e '0m')(char nl)" } else {$"(ansi -e ($map | where symbol == $char.item | get color | get 0))(char sp)"}} | append (ansi -e '0m') | str join)
clear
print $frame
}
print (ansi cursor_on)

View File

@@ -0,0 +1,127 @@
# i found this script on a github issue and wanted to see what nushell would do.
# https://github.com/microsoft/terminal/issues/11794
#########################################################
# here's the python version from that issue
#########################################################
# import math
# import os
# import sys
# size = os.popen('stty size', 'r').read().split()
# h,w = tuple(int(n) for n in size)
# mx = w//2
# my = h//2
# def frame(i):
# s = '\033[H'
# for y in range(h):
# for x in range(w):
# dy,dx = y-my,x-mx
# a = math.atan2(dy*2,dx) + math.pi
# c = (int(a/math.pi*127)+i)%256
# s += '\033[38;2;%d;%d;%dm*' % (c,c,c)
# return s
# sys.stdout.write('Generating content...\n')
# s = '\033[?25l'
# for i in range(512):
# s += frame(i)
# s += '\033[?25h\033[m\033[H'
# sys.stdout.write('Starting animation...\n')
# sys.stdout.write(s)
#########################################################
# here's the c version from that issue
#########################################################
# #include <windows.h>
# #include <string>
# #include <cmath>
# void main()
# {
# HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
# DWORD mode;
# GetConsoleMode(handle, &mode);
# mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
# SetConsoleMode(handle, mode);
# CONSOLE_SCREEN_BUFFER_INFOEX csbie;
# csbie.cbSize = sizeof(csbie);
# GetConsoleScreenBufferInfoEx(handle, &csbie);
# const auto w = csbie.dwSize.X;
# const auto h = csbie.srWindow.Bottom - csbie.srWindow.Top + 1;
# const auto mx = w/2;
# const auto my = h/2;
# const auto pi = 3.14159265358979323846;
# printf("Generating content...\n");
# std::string s = "\033[?25l";
# for (auto i = 0; i < 512; i++) {
# s += "\033[H";
# for (auto y = 0; y < h; y++) {
# for (auto x = 0; x < w; x++) {
# auto dy = y-my;
# auto dx = x-mx;
# auto a = std::atan2(dy*2,dx) + pi;
# auto c = std::to_string((int(a/pi*127)+i)%256);
# s += "\033[38;2;"+c+";"+c+";"+c+"m*";
# }
# }
# }
# s += "\033[?25h\033[m\033[H";
# printf("Starting animation...\n");
# DWORD written = 0;
# WriteConsoleA(handle, s.c_str(), s.length(), &written, NULL);
# }
use std math
def atan2 [y x] {
if $x > 0 {
$y / $x | math arctan
} else if $x < 0 {
if $y >= 0 {
$math.PI + ($y / $x | math arctan)
} else {
-1 * $math.PI + ($y / $x | math arctan)
}
} else {
if $y >= 0 {
$math.PI / 2
} else {
-1 * $math.PI / 2
}
}
}
let w = 50
let h = 20
# if it's fast for your, change w, h to the below lines
# let w = (term size).columns - 2
# let h = (term size).rows - 2
let mx = ($w / 2 | math floor)
let my = ($h / 2 | math floor)
print (ansi -e "?25l")
for i in 0..512 {
let rows = (0..($h) | each {|y|
let cols = (0..($w) | each {|x|
let dy = ($y - $my)
let dx = ($x - $mx)
let a = (atan2 ($dy * 2) $dx) + $math.PI
let c = ((($a / ($math.PI) * 127) + ($i)) mod 256 | math round)
$"(ansi -e '38;2;')($c);($c);($c)m*"
})
$cols | str join
})
print ((ansi -e 'H') + ($rows | str join (char nl)))
}
print $"(ansi -e '?25h')(ansi -e 'm')(ansi -e 'H')"

View File

@@ -0,0 +1,55 @@
# A Terminal Wordle game.
# The code is based on https://gist.github.com/huytd/6a1a6a7b34a0d0abcac00b47e3d01513 ,but slightly personalized.
# a simple termninal Wordle game!
export def main [
--unlimited(-u) # Play the game in unlimited mode.
--max_count(-M) : int = 6 # Give yourself more chances than default
--alternative_source(-a) : string = "https://raw.githubusercontent.com/charlesreid1/five-letter-words/master/sgb-words.txt" # Alternative link to provide as a word source
] {
let words = (if ($alternative_source | str substring 0..4 | str contains "http") {http get $alternative_source} else {open $alternative_source} | from ssv -n)
let word = ($words | get (random int 0..($words | length)) | get column1)
if ((($words | each {|it| ($it.column1 | str length)}) | where $it != 5 | length) != 0 ) {
echo $"(ansi rb)Warning:(ansi reset) The words list contains words that are not length 5"
}
mut end = false
mut guess_count = 0
mut avail = "abcdefghijklmnopqrstuvyxwz"
while (not ($end)) {
$guess_count += 1
if ($guess_count <= $max_count or $unlimited) {
echo $"(ansi xterm_aquamarine1a)Enter your guess (ansi reset)\((ansi green)($guess_count)(ansi reset)/(ansi yellow)(if ($unlimited) {inf} else {$max_count})(ansi reset)\)"
mut guess = (input | str downcase )
if (((($words | where column1 =~ $guess) | length) >= 1) and ($guess | str length) == 5) {
mut out = ""
mut checked = $word
for i in ($guess | split chars) -n {
if ($i.item == ($word | str substring ($i.index)..($i.index + 1)) ) {
$out += $"(ansi green_reverse)($i.item)(ansi reset)"
$avail = ($avail | str replace $i.item $"(ansi green_reverse)($i.item)(ansi white_reverse)")
$checked = ($checked | str replace $i.item "")
} else if ( $i.item in $checked) {
$out += $"(ansi yellow_reverse)($i.item)(ansi reset)"
$avail = ($avail | str replace $i.item $"(ansi yellow_reverse)($i.item)(ansi white_reverse)")
$checked = ($checked | str replace $i.item "")
} else {
$out += $"(ansi white_reverse)($i.item)(ansi reset)"
$avail = ($avail | str replace $i.item "")
}
}
$avail = $"(ansi white_reverse)($avail)(ansi reset)"
echo $"($out) possible -> ($avail)"
if ($guess == $word) {
$end = true
echo $"(ansi xterm_green1 )You guessed right!(ansi reset)"
}
} else {
echo "please enter a valid [5 letter] word!"
$guess_count -= 1
}
} else {
echo $"(ansi yellow )You loose, the word was: (ansi red)($word)(ansi reset)"
$end = true
}
}
}

View File

@@ -0,0 +1,28 @@
# Fuzzy all the things
### Purpose
This contains a few scripts that add fuzzy search interfaces to built-in nu functionalities. Often you
want to search commands/your history interactively, which is where [fzf](https://github.com/junegunn/fzf) excels at.
### How to use
`./fuzzy_history_search.nu` searches your command history and, after pressing `enter`, copies the selected command into the clipboard
`./fuzzy_command_search.nu` searches both commands and subcommands for both a) names and b) their description, and, after pressing `enter`, copies the selected command into the clipboard
To use them in your day-to-day workflow, add
```
source <absolute-path-to-nu_scripts>/fuzzy/fuzzy_history_search.nu
source <absolute-path-to-nu_scripts>/fuzzy/fuzzy_command_search.nu
```
to your `config.nu`
It's likely a good idea to also add some short and sweet aliases, e.g.
```
alias hi = fuzzy-history-search
alias hf = fuzzy-command-search
```

View File

@@ -0,0 +1,25 @@
const tablen = 8
# calculate required tabs/spaces to get a nicely aligned table
def pad-tabs [input_name max_indent] {
let input_length = ($input_name | str length)
let required_tabs = $max_indent - ($input_length / $tablen | into int)
seq 0 $required_tabs | reduce -f "" {|it, acc| $acc + (char tab)}
}
# fuzzy search a) commands b) subcommands
# on selection, will display `help` for the commands
# and paste command into clipboard for you to paste right away
export def fuzzy-command-search [] {
let max_len = (help commands | each { $in.name | str length } | math max)
let max_indent = ($max_len / $tablen | into int)
let command = ((help commands | each {|it|
let name = ($it.name | str trim | ansi strip)
$"($name)(pad-tabs $name $max_indent)($it.usage)"
}) | str join (char nl) | fzf | split column (char tab) | get column1.0)
if ($command | is-not-empty) {
help $command
}
}

View File

@@ -0,0 +1 @@
export def fuzzy-history-search [] { cat $nu.history-path | fzf | clip }

View File

@@ -0,0 +1,14 @@
# Git Scripts
### Definition
These scripts should be used to demonstrate how combine the power of nushell with git commands.
### Aliases
If you find some of these scripts useful you can add them as aliases in your git config file.
For instance you can create a nushell script in your computer and define in your git config file an alias that call that script:
```
[alias]
bcl = !nu \"D:\\Tools\\gitalias_bcl.nu\"
```

View File

@@ -0,0 +1,146 @@
export def _git_stat [n] {
do -i {
git log -n $n --pretty=»¦«%h --stat
| lines
| reduce -f { c: '', r: [] } {|it, acc|
if ($it | str starts-with '»¦«') {
$acc | upsert c ($it | str substring 6.. )
} else if ($it | find -r '[0-9]+ file.+change' | is-empty) {
$acc
} else {
let x = (
$it
| split row ','
| each {|x| $x
| str trim
| parse -r "(?P<num>[0-9]+) (?P<col>.+)"
| get 0
}
| reduce -f {sha: $acc.c file:0 ins:0 del:0} {|i,a|
let col = if ($i.col | str starts-with 'file') {
'file'
} else {
$i.col | str substring ..3
}
let num = ($i.num | into int)
$a | upsert $col $num
}
)
$acc | upsert r ($acc.r | append $x)
}
}
| get r
}
}
export def _git_log [v num] {
let stat = if $v {
_git_stat $num
} else { {} }
let r = (do -i {
git log -n $num --pretty=%h»¦«%s»¦«%aN»¦«%aE»¦«%aD
| lines
| split column "»¦«" sha message author email date
| each {|x| ($x| upsert date ($x.date | into datetime))}
})
if $v {
$r | merge $stat | reverse
} else {
$r | reverse
}
}
def "nu-complete git log" [] {
git log -n 32 --pretty=%h»¦«%s
| lines
| split column "»¦«" value description
| each {|x| $x | update value $"($x.value)"}
}
def "nu-complete git branches" [] {
git branch
| lines
| filter {|x| not ($x | str starts-with '*')}
| each {|x| $"($x|str trim)"}
}
export def gl [
commit?: string@"nu-complete git log"
--verbose(-v)
--num(-n):int=32
] {
if ($commit|is-empty) {
_git_log $verbose $num
} else {
git log --stat -p -n 1 $commit
}
}
export def glv [
commit?: string@"nu-complete git log"
--num(-n):int=32
] {
if ($commit|is-empty) {
_git_log true $num
} else {
git log --stat -p -n 1 $commit
}
}
export def gco [branch: string@"nu-complete git branches"] {
git checkout $branch
}
export def gbD [branch: string@"nu-complete git branches"] {
git branch -D $branch
}
export def gpp! [] {
git pull
git add --all
git commit -v -a --no-edit --amend
git push --force
}
export def gha [] {
git log --pretty=%h»¦«%aN»¦«%s»¦«%aD
| lines
| split column "»¦«" sha1 committer desc merged_at
| histogram committer merger
| sort-by merger
| reverse
}
export def gsq [] {
git reflog expire --all --expire=now
git gc --prune=now --aggressive
}
def "nu-complete git remotes" [] {
^git remote | lines | each { |line| $line | str trim }
}
export def gr [remote?: string@"nu-complete git remotes"] {
let remote = if ($remote|is-empty) { 'origin' } else { $remote }
git remote show $remote
}
export def grh [commit: string@"nu-complete git log"] {
git reset $commit
}
export def gf [
branch: string@"nu-complete git branches"
remote?: string@"nu-complete git remotes"
] {
let remote = if ($remote|is-empty) { 'origin' } else { $remote }
git fetch $remote $branch
}
export def gm [branch:string@"nu-complete git branches"] {
git merge $branch
}
export def grb [branch:string@"nu-complete git branches"] {
git rebase (gstat).branch $branch
}

View File

@@ -0,0 +1,15 @@
# Creates a table listing the branches of a git repository and the day of the last commit
export def "git age" [] {
git branch |
lines |
str substring 2.. |
wrap name |
insert last_commit {
get name |
each {
git show $in --no-patch --format=%as | into datetime
}
} |
sort-by last_commit
}

View File

@@ -0,0 +1,22 @@
# Git branch cleanup
Remove any local git branches that have been merged and optionally remove any
remote branches that have been merged.
Load with:
```nushell
source modules/git/git_branch_cleanup.nu
```
To remove merged branches:
```nushell
git branch-cleanup
```
To keep merged branches that start with "releases/":
```nushell
git config --local --add branch-cleanup.keep 'releases/.*'
```
Keep branch patterns are space-separated

View File

@@ -0,0 +1,171 @@
# Adapted from original by Yorick Sijsling
#
# Adapted from bash version `git cleanup-repo` by Rob Miller <rob@bigfish.co.uk>
# https://gist.github.com/robmiller/5133264
# Delete local (and optionally remote) merged branches
#
# Set branch-cleanup.keep locally to a space-separated list of branch patterns to keep
export def "git branch-cleanup" [
upstream: string@remotes = "origin" # Upstream remote repository
] {
let current_branch = current_branch
let default_branch = get_default_branch $"refs/remotes/($upstream)/HEAD"
let keep = get_keep
# Switch to the default branch
switch_branch $default_branch
# Make sure we're working with the most up-to-date version of the default
# branch.
run-external "git" "fetch"
# Prune obsolete remote tracking branches. These are branches that we
# once tracked, but have since been deleted on the remote.
run-external "git" "remote" "prune" $upstream
# Delete local branches that have been fully merged into the default branch
list_merged $upstream $default_branch $keep
| each {|branch|
delete_local $branch
}
# Again with remote branches
let merged_on_remote = list_merged --remote $upstream $default_branch $keep
if not ( $merged_on_remote | is-empty ) {
print "The following remote branches are fully merged and will be removed:"
$merged_on_remote
| each {||
print $"\t($in)"
}
print ""
if ( input --suppress-output "Continue (y/N)? " | str trim ) == "y" {
$merged_on_remote
| each {|branch|
delete_remote $upstream $branch
}
}
}
switch_branch $current_branch
}
# The current branch name
def current_branch [] {
run-external "git" "branch" "--show-current"
| into string
| str trim
}
# Delete a local branch
def delete_local [
branch: string # Branch to delete
] {
run-external "git" "branch" "--delete" $branch
}
# Delete a remote branch
def delete_remote [
upstream: string # Repository to delete from
branch: string # branch to delete
] {
run-external "git" "push" "--quiet" "--delete" $upstream $branch
}
# Get the default branch
def get_default_branch [
upstream: string # Repository to get the upstream branch name from
] {
let args = [
"--short"
$upstream
]
run-external "git" "symbolic-ref" ...$args
| str trim
| path basename
}
# Get the local set of branches to always keep
def get_keep [] {
let keep = run-external "git" "config" "--local" "--get" "branch-cleanup.keep"
if ( $keep | is-empty ) {
return []
}
$keep
| str trim
| split column " "
| get column1
}
# List all the branches that have been merged fully into the default branch.
#
# We use the remote default branch here, just in case our local default branch is out of date.
def list_merged [
--remote # List remote branches (local default)
upstream: string # Upstream repository
branch: string # Default branch
keep: list<string> # Patterns to keep. The default branch and HEAD will be added
] {
mut args = [
"--list"
"--merged" $"($upstream)/($branch)"
]
if $remote {
$args = ( $args | append [
"--format" "%(refname:lstrip=3)"
"--remote"
])
} else {
$args = ( $args | append [
"--format" "%(refname:lstrip=2)"
])
}
let args = $args
let keep = (
$keep
| append [
"HEAD",
$branch,
]
)
run-external "git" "branch" ...$args
| lines
| filter {|branch|
$keep
| all {|pattern|
$branch !~ $'\A($pattern)\z'
}
}
}
def remotes [] {
run-external "git" "remote" "-v"
| parse "{value}\t{description} ({operation})"
| select value description
| uniq
| sort
}
# Switch to a different branch
def switch_branch [
branch: string
] {
let args = [
"--quiet"
"--no-guess"
$branch
]
run-external "git" "switch" ...$args
}

View File

@@ -0,0 +1,89 @@
Consider putting related commands together, such as `push` and `pull`,
to decide how to execute based on the current environment or specified parameters.
This mode is more convenient,
but more difficult to implement in traditional shells such as zsh.
In nushell it's very easy.
In this way, the commands that need to be memorized will be greatly reduced,
and the parameters can be automatically completed.
In the most common scenarios, it is even possible to omit the parameter.
In contrast, the behavior of commands requires fine-tuning to be intuitive.
(there may still be some unreasonable places that need to be adjusted)
I tried to tidy part of it, and it is basically usable.
(The goal is to organize all aliases to where they should go)
### gs
Git status and stash.
### gl
Git log and show.
### gb
About the branch.
Create branch if it doesn't exist,
switch otherwise (branch are automatically completed),
use -d to delete.
If there is no branch as an argument, the branch is displayed.
### gp
Pull, push and other related to remote repositories
> We assume that the upstream and downstream branches keep the same name and do not operate across branches.
- `--clone` to clone
- `--submodule` submodule update and submodule init (with `--init`)
- `--force` push --force (assume `pull --force` doesn't make sense)
- `--init` git init
- `--override` just used to trigger a github actions event (in fact, webhooks can also be used)
- `--set-upstream` push --set-upstream
- if branch is specified, it is `git fetch` (let's assume you don't like pulling from a different branch)
- finally, if no branch and above parameters are specified
- `git pull` to update.
- if `ahead`, `git push` will be executed.
### ga
Git add, rm and restore. about files.
Use `ga` because git add has the highest execution frequency,
and `ga` is the most convenient input.
- `--delete` git rm
- `--restore` git restore
- git add
### gc
Git commit
### gd
Git diff
### gm
Git merge and rebase
- `--rebase` git rebase
- git merge
### gcp
Git cherry-pick
### gr
Git reset
### grmt
Git remote
### gbs
Git bisect
## changelog
#### 2023-05-18
- `gp -u` can omit branch
- delete `grb`
- improve the premise in the description

View File

@@ -0,0 +1,689 @@
use argx
def agree [
prompt
--default-not (-n)
] {
let prompt = if ($prompt | str ends-with '!') {
$'(ansi red)($prompt)(ansi reset)'
} else {
$'($prompt)'
}
(if $default_not { [no yes] } else { [yes no] } | input list $prompt) == 'yes'
}
def tips [ msg ] {
print -e $"(ansi light_gray)($msg)(ansi reset)"
}
def --wrapped with-flag [...flag] {
if ($in | is-empty) { [] } else { [...$flag $in] }
}
# git status
export def gs [] {
git status
}
# git stash
export def gst [
--apply (-a)
--clear (-c)
--drop (-d)
--list (-l)
--pop (-p)
--show (-s)
--all (-A)
--include-untracked (-i)
] {
if $apply {
git stash apply
} else if $clear {
git stash clear
} else if $drop {
git stash drop
} else if $list {
git stash list
} else if $pop {
git stash pop
} else if $show {
git stash show --text
} else if $all {
git stash --all ...(if $include_untracked {[--include-untracked]} else {[]})
} else {
git stash
}
}
# git log
export def gl [
commit?: string@"nu-complete git log"
--verbose(-v)
--num(-n):int=32
] {
if ($commit|is-empty) {
_git_log $verbose $num
} else {
git log --stat -p -n 1 $commit
}
}
# git branch
export def gb [
branch?: string@"nu-complete git branches"
--remote (-r)='origin': string@"nu-complete git remotes"
--delete (-d)
--no-merged (-n)
] {
let bs = git branch | lines | each {|x| $x | str substring 2..}
if $delete {
let remote_branches = (remote_branches)
if ($branch | is-empty) {
let dels = if $no_merged { gb } else {
gb
| where { $in.merged | is-not-empty }
}
| where { ($in.remote | is-empty) and ($in.current | is-empty) }
| each {|x|
let pf = if ($x.current | is-empty) { " " } else { $"(ansi cyan)* " }
let nm = if ($x.merged | is-not-empty ) { $"(ansi green)" } else { " " }
$x | insert display $"($nm)($pf)(ansi reset)($x.branch)"
}
if ($dels | is-empty) {
tips "no branches to delete"
return
}
let $dels = $dels
| input list -d display --multi
| get branch
for b in $dels {
tips $"delete (ansi yellow)($b)"
git branch -D $b
}
if ($dels | is-not-empty) and (agree 'delete remote branch?!') {
for b in ($dels | filter { $"($remote)/($in)" in $remote_branches }) {
tips $"delete (ansi yellow)($remote)/($b)"
git branch -D -r $'($remote)/($b)'
git push $remote -d $b
}
}
} else {
if $branch in $bs and (agree 'branch will be delete!') {
git branch -D $branch
}
if $"($remote)/($branch)" in $remote_branches and (agree 'delete remote branch?!') {
git branch -D -r $'($remote)/($branch)'
git push $remote -d $branch
}
}
} else if ($branch | is-empty) {
let merged = git branch --merged
| lines
| each { $in | parse -r '\s*\*?\s*(?<b>[^\s]+)' | get 0.b }
{
local: (git branch)
remote: (git branch --remote)
}
| transpose k v
| each {|x|
$x.v | lines
| each {|n|
let n = $n | parse -r '\s*(?<c>\*)?\s*(?<b>[^\s]+)( -> )?(?<r>[^\s]+)?' | get 0
let c = if ($n.c | is-empty) { null } else { true }
let r = if ($n.r | is-empty) { null } else { $n.r }
let m = if $n.b in $merged { true } else { null }
let rm = if $x.k == 'remote' { true } else { null }
{ current: $c, remote: $rm, branch: $n.b, ref: $r, merged: $m }
}
}
| flatten
} else if $branch in $bs {
git checkout $branch
} else {
if (agree 'create new branch?') {
git checkout -b $branch
}
}
}
# git clone, init
export def --env gn [
repo?: string@"nu-complete git branches"
local?: path
--submodule (-s) # git submodule
--init (-i) # git init
] {
if $init {
if ($repo | is-empty) {
git init --initial-branch main
} else {
git init $repo --initial-branch main
cd $repo
}
if $submodule {
git submodule init
}
} else {
let local = if ($local | is-empty) {
$repo | path basename | split row '.' | get 0
} else {
$local
}
git clone ...(if $submodule {[--recurse-submodules]} else {[]}) $repo $local
cd $local
}
}
# edit .gitignore
export def gig [--empty-dir] {
if $empty_dir {
[
'# Ignore everything in this directory'
'*'
'# Except this file'
'!.gitignore'
] | str join (char newline) | save .gitignore
} else {
^$env.EDITOR $"(git rev-parse --show-toplevel)/.gitignore"
}
}
# git pull, push and switch
export def gp [
branch?: string@"nu-complete git branches"
--remote (-r)='origin': string@"nu-complete git remotes"
--force (-f) # git push -f
--override
--submodule (-s) # git submodule
--init (-i) # git init
--merge (-m) # git pull (no)--rebase
--autostash (-a) # git pull --autostash
--back-to-prev (-b) # back to branch
] {
if $submodule {
git submodule update
} else if $override {
git pull --rebase
git add --all
git commit -v -a --no-edit --amend
git push --force
} else {
let m = if $merge { [] } else { [--rebase] }
let a = if $autostash {[--autostash]} else {[]}
let prev = (_git_status).branch
let branch = if ($branch | is-empty) { $prev } else { $branch }
let branch_repr = $'(ansi yellow)($branch)(ansi light_gray)'
let lbs = git branch | lines | each { $in | str substring 2..}
let rbs = (remote_branches)
if $"($remote)/($branch)" in $rbs {
if $branch in $lbs {
let bmsg = $'both local and remote have ($branch_repr) branch'
if $force {
tips $'($bmsg), with `--force`, push'
git branch -u $'($remote)/($branch)' $branch
git push --force
} else {
tips $'($bmsg), pull'
if $prev != $branch {
tips $'switch to ($branch_repr)'
git checkout $branch
}
git pull ...$m ...$a
}
} else {
tips $"local doesn't have ($branch_repr) branch, fetch"
git checkout -b $branch
git fetch $remote $branch
git branch -u $'($remote)/($branch)' $branch
git pull ...$m ...$a -v
}
} else {
let bmsg = $"remote doesn't have ($branch_repr) branch"
let force = if $force {[--force]} else {[]}
if $branch in $lbs {
tips $'($bmsg), set upstream and push'
git checkout $branch
} else {
tips $'($bmsg), create and push'
git checkout -b $branch
}
git push ...$force --set-upstream $remote $branch
}
if $back_to_prev {
git checkout $prev
}
let s = (_git_status)
if $s.ahead > 0 {
tips 'remote is behind, push'
git push
}
}
}
# git add, rm and restore
export def ga [
file?: path
--all (-A)
--patch (-p)
--update (-u)
--verbose (-v)
--delete (-d) # git rm
--cached (-c)
--force (-f)
--restore (-r) # git restore
--staged (-s)
--source (-o): string
] {
if $delete {
let c = if $cached {[--cached]} else {[]}
let f = if $force {[--force]} else {[]}
git rm ...$c ...$f -r $file
} else if $restore {
let o = $source | with-flag --source
let s = if $staged {[--staged]} else {[]}
let file = if ($file | is-empty) { [.] } else { [$file] }
git restore ...$o ...$s ...$file
} else {
let a = if $all {[--all]} else {[]}
let p = if $patch {[--patch]} else {[]}
let u = if $update {[--update]} else {[]}
let v = if $verbose {[--verbose]} else {[]}
let f = if $force {[--force]} else {[]}
let file = if ($file | is-empty) { [.] } else { [$file] }
git add ...([$a $p $u $v $f $file] | flatten)
}
}
# git commit
export def gc [
message?: string
--all (-A)
--amend (-a)
--keep (-k)
] {
let m = $message | with-flag -m
let a = if $all {[--all]} else {[]}
let n = if $amend {[--amend]} else {[]}
let k = if $keep {[--no-edit]} else {[]}
git commit -v ...$m ...$a ...$n ...$k
}
# git diff
export def gd [
file?: path
--cached (-c) # cached
--word-diff (-w) # word-diff
--staged (-s) # staged
] {
let w = if $word_diff {[--word-diff]} else {[]}
let c = if $cached {[--cached]} else {[]}
let s = if $staged {[--staged]} else {[]}
git diff ...$c ...$s ...$w ...($file | with-flag)
}
# git merge
export def gm [
branch?: string@"nu-complete git branches"
--abort (-a)
--continue (-c)
--quit (-q)
--no-squash (-n) # git merge (no)--squash
] {
let x = if $no_squash { [] } else { [--squash] }
if ($branch | is-empty) {
git merge ...$x $"origin/(git_main_branch)"
} else {
git merge ...$x $branch
}
if not $no_squash {
git commit -v
}
}
# git rebase
# TODO: --onto: (commit_id)
export def gr [
branch?: string@"nu-complete git branches"
--interactive (-i)
--onto (-o): string
--abort (-a)
--continue (-c)
--skip (-s)
--quit (-q)
] {
if $abort {
git rebase --abort
} else if $continue {
git rebase --continue
} else if $skip {
git rebase --skip
} else if $quit {
git rebase --quit
} else if ($onto | is-not-empty) {
git rebase --onto $branch
} else {
let i = if $interactive {[--interactive]} else {[]}
if ($branch | is-empty) {
git rebase ...$i (git_main_branch)
} else {
git rebase ...$i $branch
}
}
}
# git cherry-pick
export def gcp [
commit?: string@"nu-complete git log all"
--abort (-a)
--continue (-c)
--skip (-s)
--quit (-q)
] {
if $abort {
git cherry-pick --abort
} else if $continue {
git cherry-pick --continue
} else if $skip {
git cherry-pick --skip
} else if $quit {
git cherry-pick --quit
} else {
git cherry-pick $commit
}
}
# copy file from other branch
export def gcf [
branch: string@"nu-complete git branches"
...file: string@"nu-complete git branch files"
] {
^git checkout $branch $file
}
# git reset
export def grs [
commit?: string@"nu-complete git log"
--hard (-h)
--clean (-c)
] {
let h = if $hard {[--hard]} else {[]}
let cm = $commit | with-flag
git reset ...$h ...$cm
if $clean {
git clean -fd
}
}
# git remote
export def grm [
remote?: string@"nu-complete git remotes"
uri?: string
--add (-a)
--rename (-r)
--delete (-d)
--update (-u)
--set (-s)
] {
if ($remote | is-empty) {
git remote -v
} else if $add {
git remote add $remote $uri
} else if $set {
git remote set-url $remote $uri
} else if $rename {
let old = $remote
let new = $uri
git remote rename $old $new
} else if $delete {
git remote remove $remote
} else if $update {
git remote update $remote
} else {
git remote show $remote
}
}
# git bisect
export def gbs [
--bad (-b)
--good (-g)
--reset (-r)
--start (-s)
] {
if $good {
git bisect good
} else if $bad {
git bisect bad
} else if $reset {
git bisect reset
} else if $start {
git bisect start
} else {
git bisect
}
}
export def gha [] {
git log --pretty=%h»¦«%aN»¦«%s»¦«%aD
| lines
| split column "»¦«" sha1 committer desc merged_at
| histogram committer merger
| sort-by merger
| reverse
}
export def ggc [] {
git reflog expire --all --expire=now
git gc --prune=now --aggressive
}
export alias gcl = git config --list
export alias gsw = git switch
export alias gswc = git switch -c
export alias gts = git tag -s
export def _git_status [] {
# TODO: show-stash
let raw_status = do -i { git --no-optional-locks status --porcelain=2 --branch | lines }
let stashes = do -i { git stash list | lines | length }
mut status = {
idx_added_staged : 0
idx_modified_staged : 0
idx_deleted_staged : 0
idx_renamed : 0
idx_type_changed : 0
wt_untracked : 0
wt_modified : 0
wt_deleted : 0
wt_type_changed : 0
wt_renamed : 0
ignored : 0
conflicts : 0
ahead : 0
behind : 0
stashes : $stashes
repo_name : no_repository
tag : no_tag
branch : no_branch
remote : ''
}
if ($raw_status | is-empty) { return $status }
for s in $raw_status {
let r = $s | split row ' '
match $r.0 {
'#' => {
match ($r.1 | str substring 7..) {
'oid' => {
$status.commit_hash = ($r.2 | str substring 0..8)
}
'head' => {
$status.branch = $r.2
}
'upstream' => {
$status.remote = $r.2
}
'ab' => {
$status.ahead = ($r.2 | into int)
$status.behind = ($r.3 | into int | math abs)
}
}
}
'1'|'2' => {
match ($r.1 | str substring 0..1) {
'A' => {
$status.idx_added_staged += 1
}
'M' => {
$status.idx_modified_staged += 1
}
'R' => {
$status.idx_renamed += 1
}
'D' => {
$status.idx_deleted_staged += 1
}
'T' => {
$status.idx_type_changed += 1
}
}
match ($r.1 | str substring 1..2) {
'M' => {
$status.wt_modified += 1
}
'R' => {
$status.wt_renamed += 1
}
'D' => {
$status.wt_deleted += 1
}
'T' => {
$status.wt_type_changed += 1
}
}
}
'?' => {
$status.wt_untracked += 1
}
'u' => {
$status.conflicts += 1
}
}
}
$status
}
export def _git_log_stat [n] {
do -i {
git log --reverse -n $n --pretty=»¦«%h --stat
| lines
| reduce -f { c: '', r: [] } {|it, acc|
if ($it | str starts-with '»¦«') {
$acc | upsert c ($it | str substring 6.. )
} else if ($it | find -r '[0-9]+ file.+change' | is-empty) {
$acc
} else {
let x = $it
| split row ','
| each {|x| $x
| str trim
| parse -r "(?<num>[0-9]+) (?<col>.+)"
| get 0
}
| reduce -f {sha: $acc.c file:0 ins:0 del:0} {|i,a|
let col = if ($i.col | str starts-with 'file') {
'file'
} else {
$i.col | str substring ..3
}
let num = $i.num | into int
$a | upsert $col $num
}
$acc | upsert r ($acc.r | append $x)
}
}
| get r
}
}
export def _git_log [verbose num] {
let r = do -i {
git log --reverse -n $num --pretty=%h»¦«%s»¦«%aN»¦«%aE»¦«%aD»¦«%D
| lines
| split column "»¦«" sha message author email date refs
| each {|x|
let refs = if ($x.refs | is-empty) {
$x.refs
} else {
$x.refs | split row ", "
}
$x
| update date { $x.date | into datetime }
| update refs $refs
}
}
if $verbose {
$r | merge ( _git_log_stat $num )
} else {
$r
}
}
def "nu-complete git log" [] {
git log -n 32 --pretty=%h»¦«%s
| lines
| split column "»¦«" value description
| each {|x| $x | update value $"($x.value)"}
}
def "nu-complete git log all" [] {
git log --all -n 32 --pretty=%h»¦«%d»¦«%s
| lines
| split column "»¦«" value branch description
| each {|x| $x | update description $"($x.branch) ($x.description)" }
}
def "nu-complete git branch files" [context: string, offset:int] {
let token = $context | split row ' '
let branch = $token | get 1
let files = $token | skip 2
git ls-tree -r --name-only $branch
| lines
| filter {|x| not ($x in $files)}
}
def "nu-complete git branches" [] {
git branch
| lines
| filter {|x| not ($x | str starts-with '*')}
| each {|x| $"($x|str trim)"}
}
export def remote_branches [] {
git branch -r
| lines
| str trim
| filter {|x| not ($x | str starts-with 'origin/HEAD') }
}
def "nu-complete git remotes" [] {
^git remote | lines | each { |line| $line | str trim }
}
def git_main_branch [] {
git remote show origin
| lines
| str trim
| find --regex 'HEAD .*?[: ].+'
| first
| str replace --regex 'HEAD .*?[: ](.+)' '$1'
}

View File

@@ -0,0 +1,105 @@
def quote [...t] {
$"'($t | str join '')'"
}
def flatten_fields [args] {
let f = $in | default [] | filter {|x| $x | is-not-empty }
let prefix = $args.0
let inner = $args.1
let outer = $args.2
if ($f | is-not-empty) {
$f
| each {|x|
if ($x | describe -d).type == list {
$x | str join $inner
} else {
$x
}
}
| str join $outer
| do { (if ($prefix | is-empty) {[$in]} else {[$prefix $in]})}
} else { [] }
}
def sql [q] {
[
[$q.select ['select', ' as ', ', ']]
[$q.from ['from', ' as ', ' join ']]
[$q.where? ['where', ' ', ' and ']]
[$q.whereOr? ['or', ' ', ' or ']]
[$q.groupBy? ['group by', null, ', ']]
[$q.orderBy? ['order by', ' ', ', ']]
[$q.limit? ['limit', null, ' offset ']]
]
| each {|x| $x.0 | flatten_fields $x.1 }
| flatten
| str join ' '
}
export def 'history timing' [
pattern?
--exclude(-x): string
--num(-n)=10
--all(-a)
] {
open $nu.history-path | query db (sql {
from: history
where: [
"cmd not like 'history timing%'"
(if ($pattern | is-not-empty) {[cmd like (quote '%' $pattern '%')]})
(if ($exclude | is-not-empty) {[cmd not like (quote '%' $exclude '%')]})
(if not $all {[cwd = (quote $env.PWD)]})
]
orderBy: [[start desc]]
select: [
[duration_ms duration]
[command_line cmd]
[start_timestamp start]
(if $all {[$"replace\(cwd, '($env.HOME)', '~')" cwd]})
[exit_status exit]
]
limit: $num
})
| update duration {|x| $x.duration | default 0 | do { $in * 1_000_000 } | into duration }
| update start {|x| $x.start | into int | do { $in * 1_000_000 } | into datetime }
}
def "nu-complete history dir" [] {
open $nu.history-path | query db (sql {
select: [cwd ['count(1)' count]]
from: history
groupBy: [cwd]
orderBy: ['count desc']
limit: 20
})
| rename value description
| update value {|x| $x.value | str replace $env.HOME '~' }
}
export def 'history top' [
num=10
--before (-b): duration
--dir (-d)
--path(-p): list<string@"nu-complete history dir">
] {
open $nu.history-path | query db (sql {
from: history
select: [
(if $dir {[$"replace\(cwd, '($env.HOME)', '~')" cwd]} else {[command_line cmd]})
['count(1)' count]
]
where: [
(if ($before | is-not-empty) {
let ts = (date now) - $before | into int | do { $in / 1_000_000 }
[start_timestamp > $ts]
})
(if ($path | is-not-empty) {
let ps = $path | path expand | each { quote $in } | str join ', '
[cwd in '(' $ps ')']
})
]
groupBy: [(if $dir {'cwd'} else {'cmd'})]
orderBy: [[count desc]]
limit: $num
})
}

View File

@@ -0,0 +1,30 @@
# Run `jc` (Json Converter)
#
# This module provides a wrapper around the `jc` command line tool and automatically
# parses its output into a structured data format.
#
# Dependencies:
# * `jc`
#
# Installation:
# 1. Install the `jc` command line: https://kellyjonbrazil.github.io/jc/#installation
# 2. Import this module in your `config.nu`: `import ~/.local/share/nu_scripts/modules/jc/`
export def --wrapped main [...args]: [any -> table, any -> record, any -> string] {
let run = (^jc ...$args | complete)
if $run.exit_code != 0 {
error make {
msg: $run.stderr,
label: {
text: "jc execution failed",
span: (metadata $args).span
}
}
}
if '--help' in $args or '-h' in $args {
$run.stdout
} else {
$run.stdout | from json
}
}

View File

@@ -0,0 +1,178 @@
use argx
use utils.nu *
export def "nu-complete kube ctx" [] {
let k = (kube-config)
let cache = $'($env.HOME)/.cache/nu-complete/k8s/($k.path | path basename).json'
let data = ensure-cache-by-lines $cache $k.path { ||
let clusters = $k.data | get clusters | select name cluster.server
let data = $k.data
| get contexts
| reduce -f {completion:[], mx_ns: 0, mx_cl: 0} {|x, a|
let ns = if ($x.context.namespace? | is-empty) { '' } else { $x.context.namespace }
let max_ns = $ns | str length
let cluster = $"($x.context.user)@($clusters | where name == $x.context.cluster | get cluster_server.0)"
let max_cl = $cluster | str length
$a
| upsert mx_ns (if $max_ns > $a.mx_ns { $max_ns } else $a.mx_ns)
| upsert mx_cl (if $max_cl > $a.mx_cl { $max_cl } else $a.mx_cl)
| upsert completion ($a.completion | append {value: $x.name, ns: $ns, cluster: $cluster})
}
{completion: $data.completion, max: {ns: $data.mx_ns, cluster: $data.mx_cl}}
}
$data.completion | each {|x|
let ns = $x.ns | fill -a l -w $data.max.ns -c ' '
let cl = $x.cluster | fill -a l -w $data.max.cluster -c ' '
{value: $x.value, description: $"\t($ns) ($cl)"}
}
}
export def "nu-complete kube ns" [] {
kubectl get namespaces
| from ssv -a
| each {|x|
{value: $x.NAME, description: $"($x.AGE)\t($x.STATUS)"}
}
}
export def "nu-complete kube kind" [] {
let ctx = (kube-config)
let cache = $'($env.HOME)/.cache/nu-complete/k8s-api-resources/($ctx.data.current-context).json'
ensure-cache-by-lines $cache $ctx.path {||
kubectl api-resources | from ssv -a
| each {|x| {value: $x.NAME description: $x.SHORTNAMES} }
| append (kubectl get crd | from ssv -a | get NAME | wrap value)
}
}
export def "nu-complete kube res" [context: string, offset: int] {
let ctx = $context | argx parse
let kind = $ctx | get _args.1
let ns = if ($ctx.namespace? | is-empty) { [] } else { [-n $ctx.namespace] }
kubectl get ...$ns $kind | from ssv -a | get NAME
}
export def "nu-complete kube res via name" [context: string, offset: int] {
let ctx = $context | argx parse
let kind = $env.KUBERNETES_RESOURCE_ABBR | get ($ctx | get _args.0 | str substring (-1..))
let ns = if ($ctx.namespace? | is-empty) { [] } else { [-n $ctx.namespace] }
kubectl get ...$ns $kind | from ssv -a | get NAME
}
export def "nu-complete kube jsonpath" [context: string] {
let ctx = $context | argx parse
let kind = $ctx | get _args.1
let res = $ctx | get _args.2
let path = $ctx.jsonpath?
let ns = if ($ctx.namespace? | is-empty) { [] } else { [-n $ctx.namespace] }
mut r = []
if ($path | is-empty) {
if ($context | str ends-with '-p ') {
$r = ['.']
} else {
$r = ['']
}
} else if ($path | str starts-with '.') {
let row = $path | split row '.'
let p = $row | range ..-2 | str join '.'
if ($p | is-empty) {
$r = ( kubectl get ...$ns -o json $kind $res
| from json
| columns
| each {|x| $'($p).($x)'}
)
} else {
let m = kubectl get ...$ns $kind $res $"--output=jsonpath={($p)}" | from json
let l = $row | last
let c = do -i {$m | get $l}
if ($c | is-not-empty) and ($c | describe | str substring 0..5) == 'table' {
$r = (0..(($c | length) - 1) | each {|x| $'($p).($l)[($x)]'})
} else {
$r = ($m | columns | each {|x| $'($p).($x)'})
}
}
} else {
$r = ['']
}
$r
}
export def "nu-complete kube nodes" [context: string, offset: int] {
let ctx = $context | argx parse
kubectl get nodes -o wide | from ssv -a
| each {|x| {value: $x.NAME, description: $"($x.INTERNAL-IP)(char tab)($x.ROLES)"} }
}
export def "nu-complete kube deploys" [context: string, offset: int] {
let ctx = $context | argx parse
let ns = $ctx.namespace? | with-flag -n
kubectl get ...$ns deployments | from ssv -a | get NAME
}
export def "nu-complete kube deploys and pods" [context: string, offset: int] {
let ctx = $context | argx parse
let ns = $ctx.namespace? | with-flag -n
let all_pods = ($ctx.a? | default false) or ($ctx.all-pods? | default false)
if $all_pods or ($ctx._pos.pod? | default '' | str ends-with '-') {
kubectl get ...$ns pods | from ssv -a | get NAME
} else {
kubectl get ...$ns deployments | from ssv -a | get NAME | each {|x| $"($x)-"}
}
}
export def "nu-complete kube ctns" [context: string, offset: int] {
let ctx = $context | argx parse
let ns = $ctx.namespace? | with-flag -n
let pod = $ctx | get _args.1
kubectl get ...$ns pod $pod -o jsonpath={.spec.containers[*].name} | split row ' '
}
export def "nu-complete port forward type" [] {
[pod svc]
}
export def "nu-complete kube port" [context: string, offset: int] {
let ctx = $context | argx parse
let kind = $ctx | get _args.1
let ns = if ($ctx.namespace? | is-empty) { [] } else { [-n $ctx.namespace] }
let res = $ctx | get _args.2
if ($kind | str starts-with 's') {
kubectl get ...$ns svc $res --output=jsonpath="{.spec.ports}"
| from json
| each {|x| {value: $x.port description: $x.name} }
} else {
kubectl get ...$ns pods $res --output=jsonpath="{.spec.containers[].ports}"
| from json
| each {|x| {value: $x.containerPort description: $x.name?} }
}
}
export def "nu-complete kube cp" [cmd: string, offset: int] {
let ctx = $cmd | str substring ..$offset | argx parse
let p = $ctx._args | get (($ctx._args | length) - 1)
let ns = $ctx.namespace? | with-flag -n
let c = $ctx.container? | with-flag -c
let ctn = kubectl get pod ...$ns | from ssv -a | each {|x| {description: $x.READY value: $"($x.NAME):" }}
let n = $p | split row ':'
if $"($n | get 0):" in ($ctn | get value) {
kubectl exec ...$ns ($n | get 0) ...$c -- sh -c $"ls -dp ($n | get 1)*"
| lines
| each {|x| $"($n | get 0):($x)"}
} else {
let files = do -i { ls -a ($"($p)*" | into glob)
| each {|x| if $x.type == dir { $"($x.name)/"} else { $x.name }}
}
$files | append $ctn
}
}
export def "nu-complete kube kind with image" [] {
[
deployment daemonset statefulset
pod replicationcontroller
cronjob replicaset
]
}

View File

@@ -0,0 +1,155 @@
# kubernetes to docker-compose
export def kube-compose [--without-service(-s)] {
let a = $in
let dpl = $a | where kind == 'Deployment'
mut dpl_svc = {}
mut svc = {}
if not $without_service {
let svcs = $a | where kind == 'Service'
for s in $svcs {
for d in $dpl {
let dl = $d.metadata.labels?
let ss = $s.spec.selector?
mut p = true
for x in ($ss | transpose k v) {
if (not ($x.k in $dl)) or (($dl | get $x.k) != $x.v) {
$p = false
break
}
}
if $p {
let dn = $d.metadata.name
let dv = if $dn in $dpl_svc {
$dpl_svc | get $dn
} else { [] }
$dpl_svc = ($dpl_svc | upsert $dn ($dv | append $s.metadata.name))
}
}
}
$svc = ($svcs
| reduce -f {} {|i, a|
$a | upsert $i.metadata.name $i.spec.ports
})
}
let dpl_svc = $dpl_svc
let svc = $svc
let cm = $a | where kind == 'ConfigMap'
| reduce -f {} {|i,a|
let p = ['.kcmp', 'ConfigMap', $i.metadata.name] | path join
mkdir $p
for f in ($i.data | transpose k v) {
$f.v | save -f ([$p $f.k] | path join)
}
$a | insert $i.metadata.name $p
}
let sec = $a | where kind == 'Secret'
| reduce -f {} {|i,a|
let p = ['.kcmp', 'Secret', $i.metadata.name] | path join
mkdir $p
for f in ($i.data | transpose k v) {
$f.v | decode base64 | save -f ([$p $f.k] | path join)
}
$a | insert $i.metadata.name $p
}
let pv = $a | where kind == 'PersistentVolume'
| reduce -f {} {|i,a| $a | insert $i.metadata.name $i.spec.local?.path? }
let pvc = $a | where kind == 'PersistentVolumeClaim'
| reduce -f {} {|i,a| $a | insert $i.metadata.name ($pv | get $i.spec.volumeName) }
let services = $dpl
| each {|x|
let d = $x.metadata.name
let s = if not $without_service {
$dpl_svc
| get $d
| each {|z| $svc | get $z}
| flatten
| each {|z| [$z.port $z.targetPort] }
}
let v = $x.spec.template.spec.volumes?
| reduce -f {} {|i,a|
$a | insert $i.name $i
}
$x.spec.template.spec.containers?
| default []
| each {|y|
let ca = $y.securityContext?.capabilities?.add?
let cd = $y.securityContext?.capabilities?.drop?
let v = $y.volumeMounts?
| default []
| each {|z|
let sp = $z.subPath? | default ''
let s = $v | get $z.name
let s = if ($s.hostPath? | is-not-empty) {
$s.hostPath.path
} else if ($s.path? | is-not-empty) {
$s.path
} else if ($s.persistentVolumeClaim?.claimName? | is-not-empty) {
$pvc | get $s.persistentVolumeClaim.claimName
} else if ($s.configMap?.name? | is-not-empty) {
['.'
($cm | get $s.configMap.name)
$sp
] | path join
} else if ($s.secret?.secretName? | is-not-empty) {
['.'
($sec | get $s.secret.secretName)
$sp
] | path join
} else {
$s
}
let m = [$z.mountPath $sp] | path join
$"($s):($m)"
}
let s = if $without_service {
$y.ports? | default [] | each {|x| $"($x.containerPort):($x.containerPort)"}
} else {
$s | each {|x|
if ($x.1 | find -r '[^0-9]' | is-empty) {
$"($x.0):($x.1)"
} else {
mut p = ''
for i in ($y.ports? | default []) {
if $i.name == $x.1 {
$p = $i.containerPort
break
}
}
$"($x.0):($p)"
}
}
}
{
name: $"($d)_($y.name)"
image: $y.image
environment: ($y.env? | reduce -f {} {|i,a| $a | insert $i.name $i.value?})
ports: $s
entrypoint: $y.command?
command: $y.args?
cap_add: $ca
cap_drop: $cd
volumes: $v
}
| transpose k v
| reduce -f {} {|i,a|
if ($i.v | is-empty) {
$a
} else {
$a | insert $i.k $i.v
}
}
}
}
| flatten
| reduce -f {} {|i,a|
$a | insert $i.name ($i | reject name)
}
{ version: '3.8', services: $services}
| to yaml
}

View File

@@ -0,0 +1,58 @@
use complete.nu *
export def 'kconf import' [name: string, path: string] {
let k = (kube-config)
mut d = $k.data
let i = cat $path | from yaml
let c = {
context: {
cluster: $name,
namespace: default,
user: $name
}
name: $name,
}
$d.clusters = (upsert_row $d.clusters name [] $name ($i.clusters.0 | upsert name $name))
$d.users = (upsert_row $d.users name [] $name ($i.users.0 | upsert name $name))
$d.contexts = (upsert_row $d.contexts name [] $name $c)
$d | to yaml
}
export def 'kconf delete' [name: string@"nu-complete kube ctx"] {
let kc = (kube-config)
let d = $kc.data
let ctx = $d | get contexts | where name == $name | get 0
let rctx = $d | get contexts | where name != $name
let user = if ($ctx.context.user in ($rctx | get context.user)) {
$d | get users
} else {
$d | get users | where name != $ctx.context.user
}
let cluster = if ($ctx.context.cluster in ($rctx | get context.cluster)) {
$d | get clusters
} else {
$d | get clusters | where name != $ctx.context.cluster
}
$d
| update contexts $rctx
| update users $user
| update clusters $cluster
| to yaml
}
export def 'kconf export' [name: string@"nu-complete kube ctx"] {
let d = (kube-config).data
let ctx = $d | get contexts | where name == $name | get 0
let user = $d | get users | where name == $ctx.context.user
let cluster = $d | get clusters | where name == $ctx.context.cluster
{
apiVersion: 'v1',
current-context: $ctx.name,
kind: Config,
clusters: $cluster,
preferences: {},
contexts: [$ctx],
users: $user,
} | to yaml
}

View File

@@ -0,0 +1,188 @@
export-env {
$env.KUBERNETES_SCHEMA_URL = $"file:///($env.HOME)/.config/kubernetes-json-schema/all.json"
$env.KUBERNETES_RESOURCE_ABBR = {
s: services
d: deployments
p: pods
}
let id = {
name: [metadata name]
kind: [kind {|x|$x| str downcase}]
apiVersion: [apiVersion]
labels: [metadata labels]
created: [metadata creationTimestamp {|x|$x | into datetime}]
}
let ids = {...$id, namespace: [metadata namespace] }
$env.KUBERNETES_REFINE = {
_namespace: [
kube-system kube-node-lease kube-public
kube-flannel istio-system ingress-nginx
]
shortnames: {
sc: storageclasses
ing: ingresses
vs: virtualservices
gw: gateways.networking.istio.io
gtw: gateways
dr: destinationrules
ev: events
cj: cronjobs
hpa: horizontalpodautoscalers
sts: statefulsets
rs: replicasets
deploy: deployments
ds: daemonsets
crd: customresourcedefinitions
svc: services
sa: serviceaccounts
quota: resourcequotas
rc: replicationcontrollers
po: pods
pv: persistentvolumes
pvc: persistentvolumeclaims
no: nodes
ns: namespaces
ep: endpoints
cm: configmaps
}
cluster_resources: {
namespaces: {
...$id
}
}
cluster_status: {
}
status: {
deployments: {
conditions: {
_: [status conditions]
type: [type]
reason: [reason]
message: [message]
}
}
pods: {
...$ids
image: [spec containers image]
containers: {
_: [spec containers]
name: [name]
image: [image]
serviceAccount: [serviceAccount]
env: [env]
args: [args]
ports: [ports]
volumeMounts: [volumeMounts]
node: [nodeName]
nodeSelector: [nodeSelector]
}
hostIP: [status hostIP]
podIP: [status podIP]
phase: [status phase]
startTime: [status startTime]
conditions: {
_: [status conditions]
type: [type]
reason: [reason]
message: [message]
}
}
}
resources: {
deployments: {
...$ids
replicas: [spec replicas]
containers: {
_: [spec template spec containers]
name: [name]
labels: [metadata labels]
image: [image]
imagePullPolicy: [imagePullPolicy]
env: [env]
ports: [ports]
resources: [resources]
args: [args]
label: [label]
replicas: [replicas]
}
}
services: {
...$ids
type: [spec type]
clusterIP: [spec clusterIP]
ports: [spec ports]
selector: [spec selector]
sessionAffinity: [sessionAffinity]
}
configmaps: {
...$ids
data: [data]
}
secrets: {
...$ids
data: [data]
type: [type]
}
gateways: {
...$ids
addresses: [spec addresses]
gatewayClassName: [spec gatewayClassName]
listeners: {
_: [spec listeners]
name: [name]
hostname: [hostname]
port: [port]
protocol: [protocol]
tls: [tls]
}
}
httproutes: {
...$ids
hostnames: [spec hostnames]
parentRefs: [spec parentRefs name]
rules: {
_: [spec rules]
backend: {
_: [backendRefs]
name: [name]
port: [port]
weight: [weight]
}
matches: {
_: [matches]
type: [path type]
value: [path value]
}
}
}
virtualservices.networking.istio.io: {
...$ids
http: [spec http]
gateways: {
_: [spec gateways]
hosts: {
_: [spec hosts]
}
}
}
gateways.networking.istio.io: {
...$ids
selector: [spec selector]
servers: [spec servers]
}
ingresses: {
...$ids
annotations: [metadata annotations]
rules: {
_: [spec rules]
host: [host]
http: [http]
}
}
}
}
}

View File

@@ -0,0 +1,125 @@
use complete.nu *
use utils.nu *
use argx
export def record-to-set-json [value] {
$value | transpose k v
| each {|x| $"($x.k)=($x.v | to json -r)"}
| str join ','
}
def "nu-complete helm list" [context: string, offset: int] {
let ctx = $context | argx parse
kgh -n $ctx.namespace? | each {|x| {value: $x.name description: $x.updated} }
}
def "nu-complete helm charts" [context: string, offset: int] {
let ctx = $context | argx parse
let path = $ctx | get _pos.chart?
let paths = do -i { ls ($"($path)*" | into glob) | each {|x| if $x.type == dir { $"($x.name)/"} else { $x.name }} }
helm repo list | from ssv -a | rename value description
| append $paths
}
# helm list and get
export def kgh [
name?: string@"nu-complete helm list"
--namespace (-n): string@"nu-complete kube ns"
--manifest (-m)
--values(-v)
--all (-a)
] {
if ($name | is-empty) {
let ns = if $all { [--all] } else { $namespace | with-flag -n }
helm list ...$ns --output json
| from json
| update updated {|x|
$x.updated
| str substring ..-4
| into datetime -f '%Y-%m-%d %H:%M:%S.%f %z'
}
} else {
if $manifest {
helm get manifest $name ...($namespace | with-flag -n)
} else if $values {
helm get values $name ...($namespace | with-flag -n)
} else {
helm get notes $name ...($namespace | with-flag -n)
}
}
}
# helm install or upgrade via values file
export def kah [
name: string@"nu-complete helm list"
chart: string@"nu-complete helm charts"
valuefile: path
--values (-v): any
--namespace (-n): string@"nu-complete kube ns"
--ignore-image (-i) # for kdh
] {
let update = $name in (
helm list ...($namespace | with-flag -n) --output json
| from json | get name
)
let act = if $update { [upgrade] } else { [install] }
let values = if ($values | is-empty) { [] } else { [--set-json (record-to-set-json $values)] }
helm ...$act $name $chart -f $valuefile ...$values ...($namespace | with-flag -n)
}
# helm diff
export def kdh [
name: string@"nu-complete helm list"
chart: string@"nu-complete helm charts"
valuefile: path
--values (-v): any
--namespace (-n): string@"nu-complete kube ns"
--ignore-image (-i)
--has-plugin (-h)
] {
if $has_plugin {
helm diff $name $chart -f $valuefile ...($namespace | with-flag -n)
} else {
let update = $name in (
helm list ...($namespace | with-flag -n) --output json
| from json | get name
)
if not $update {
echo "new installation"
return
}
let values = if ($values | is-empty) { [] } else { [--set-json (record-to-set-json $values)] }
let target = $'/tmp/($chart | path basename).($name).out.yaml'
helm template --debug $name $chart -f $valuefile ...$values ...($namespace | with-flag -n) | save -f $target
if $ignore_image {
do -i { yq -i ea 'del(.spec.template.spec.containers.[].image)' $target }
}
kubectl diff -f $target
}
}
# helm delete
export def kdelh [
name: string@"nu-complete helm list"
--namespace (-n): string@"nu-complete kube ns"
] {
helm uninstall $name ...($namespace | with-flag -n)
}
# helm template
export def kh [
chart: string@"nu-complete helm charts"
valuefile: path
--values (-v): any
--namespace (-n): string@"nu-complete kube ns"='test'
--app (-a): string='test'
] {
let values = if ($values | is-empty) { [] } else { [--set-json (record-to-set-json $values)] }
let target = $valuefile | split row '.' | range ..-2 | append [out yaml] | str join '.'
if (not ($target | path exists)) and (([yes no] | input list $'create ($target)?') in [no]) { return }
helm template --debug $app $chart -f $valuefile ...$values ...($namespace | with-flag -n)
| save -f $target
}

View File

@@ -0,0 +1,573 @@
export-env {
use env.nu *
}
### ctx
export def "kube-config" [] {
let file = if ($env.KUBECONFIG? | is-empty) { $"($env.HOME)/.kube/config" } else { $env.KUBECONFIG }
{ path: $file, data: (cat $file | from yaml) }
}
use utils.nu *
use complete.nu *
export use refine.nu *
export use helm.nu *
export use conf.nu *
export use resources.nu *
export use compose.nu *
def krefine [kind] {
let obj = $in
let conf = $env.KUBERNETES_REFINE
let kind = if $kind in $conf.shortnames {
$conf.shortnames | get $kind
} else {
$kind
}
let tg = [cluster_resources cluster_status resources status]
| reduce -f {} {|i,a|
let r = $conf | get $i
if $kind in $r {
$a | merge ($r | get $kind)
} else {
$a
}
}
if ($tg | is-empty) {
$obj
} else {
refine $tg $obj
}
}
# kubectl apply -f
export def kaf [file: path] {
kubectl apply -f $file
}
# kubectl diff -f
export def kdf [file: path] {
kubectl diff -f $file
}
# kubectl delete -f
export def kdelf [file: path] {
kubectl delete -f $file
}
# kubectl apply -k (kustomize)
export def kak [file: path] {
kubectl apply -k $file
}
# kubectl diff -k (kustomize)
export def kdk [file: path] {
kubectl diff -k $file
}
# kubectl delete -k (kustomize)
export def kdelk [file: path] {
kubectl delete -k $file
}
# kubectl kustomize (template)
export def kk [file: path] {
kubectl kustomize $file
}
# kubectl change context
export def kcc [context: string@"nu-complete kube ctx"] {
kubectl config use-context $context
}
# kubectl (change) namespace
export def kn [namespace: string@"nu-complete kube ns"] {
if not ($namespace in (kubectl get namespace | from ssv -a | get NAME)) {
if ([no yes] | input list $"namespace '($namespace)' doesn't exist, create it?") in [yes] {
kubectl create namespace $namespace
} else {
return
}
}
kubectl config set-context --current $"--namespace=($namespace)"
}
# kubectl change context clone
export def --env kccc [name: string@"nu-complete kube ctx"] {
let dist = $"($env.HOME)/.kube/config.d"
mkdir $dist
kconf export $name | save -fr $"($dist)/($name)"
$env.KUBECONFIG = $"($dist)/($name)"
}
# kubectl get
export def kg [
kind: string@"nu-complete kube kind"
resource?: string@"nu-complete kube res"
--namespace (-n): string@"nu-complete kube ns"
--jsonpath (-p): string@"nu-complete kube jsonpath"
--selector (-l): string
--verbose (-v)
--watch (-w)
--wide (-W)
--all (-a)
] {
let n = if $all {
[-A]
} else if ($namespace | is-empty) {
[]
} else {
[-n $namespace]
}
if ($resource | is-empty) {
let l = $selector | with-flag -l
if ($jsonpath | is-empty) {
let wide = if $wide {[-o wide]} else {[]}
if $verbose {
kubectl get -o json ...$n $kind ...$l | from json
| get items
| krefine $kind
} else if $watch {
kubectl get ...$n $kind ...$l ...$wide --watch
} else {
kubectl get ...$n $kind ...$l ...$wide | from ssv -a | normalize-column-names
}
} else {
kubectl get ...$n $kind $"--output=jsonpath={($jsonpath)}" | from json
}
} else {
let o = kubectl get ...$n $kind $resource -o json | from json
if $verbose { $o } else { $o | krefine $kind }
}
}
# kubectl describe
export def kd [
kind: string@"nu-complete kube kind"
resource: string@"nu-complete kube res"
--namespace (-n): string@"nu-complete kube ns"
] {
kubectl describe ...($namespace | with-flag -n) $kind $resource
}
# kubectl create
export def kc [
kind: string@"nu-complete kube kind"
--namespace (-n): string@"nu-complete kube ns"
name:string
] {
kubectl create ...($namespace | with-flag -n) $kind $name
}
# kubectl get -o yaml
export def ky [
kind: string@"nu-complete kube kind"
resource: string@"nu-complete kube res"
--namespace (-n): string@"nu-complete kube ns"
] {
kubectl get ...($namespace | with-flag -n) -o yaml $kind $resource
}
# kubectl edit
export def ke [
kind: string@"nu-complete kube kind"
resource?: string@"nu-complete kube res"
--namespace (-n): string@"nu-complete kube ns"
--selector(-l): string
] {
let n = $namespace | with-flag -n
let r = if ($selector | is-empty) { $resource } else {
let res = kubectl get $kind ...$n -l $selector | from ssv -a | each {|x| $x.NAME}
if ($res | length) == 1 {
$res.0
} else if ($res | length) == 0 {
return
} else {
$res | input list $'select ($kind) '
}
}
kubectl edit ...$n $kind $r
}
# kubectl delete
export def kdel [
kind: string@"nu-complete kube kind"
resource: string@"nu-complete kube res"
--namespace (-n): string@"nu-complete kube ns"
--force(-f)
] {
kubectl delete ...($namespace | with-flag -n) ...(if $force {[--grace-period=0 --force]} else {[]}) $kind $resource
}
# kubectl get nodes
export def kgno [] {
kubectl get nodes -o wide | from ssv -a
| rename name status roles age version internal-ip external-ip os kernel runtime
}
# kubectl get pods
export def kgp [
pod?: string@"nu-complete kube res via name"
--namespace (-n): string@"nu-complete kube ns"
--jsonpath (-p): string@"nu-complete kube jsonpath"
--selector (-l): string
--all (-a)
] {
if ($pod | is-not-empty) {
kg pods -n $namespace $pod
} else if $all {
kg pods -a --wide
} else {
kg pods -n $namespace -p $jsonpath -l $selector --wide $pod
}
}
# kubectl get pods --watch
export def kwp [
pod?: string@"nu-complete kube res via name"
--namespace (-n): string@"nu-complete kube ns"
--selector (-l): string
] {
kg pods -n $namespace -w -l $selector --wide $pod
}
# kubectl edit pod
export def kep [
--namespace (-n): string@"nu-complete kube ns"
pod: string@"nu-complete kube res via name"
--selector (-l): string
] {
ke -n $namespace pod -l $selector $pod
}
# kubectl describe pod
export def kdp [
--namespace (-n): string@"nu-complete kube ns"
pod: string@"nu-complete kube res via name"
] {
kd -n $namespace pod $pod
}
# kubectl attach (exec -it)
export def --wrapped ka [
pod?: string@"nu-complete kube deploys and pods"
--namespace (-n): string@"nu-complete kube ns"
--container(-c): string@"nu-complete kube ctns"
--selector(-l): string
--all-pods(-a) # for completion
...args
] {
let n = $namespace | with-flag -n
let pod = if ($selector | is-empty) {
if ($pod | str ends-with '-') {
$"deployment/($pod | str trim --char '-' --right)"
} else {
$pod
}
} else {
let pods = kubectl get pods $n -o wide -l $selector
| from ssv -a
| where STATUS == Running
| select NAME IP NODE
| rename name ip node
if ($pods | length) == 1 {
($pods.0).name
} else if ($pods | length) == 0 {
return
} else {
($pods | input list 'select pod ').name
}
}
let c = if ($container | is-empty) {
if ($selector | is-empty) { [] } else {
let cs = kgp -n $n $pod -p '.spec.containers[*].name' | split row ' '
let ctn = if ($cs | length) == 1 {
$cs.0
} else {
$cs | input list 'select container '
}
[-c $ctn]
}
} else {
[-c $container]
}
kubectl exec ...$n -it $pod ...$c -- ...(if ($args|is-empty) {['bash']} else { $args })
}
# kubectl logs
export def kl [
pod: string@"nu-complete kube deploys and pods"
--namespace(-n): string@"nu-complete kube ns"
--container(-c): string@"nu-complete kube ctns"
--follow(-f)
--previous(-p)
--all-pods(-a) # for completion
] {
let n = $namespace | with-flag -n
let c = $container | with-flag -c
let f = if $follow {[-f]} else {[]}
let p = if $previous {[-p]} else {[]}
let trg = if ($pod | str ends-with '-') {
$"deployment/($pod | str substring ..-1)"
} else {
$pod
}
kubectl logs ...$n ...$f ...$p $trg ...$c
}
# kubectl port-forward
export def kpf [
kind: string@"nu-complete port forward type"
target: string@"nu-complete kube res"
port: string@"nu-complete kube port"
--local (-l): string
--namespace (-n): string@"nu-complete kube ns"
] {
let ns = $namespace | with-flag -n
let port = if ($local | is-empty) { $port } else { $"($local):($port)" }
kubectl port-forward ...$ns $"($kind)/($target)" $port
}
# kubectl cp
export def kcp [
lhs: string@"nu-complete kube cp"
rhs: string@"nu-complete kube cp"
--container (-c): string@"nu-complete kube ctns"
--namespace (-n): string@"nu-complete kube ns"
] {
kubectl cp ...($namespace | with-flag -n) $lhs ...($container | with-flag -c) $rhs
}
# kubectl get services
export def kgs [
service?: string@"nu-complete kube res via name"
--namespace (-n): string@"nu-complete kube ns"
--jsonpath (-p): string@"nu-complete kube jsonpath"
--selector (-l): string
] {
if ($service | is-empty) {
kg services -n $namespace -p $jsonpath -l $selector $service
} else {
kg services -n $namespace $service
}
}
# kubectl edit service
export def kes [
service?: string@"nu-complete kube res via name"
--namespace (-n): string@"nu-complete kube ns"
--selector (-l): string
] {
ke -n $namespace service -l $selector $service
}
# kubectl delete service
export def kdels [
service: string@"nu-complete kube res via name"
--namespace (-n): string@"nu-complete kube ns"
] {
kdel -n $namespace service $service
}
# kubectl get deployments
export def kgd [
deployment?: string@"nu-complete kube res via name"
--namespace (-n): string@"nu-complete kube ns"
--jsonpath (-p): string@"nu-complete kube jsonpath"
--selector (-l): string
] {
kg -n $namespace deployments -p $jsonpath -l $selector $deployment
}
# kubectl edit deployment
export def ked [
deployment?: string@"nu-complete kube res via name"
--namespace (-n): string@"nu-complete kube ns"
--selector (-l): string
] {
ke -n $namespace deployments -l $selector $deployment
}
def "nu-complete num9" [] { [0 1 2 3] }
# kubectl scale deployment
export def ksd [
deployment: string@"nu-complete kube deploys"
num: string@"nu-complete num9"
--namespace (-n): string@"nu-complete kube ns"
] {
if ($num | into int) > 9 {
"too large"
} else {
let ns = $namespace | with-flag -n
kubectl scale ...$ns deployments $deployment --replicas $num
}
}
# kubectl scale deployment with reset
export def ksdr [
deployment: string@"nu-complete kube deploys"
num: int@"nu-complete num9"
--namespace (-n): string@"nu-complete kube ns"
] {
if $num > 9 {
"too large"
} else if $num <= 0 {
"too small"
} else {
let ns = $namespace | with-flag -n
kubectl scale ...$ns deployments $deployment --replicas 0
kubectl scale ...$ns deployments $deployment --replicas $num
}
}
# kubectl set image
export def ksi [
kind: string@"nu-complete kube kind with image"
resource: string@"nu-complete kube res"
--namespace(-n): string@"nu-complete kube ns"
act?: any
] {
let ns = $namespace | with-flag -n
let path = match $kind {
_ => '.spec.template.spec.containers[*]'
}
let name = kubectl get ...$ns $kind $resource -o $"jsonpath={($path).name}" | split row ' '
let image = kubectl get ...$ns $kind $resource -o $"jsonpath={($path).image}" | split row ' '
let list = $name | zip $image | reduce -f {} {|it,acc| $acc | insert $it.0 $it.1 }
if ($act | describe -d).type == 'closure' {
let s = do $act $list
if ($s | describe -d).type == 'record' {
let s = $s | transpose k v | each {|x| $"($x.k)=($x.v)"}
kubectl ...$ns set image $"($kind)/($resource)" ...$s
}
} else {
$list
}
}
# kubectl redistribution deployment
export def krd [
deployment: string@"nu-complete kube deploys"
...nodes: string@"nu-complete kube nodes"
--namespace (-n): string@"nu-complete kube ns"
] {
let ns = $namespace | with-flag -n
let nums = kubectl get nodes | from ssv -a | length
kubectl scale ...$ns deployments $deployment --replicas $nums
let labels = kubectl get ...$ns deploy $deployment --output=json
| from json
| get spec.selector.matchLabels
| transpose k v
| each {|x| $"($x.k)=($x.v)"}
| str join ','
let pods = kubectl get ...$ns pods -l $labels -o wide | from ssv -a
for p in ($pods | where NODE not-in $nodes) {
kubectl delete ...$ns pod --grace-period=0 --force $p.NAME
}
kubectl scale ...$ns deployments $deployment --replicas ($pods | where NODE in $nodes | length)
}
# kubectl rollout status deployment
export alias krsd = kubectl rollout status deployment
# kubectl get rs
export alias kgrs = kubectl get rs
# kubectl rollout history
export def krhd [
--namespace (-n): string@"nu-complete kube ns"
--revision (-v): int
deployment: string@"nu-complete kube res via name"
] {
let ns = $namespace | with-flag -n
let v = if ($revision|is-empty) { [] } else { [ $"--revision=($revision)" ] }
kubectl ...$ns rollout history $"deployment/($deployment)" ...$v
}
# kubectl rollout undo
export def krud [
--namespace (-n): string@"nu-complete kube ns"
--revision (-v): int
deployment: string@"nu-complete kube res via name"
] {
let ns = $namespace | with-flag -n
let v = if ($revision|is-empty) { [] } else { [ $"--to-revision=($revision)" ] }
kubectl ...$ns rollout undo $"deployment/($deployment)" ...$v
}
export alias ksss = kubectl scale statefulset
export alias krsss = kubectl rollout status statefulset
# kubectl top pod
export def ktp [
--namespace (-n): string@"nu-complete kube ns"
--all(-a)
] {
if $all {
kubectl top pod -A | from ssv -a | rename namespace name cpu mem
| each {|x|
{
namespace: $x.namespace
name: $x.name
cpu: ($x.cpu| str substring ..-1 | into float)
mem: ($x.mem | str substring ..-2 | into float)
}
}
} else {
let ns = $namespace | with-flag -n
kubectl top pod ...$ns | from ssv -a | rename name cpu mem
| each {|x|
{
name: $x.name
cpu: ($x.cpu| str substring ..-1 | into float)
mem: ($x.mem | str substring ..-2 | into float)
}
}
}
}
# kubectl top node
export def ktno [] {
kubectl top node | from ssv -a | rename name cpu pcpu mem pmem
| each {|x| {
name: $x.name
cpu: ($x.cpu| str substring ..-1 | into float)
cpu%: (($x.pcpu| str substring ..-1 | into float) / 100)
mem: ($x.mem | str substring ..-2 | into float)
mem%: (($x.pmem | str substring ..-1 | into float) / 100)
} }
}
###
export def "kclean evicted" [] {
kubectl get pods -A
| from ssv -a
| where STATUS == Evicted
| each { |x| kdel pod -n $x.NAMESPACE $x.NAME }
}
### FIXME:
export def "kclean stucked ns" [ns: string] {
kubectl get namespace $ns -o json \
| tr -d "\n"
| sed 's/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/' \
| kubectl replace --raw /api/v1/namespaces/$1/finalize -f -
}
export alias "kclean finalizer" = kubectl patch -p '{\"metadata\":{\"finalizers\":null}}'
export alias "kadm check" = kubeadm certs check-expiration
export alias "kadm renew" = kubeadm certs renew all
### cert-manager
export def kgcert [] {
kubectl get certificates -o wide | from ssv | rename certificates
kubectl get certificaterequests -o wide | from ssv | rename certificaterequests
kubectl get order.acme -o wide | from ssv | rename order.acme
kubectl get challenges.acme -o wide | from ssv | rename challenges.acme
}

View File

@@ -0,0 +1,61 @@
def safe_get [path obj] {
mut r = $obj
mut ps = $path
loop {
if ($ps | length) < 1 { break }
if $r == null { break }
let p = $ps | first
if ($p | describe -d).type == closure {
$r = ($r | do $p $r)
$ps = ($ps | range 1..)
continue
}
match ($r | describe -d).type {
record => {
if $p in $r {
$r = ($r | get $p)
} else {
$r = null
}
}
list => {
let ps = $ps
return ($r | each {|x| safe_get $ps $x })
}
_ => {
$r = null
}
}
$ps = ($ps | range 1..)
}
$r
}
def extract [tg obj] {
$tg
| transpose k v
| reduce -f {} {|i,a|
match ($i.v | describe -d).type {
list => {
let c = safe_get $i.v $obj
$a | upsert $i.k $c
}
record => {
let o = safe_get $i.v._ $obj
let t = $i.v | reject _
$a | upsert $i.k (main $t $o)
}
}
}
}
export def main [tg obj] {
if ($obj | describe -d).type == list {
$obj | each {|x| extract $tg $x }
} else {
extract $tg $obj
}
}

View File

@@ -0,0 +1,61 @@
use complete *
### refine kubernetes resources
export def kube-refine [
...namespace: string@"nu-complete kube ns"
--kind(-k): list<string@"nu-complete kube kind">
] {
use lg
let config = $env.KUBERNETES_REFINE
let nsf = if ($namespace | is-empty) {
{|x| $x not-in $config._namespace }
} else {
{|x| $x in $namespace}
}
let cns = kubectl get namespace
| from ssv -a
| get NAME
| filter $nsf
let resource = kubectl get crd | from ssv | get NAME
let resource = kubectl api-resources | from ssv -a | get NAME | append $resource
let resource = if ($kind | is-empty) {
$resource
} else {
$resource
| filter {|x| $x in $kind }
}
mut data = []
if ($namespace | is-empty) {
lg level 4 {stage: cluster}
for p in ($config.cluster_resources | transpose k v) {
if $p.k not-in $resource { continue }
lg level 3 {kind: $p.k} list
let rs = kubectl get $p.k | from ssv -a | get NAME
for r in $rs {
lg level 1 {kind: $p.k, name: $r} collect
let obj = kubectl get $p.k $r --output=json | from json
let pyl = refine $p.v $obj
$data ++= $pyl
}
}
}
lg level 4 {stage: namespace}
for p in ($config.resources | transpose k v) {
if $p.k not-in $resource { continue }
for ns in $cns {
lg level 2 {kind: $p.k, ns: $ns} list
let rs = kubectl get $p.k --namespace $ns | from ssv -a | get NAME
for r in $rs {
lg level 0 {kind: $p.k, ns: $ns, name: $r} collect
let obj = kubectl get $p.k --namespace $ns $r --output=json | from json
let pyl = refine $p.v $obj
$data ++= $pyl
}
}
}
$data
}

View File

@@ -0,0 +1,89 @@
export def ensure-cache-by-lines [cache path action] {
let ls = do -i { open $path | lines | length }
if ($ls | is-empty) { return false }
let lc = do -i { open $cache | get lines}
if not (($cache | path exists) and ($lc | is-not-empty) and ($ls == $lc)) {
mkdir ($cache | path dirname)
{
lines: $ls
payload: (do $action)
} | save -f $cache
}
(open $cache).payload
}
export def normalize-column-names [ ] {
let i = $in
let cols = $i | columns
mut t = $i
for c in $cols {
$t = ($t | rename -c {$c: ($c | str downcase | str replace ' ' '_')})
}
$t
}
export def --wrapped with-flag [...flag] {
if ($in | is-empty) { [] } else { [...$flag $in] }
}
export def `kcache flush` [] {
rm -rf ~/.cache/nu-complete/k8s/
nu-complete kube ctx
rm -rf ~/.cache/nu-complete/k8s-api-resources/
}
export def kube-shortnames [] {
kubectl api-resources | from ssv -a
| where SHORTNAMES != ''
| reduce -f {} {|i,a|
$i.SHORTNAMES
| split row ','
| reduce -f {} {|j,b|
$b | insert $j $i.NAME
}
| merge $a
}
}
export def parse_cellpath [path] {
$path | split row '.' | each {|x|
if ($x | find --regex "^[0-9]+$" | is-empty) {
$x
} else {
$x | into int
}
}
}
export def get_cellpath [record path] {
$path | reduce -f $record {|it, acc| $acc | get $it }
}
export def set_cellpath [record path value] {
if ($path | length) > 1 {
$record | upsert ($path | first) {|it|
set_cellpath ($it | get ($path | first)) ($path | range 1..) $value
}
} else {
$record | upsert ($path | last) $value
}
}
export def upsert_row [table col mask id value] {
# let value = ($mask | reduce -f $value {|it, acc|
# let path = (parse_cellpath $it)
# set_cellpath $value $path (get_cellpath $table $path)
# })
if $id in ($table | get $col) {
$table | each {|x|
if ($x | get $col) == $id {
$value
} else {
$x
}
}
} else {
$table | append $value
}
}

View File

@@ -0,0 +1 @@
source language/playground/lib.nu

View File

@@ -0,0 +1,54 @@
export def main [topic, closure] {
with-env {N: 5 REJECT: slow } {
print (echo $topic " tests" (char newline) | str join)
do $closure
}
}
export def scene [
topic: any
--tag: string
closure: closure
] {
print $" ($topic)(char newline)"
do $closure
}
export def play [
topic: any
--tag: string
closure: closure
] {
let is_tag_empty = ($tag | is-empty);
let should_run_all = ($env | get -i RUN_ALL | default false);
if $is_tag_empty {
do $closure $topic
} else {
if $tag == $env.REJECT and $should_run_all {
$" ($topic) ... (ansi yellow)skipped(ansi reset) (char newline)"
} else {
do $closure $topic
}
}
}
export def expect [
topic: string
actual: list<any>
--to-be: list<any>
] {
let are_equal = (($actual | length) == ($to_be | length)) and ($actual | zip $to_be | all {|case|
$case.0 == $case.1
}
)
let line = (if true == $are_equal {
$"(ansi green)ok(ansi reset)(char newline)"
} else {
$"(ansi red)failed(ansi reset)(char newline)"
}
)
$" ($topic) ... ($line)"
}

View File

@@ -0,0 +1 @@
source language/std/date.nu

View File

@@ -0,0 +1,7 @@
export def "date local" [now] {
insert time {|value|
let converted = ($now | date to-timezone $value.tz);
$converted | format date '%c'
}
}

View File

@@ -0,0 +1,34 @@
use ../playground *
use ../std/date.nu *
def mock-now [] {
"2021-08-29 03:31:21" | into datetime
}
def people [] {
[
[ 'name', 'tz'];
[ 'andres', 'America/Guayaquil']
[ 'fdncred', 'US/Central']
]
}
playground "std/date" {
scene 'command: "date local"' {
play "adds times in local timezone" {|topic|
let expected_times = [
"Sun Aug 29 03:31:21 2021"
"Sun Aug 29 03:31:21 2021"
] | into datetime;
let actual = (people | date local (mock-now) | get time | into datetime)
expect $topic $actual --to-be $expected_times
}
}
}

View File

@@ -0,0 +1,114 @@
def get_settings [] {
{
level: ($env.lg.level? | default 2)
file: ($env.lg.file?)
}
}
export-env {
$env.lg = {
prefix: ['TRC' 'DBG' 'INF' 'WRN' 'ERR' 'CRT']
index: {
trc: 0
dbg: 1
inf: 2 msg: 2
wrn: 3
err: 4
crt: 5
}
theme: {
console: {
level : (['navy' 'teal' 'xgreen' 'xpurplea' 'olive' 'maroon'] | each { ansi $in })
delimiter: $'(ansi grey39)│'
fg: (ansi light_gray)
bg: (ansi grey39)
terminal: (ansi reset)
}
file: {
level : ['' '' '' '' '' '']
delimiter: '│'
fg: ''
bg: ''
terminal: (char newline)
}
}
line_formatter: {|theme, align, max_key_len| {|y|
let k = if $align { $y.k | fill -a r -w $max_key_len } else { $y.k }
$" ($theme.bg)($k) = ($theme.fg)($y.v | to json -r)"
} }
}
}
def parse_msg [args] {
let time = date now | format date '%FT%T.%3f'
let s = $args
| reduce -f {tag: {}, txt:[]} {|x, acc|
if ($x | describe -d).type == 'record' {
$acc | update tag ($acc.tag | merge $x)
} else {
$acc | update txt ($acc.txt | append $x)
}
}
{time: $time, txt: $s.txt, tag: $s.tag }
}
export def --wrapped level [
level
...args
--multiline(-m)
--label: string
--setting: any
] {
let setting = if ($setting | is-empty) { get_settings } else { $setting }
let target = if ($setting.file? | is-empty) { 'console' } else { 'file' }
let theme = $env.lg.theme | get $target
let output = if ($setting.file? | is-empty) {{ print -e $in }} else {{ $in | save -af $setting.file }}
let msg = parse_msg $args
let time = $"($theme.level | get $level)($msg.time)"
let label = if ($label | is-empty) { '' } else { $"($theme.fg)($label)" }
let txt = $msg.txt | str join ' '
let txt = if ($txt | is-empty) { '' } else { $"($theme.fg)($txt)" }
let tag = $msg.tag | transpose k v
let r = if $multiline {
let align = $target == 'console'
let mkl = if $align { $tag | get k | each { $in | str length } | math max }
let body = $tag
| each (do $env.lg.line_formatter $theme $align $mkl)
| str join (char newline)
let head = [$time $label $txt]
| filter {|x| $x | is-not-empty }
| str join $theme.delimiter
[$head $body] | str join (char newline)
} else {
let tag = $tag
| each {|y| $"($theme.bg)($y.k)=($theme.fg)($y.v)"}
| str join ' '
[$time $label $tag $txt]
| filter {|x| $x | is-not-empty }
| str join $theme.delimiter
}
$r + $theme.terminal | do $output
}
def 'nu-complete log-prefix' [] {
$env.lg.index | columns
}
export def --wrapped main [
level: string@'nu-complete log-prefix'
--multiline(-m)
...args
] {
let setting = get_settings
let lv = $env.lg.index | get $level
if $lv < $setting.level {
return
}
let label = $env.lg.prefix | get $lv
if $multiline {
level $lv ...$args --label $label --setting $setting --multiline
} else {
level $lv ...$args --label $label --setting $setting
}
}

View File

@@ -0,0 +1,16 @@
# List any directory that does not follow a SemVer naming pattern
# For example
# - 1.0.1 is a valid directory name.
# - yeah_whatever_linter is not a valid directory name.
def ls-incorrect-dirs [] {
ls | where type == dir and name != 'scripts' | find --invert --regex '(\d+\.){2,}\d$' --columns [name]
}
let incorrect_count = (ls-incorrect-dirs | length);
if $incorrect_count > 0 {
print $"The following directories are named incorrectly: (char newline)"
print (ls-incorrect-dirs)
exit 1
} else {
exit 0
}

View File

@@ -0,0 +1,24 @@
def logtime [msg act] {
let start = (date now)
let result = (do $act)
let period = ((date now) - $start
| into duration --unit ns
| into string
| str replace ' ' '')
echo $'($start | format date '%Y-%m-%d_%H:%M:%S%z')(char tab)($period)(char tab)($msg)(char newline)'
| save -a ~/.cache/nushell/time.log
return $result
}
export def timelog [] {
open ~/.cache/nushell/time.log
| from tsv -n
| rename start duration message
| each {|x|
$x
| update start ($x.start | into datetime -f '%Y-%m-%d_%H:%M:%S%z')
| update duration ($x.duration | into duration)
}
}

View File

@@ -0,0 +1,7 @@
export def ls-hidden [
--dir(-d):any # The directory you want to list
] {
let dir = if ($dir | is-empty) { "." } else { $dir }
ls -a $dir | filter { ($in.name | into string | str starts-with '.') }
}

View File

@@ -0,0 +1,12 @@
# An attempt at trying to put ls into a paging mode
export def ls-less [
--dir(-d):any # The directory you want to list
] {
let is_empty = ($dir | is-empty)
if $is_empty {
nu -c 'ls' | less -r
} else {
let command = $"ls ($dir)"
nu -c $command | less -r
}
}

View File

@@ -0,0 +1,75 @@
alias relet = ansi -e '0m' # really reset but there are external commands for reset already
alias fg_black = ansi -e '30m'
alias fg_red = ansi -e '31m'
alias fg_green = ansi -e '32m'
alias fg_yellow = ansi -e '33m'
alias fg_blue = ansi -e '34m'
alias fg_magenta = ansi -e '35m'
alias fg_purple = ansi -e '35m'
alias fg_cyan = ansi -e '36m'
alias fg_white = ansi -e '37m'
alias fg_dark_gray = ansi -e '90m'
alias fg_light_black = ansi -e '90m'
alias fg_light_red = ansi -e '91m'
alias fg_light_green = ansi -e '92m'
alias fg_light_yellow = ansi -e '93m'
alias fg_light_blue = ansi -e '94m'
alias fg_light_magenta = ansi -e '95m'
alias fg_light_purple = ansi -e '95m'
alias fg_light_cyan = ansi -e '96m'
alias fg_light_gray = ansi -e '97m'
alias fg_light_white = ansi -e '97m'
# A ls command that approximates the ls -sh command in bash
export def ls-wide2 [
--dir(-d):any # The directory you want to list
--columns(-c):int # The number of columns in your output
] {
let is_dir_empty = ($dir | is-empty)
let is_columns_empty = ($columns | is-empty)
let ls_data = (if $is_dir_empty { ls } else { ls $dir })
let max_fname_size = ($ls_data | get name | into string | str length | math max)
let max_fsize_size = ($ls_data | get size | into string | str length | math max)
($ls_data) | enumerate | each { |file|
let clr_file = (colorize $file.item.name)
let clr_size = (echo $file.item.size | into string)
let new_line = (if $is_columns_empty {
if (($file.index + 1) mod 3) == 0 {
char newline
}
} else {
if (($file.index + 1) mod $columns) == 0 {
char newline
}
})
$"($clr_file | fill -a l -c ' ' -w $max_fname_size) ($clr_size | fill -a r -c ' ' -w $max_fsize_size) ($new_line)"
} | str join
}
def colorize [thing:any] {
let thing_as_string = (echo $thing | into string)
let ext = (echo $thing_as_string | path parse | get extension)
let is_empty = ($ext | is-empty)
if $is_empty {
$"(fg_cyan)($thing)(relet)"
} else {
if $ext == "nu" {
$"(fg_light_magenta)($thing)(relet)"
} else {
$"(fg_light_green)($thing)(relet)"
}
}
}
def colorit [] {
print (colorize 123)
print (colorize " 123.456")
print (colorize " file.nu")
# These all work
print $"(fg_light_green)abc(relet)"
print $"(fg_cyan)def(relet)"
}

View File

@@ -0,0 +1,47 @@
# A ls command that approximates the ls -sh command in bash
export def ls-wide [
--path(-p):string # The path you want to list
--columns(-c):int # The number of columns in your output
] {
let is_columns_empty = ($columns | is-empty)
let is_path_empty = ($path | is-empty)
let columns_default = 3
if $is_path_empty {
if $is_columns_empty {
run_ls "." $columns_default
} else {
run_ls "." $columns
}
} else {
if $is_columns_empty {
run_ls $path $columns_default
} else {
run_ls $path $columns
}
}
}
def run_ls [
path:string
columns:int
] {
let max_fname_size = (ls $path | get name | into string | str length | math max)
let max_fsize_size = (ls $path | get size | into string | str length | math max)
let is_columns_empty = ($columns | is-empty)
ls $path | enumerate | each { |file|
let the_file = ($file.item.name | into string | fill -a l -c ' ' -w $max_fname_size)
let the_size = ($file.item.size | into string | fill -a r -c ' ' -w $max_fsize_size)
let new_line = (if $is_columns_empty {
if ($file.index + 1) mod 3 == 0 {
char newline
}
} else {
if ($file.index + 1) mod $columns == 0 {
char newline
}
})
$"($the_file) ($the_size) ($new_line)"
} | str join
}

View File

@@ -0,0 +1,18 @@
let m_table = (
[
['name', 'tz', 'time'];
['andres' 'America/Guayaquil' ' ']
['fdncred' 'US/Central' ' ']
['gedge' 'US/Eastern' ' ']
['jt' 'NZ' ' ']
['wycats' 'US/Pacific' ' ']
['kubouch' 'Europe/Helsinki' ' ']
['elferherrera' 'Europe/London' ' ']
['storm' 'US/Pacific' ' ']
]
)
let now = (date now)
$m_table | update time {|row|
$now | date to-timezone ($row | get tz) | format date '%c'
}

View File

@@ -0,0 +1,32 @@
# A Script to try and create the table for the readme.md file
# | Category | File |
# | ---------------- | ----------------------------------------------------------------------------- |
# | coloring | [24bit-1.nu](./coloring\24bit-1.nu) |
# | coloring | [color_table.nu](./coloring\color_table.nu) |
# | coloring | [color_tables.nu](./coloring\color_tables.nu) |
# | coloring | [gradient.nu](./coloring\gradient.nu) |
# Right now there is still manual manipulation in order to update the README.md
# Hopefully, in the future someone will contribute a script to make this automatic.
let nu_files = (ls **/*.nu)
let nu_table = ($nu_files |
get name |
wrap File |
insert Category { |it|
let cat = ($it.File | path dirname)
if $cat == "" {
"not assigned yet"
} else {
$cat
}
} | where Category !~ ".git" | select Category File | sort-by Category)
# Let's fix the file now
let nu_table = ($nu_table | update File { |it|
let file_path = ($it.File | into string | str replace '\' '/' --all)
let file_name = ($file_path | path basename)
$"[($file_name)](char lparen)./($file_path)(char rparen)"
})
echo $nu_table | to md --pretty

View File

@@ -0,0 +1,289 @@
#Root with a custom denominator
export def root [ denominator, num ] {
$num ** ( 1 / $denominator ) | math round -p 10
}
#Cube root
export def croot [num] {
$num ** ( 1 / 3 ) | math round -p 10
}
#Root with a custom scaler and denominator
export def aroot [ scaler, denominator, num] {
$num ** ($scaler / $denominator) | math round -p 10
}
#calculate delta of the quadratic function
export def delta [ a,#x^2 factor
b, #x factor
c #the rest
] {
( $b ** 2 ) - ( 4 * $a * $c)
}
#Factorial of the given number
export def fact [num: int] {
if $num >= 0 {
if $num < 2 {
$num
} else {
seq 2 $num | math product
}
} else {
error make -u {msg: "can only calculate non-negative integers"}
}
}
#Calculate roots of the quadratic function: ax^2+bx+x
export def q_roots [
a # x^2
b # x
c # independent term
] {
let d = $b ** 2 - 4 * $a * $c
if $d > 0 {
let s = ($d | math sqrt)
let r1 = (($s - $b) / (2 * $a))
let r2 = (0 - (($s + $b) / (2 * $a)))
echo $"root #1: ($r1)"
echo $"root #2: ($r2)"
} else if $d == 0 {
let s = ($d | math sqrt)
let r = (($s - $b) / (2 * $a))
echo $"root: ($r)"
} else {
let s = ((0 - $d) | math sqrt)
let r = ((0 - $b) / (2 * $a))
let i = ($s / (2 * $a))
echo $"root #1: ($r) + ($i)*i"
echo $"root #2: ($r) - ($i)*i"
}
}
#Check if integer is prime
export def isprime [n: int] {
let max = ($n | math sqrt | math ceil)
let flag = ([[isPrime];[true]] | update isPrime {if ($n mod 2) == 0 { false } else { seq 3 1 $max | each { |it| if ($n mod $it) == 0 { false }}}})
if ($flag.isPrime.0 | is-empty) { echo 'prime' } else { echo 'not prime' }
}
#Prime list <= n
export def primelist [n: int] {
let primes = [2 3]
let primes2 = (seq 5 2 $n | each {|it| if (isprime $it) == 'prime' {$it}})
$primes | append $primes2
}
#Multiplication table of n till max
export def mtable [n: int, max: int] {
seq 1 $max | each {|it| echo $"($it)*($n) = ($n * $it)"}
}
#Check if year is leap
export def isleap [year: int] {
if ( (($year mod 4) == 0 and ($year mod 100) != 0) or ($year mod 400) == 0 ) { echo "It is a leap year." } else { echo "It is not a leap year."}
}
#Greatest common divisor (gcd) between 2 integers
export def gcd [a: int, b:int] {
if $a < $b {
gcd $b $a
} else if $b == 0 {
$a
} else {
gcd $b ($a mod $b)
}
}
#Least common multiple (lcm) between 2 integers
export def lcm [a: int, b:int] {
if $a == $b and $b == 0 {
0
} else {
$a * ($b / (gcd $a $b))
}
}
#Decimal number to custom base representation
export def dec2base [
n: string #decimal number
b: string #base in [2,16]
] {
let base = if ( ($b | into int) < 2 or ($b | into int) > 16 ) {
echo "Wrong base, it must be an integer between 2 and 16"
10
} else {
$b | into int
}
let number = ($n | into int)
let chars = ['0' '1' '2' '3' '4' '5' '6' '7' '8' '9' 'A' 'B' 'C' 'D' 'E' 'F']
if $number == 0 {
''
} else {
let newNumber = (($number - ($number mod $base)) / $base)
[(dec2base $newNumber $base) ($chars | get ($number mod $base))] | str join
}
}
# Scale list to [a,b] interval
export def scale-minmax [a, b,input?] {
let x = if ($input | is-empty) {$in} else {$input}
let min = ($x | math min)
let max = ($x | math max)
$x | each {|it| ((($it - $min) / ($max - $min)) * ($b - $a) + $a) }
}
# Scale every column of a table (separately) to [a,b] interval
export def scale-minmax-table [a, b,input?] {
let x = if ($input | is-empty) {$in} else {$input}
let n_cols = ($x | transpose | length)
let name_cols = ($x | transpose | column2 0)
0..($n_cols - 1)
| each {|i|
($x | column2 $i) | scale-minmax $a $b | wrap ($name_cols | get $i)
} | reduce {|it, acc| $acc | merge {$it}}
}
# compute the cartesian product of any number of lists
#
# basically, if you give `iter cartesian product` *n* lists, from *i_1* to *i_n*,
# it will compute recursively the cartesian product of the first one with the
# `iter cartesian product` of the rest, i.e. if we call CP the two-set cartesian
# product and ICP the multi cartesian product here, we have
#
# *ICP(i_1, i_2, ..., i_n) == CP(i_1, ICP(i_2, ..., i_n))*
#
# # Example
#```nushell
# use std ["assert equal" "iter iter cartesian product"]
#
# let res = (
# iter cartesian product [1, 2] [3, 4]
# )
#
# assert equal $res [
# [1, 3],
# [1, 4],
# [2, 3],
# [2, 4],
# ]
# ```
export def "cartesian product" [
...iters: list<any> # the iterables you want the cartesian product of
]: nothing -> list<list<any>> {
def aux [a: list<list<any>>]: nothing -> list<list<any>> {
if ($a | is-empty) {
return []
}
let head = $a | first
let tail = aux ($a | skip 1)
if ($head | is-empty) {
return $tail
} else if ($tail | is-empty) {
return $head
}
$head | each {|h| $tail | each {|t| [$h, $t]}} | flatten | each { flatten }
}
aux $iters
}
#[test]
def cartesian_product [] {
use std assert
# emptyness
assert equal (cartesian product [] []) []
assert equal (cartesian product []) []
assert equal (cartesian product) []
# symmetry
assert equal (cartesian product [1, 2] []) [1, 2]
assert equal (cartesian product [] [1, 2]) [1, 2]
# NOTE: `cartesian product` might not preserve the order of the elements produced
assert equal (
cartesian product [1, 2] [3, 4] | each { sort } | sort
) (
cartesian product [3, 4] [1, 2] | each { sort } | sort
)
assert equal (
cartesian product [1, 2] [3, 4]
) [
[1, 3], [1, 4], [2, 3], [2, 4]
]
assert equal (
cartesian product [1, 2] [3, 4] [5, 6]
) [
[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]
]
}
# `ways-to-add-up-to $n` is a list of all possible strictly-positive-integer sums that add up to `$n`
#
# # Example
# `ways-to-add-up-to 4` will be `[[1, 1, 1, 1], [1, 1, 2], [1, 3], [2, 2], [4]]]` because $4$
# can be obtained as follows:
# $$
# 4 = 1 + 1 + 1 + 1
# = 1 + 1 + 2
# = 1 + 3
# = 2 + 2
# = 4
# $$
export def ways-to-add-up-to [n: int]: [ nothing -> list<list<int>> ] {
if $n == 0 {
return []
} else if $n == 1 {
return [[1]]
}
ways-to-add-up-to ($n - 1)
| each { |it|
let a = $it | append [1]
let b = seq 0 ($it | length | $in - 1) | each { |i| $it | update $i { $in + 1 } }
[$a] ++ $b
}
| flatten
| each { sort }
| uniq
}
#[test]
def test [] {
use std assert
for it in [
[n, expected];
[0, []],
[1, [[1]]],
[2, [[1, 1], [2]]],
[2, [[1, 1], [2]]],
[3, [[1, 1, 1], [1, 2], [3]]],
[4, [[1, 1, 1, 1], [1, 1, 2], [1, 3], [2, 2], [4]]],
[5, [[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 4], [2, 3], [5]]],
] {
assert equal (ways-to-add-up-to $it.n | sort) ($it.expected | sort)
}
print "tests passed"
}

View File

@@ -0,0 +1,46 @@
# Remoting
This module provide convenient way to manage multiple remote clients.
## Prerequisites
* Both `ssh` and `ssh script` require ssh to be installed on the host
* `ssh script` requires nushell to be installed on the client
* `ssh` can work both with and without nushell installed on the client however having it installed enables more sophisticated interaction between host and clients
* `wake` requires wakeonlan to be installed on the host and clients to be configured to accept Wake on Lan magic packets
## `ssh` function
This function serves as a wrapper around standard ssh command.
Function accepts following arguments:
* name - Name of the client as specified in the config. This parameter is required (autocompletion enabled)
* args - command to run on the client. If not provided ssh starts an interactive session with the client. If provided and specified client has nushell configured output will be returned as nushell table on the host allowing further parsing. If provided and specified client does not have nushell configured output will be passed back as is
## `ssh script` function
This function executes a nushell script on a client that has nushell configured.
Function accepts following arguments:
* name - Name of the client as specified in the config. This parameter is required (autocompletion enabled)
* script - Name of the script to be executed on the client. This parameter is required The script must be available in current scope in order to be used (autocompletion enabled)
* args - Arguments to be passed to the script. Named parameters should be put in quotes to avoid parsing errors like this: `ssh script my-host my-script '--arg value'`
## `wake` function
This function wakes specified clients via Wake on Lan.
Function accepts following arguments:
* names - Name of clients to be woken up as specified in the config. (autocompletion enabled)
## Config
Client config is kept within (non-exported) `hosts` function as a list of records. Each record should contain following fields:
| Parameter | Is required? | Usage | Type |
|-----------|----------------------------------------|------------------------------|--------|
| name | Required | DNS name of the client | string |
| domain | Either domain or IP must be specified | DNS domain of the client | string |
| ip | Either domain or IP must be specified | IP address of the client | string |
| username | Required | Username used for connection | string |
| port | Required | SSH port | int |
| mac | Required only for `wake` | MAC address of the client | string |
| nu | Required | Whether nushell is installed | bool |
Example configuration records:
* {name: 'host1', domain: 'nushell.sh', ip: '', username: 'username', port: 22, mac: 'AA:BB:CC:DD:EE;FF', nu: false}
* {name: 'host2', domain: '', ip: '192.168.0.1', username: 'username', port: 2222, mac: '', nu: true}

View File

@@ -0,0 +1,98 @@
# internal function that holds the host data. We could store it in a yaml file as well but that would require nushell to read it from disk every single time
def hosts [] {
[
# Put your config here
]
}
def "nu-complete wol" [] {
hosts
|where mac != ''
|get name
}
def "nu-complete nu" [] {
hosts
|where nu
|get name
}
def "nu-complete hosts" [] {
hosts
|get name
}
def "nu-complete scripts" [] {
scope commands
|where is_custom
|get -i command
}
# Returns ssh connection as url to be consumed by original ssh command
def get-url [
host: record
] {
if 'ip' in ($host|columns) {
echo $"ssh://($host.username)@($host.ip):($host.port)"
} else {
echo $"ssh://($host.username)@($host.name).($host.domain):($host.port)"
}
}
# Connect over ssh to one of predefined hosts, execute nushell commands and parse them on the host
export def ssh [
hostname: string@"nu-complete hosts" # name of the host you want to connect to
...args # commands you wish to run on the host
] {
let host = (hosts|where name == $hostname|get -i 0)
if ($host.nu) {
if ($args|length) > 0 {
^ssh (get-url $host) (build-string ($args|str join ' ') '|to json -r')|from json
} else {
^ssh (get-url $host)
}
} else {
^ssh (get-url $host) $args
}
}
# Connect over ssh to one of predefined hosts, execute nushell script with arguments passed from the host
export def "ssh script" [
hostname: string@"nu-complete nu" # name of the host you want to connect to
script: string@"nu-complete scripts" # name of the script
...args # arguments you wish to pass to the script in key=value format
] {
let span = (metadata $script).span
if $script in (scope commands|where is_custom|get command) {
let host = (hosts|where name == $hostname|get 0)
let full_command = (build-string (view-source $script) '; ' $script ' ' ($args|str join ' ') '|to json -r')
^ssh (get-url $host) ($full_command)|from json
} else {
error make {
msg: $"($script) is not a custom command, use regular ssh command instead"
label: {
text: "Not a custom command",
start: $span.start,
end: $span.end
}
}
}
}
# Turns on specified hosts using Wake on Lan
export def wake [
...names: string@"nu-complete wol" # list of host names to wake
] {
hosts
|where name in $names
|each {|host|
if $host.mac != '' {
echo $"Waking ($host.name)"
wakeonlan $host.mac|ignore
} else {
error make {
msg: $"($host.name) does not support Wake on Lan"
}
}
}
}

View File

@@ -0,0 +1,4 @@
The `sockets` command returns a table containing information on network sockets and the processes they belong to.
It is basically a join of the tables produced by the `lsof` command, and the nushell `ps` command.
<img width="1486" alt="image" src="https://user-images.githubusercontent.com/52205/196287615-00e46f8e-06ed-45ce-8fe7-a5c5f38afaaa.png">

View File

@@ -0,0 +1,32 @@
export def sockets [--abbreviate-java-class-paths (-j)] {
let input = (^lsof +c 0xFFFF -i -n -P)
let header = ($input | lines
| take 1
| each { str downcase | str replace ' name$' ' name state' })
let body = ($input | lines
| skip 1
| each { str replace '([^)])$' '$1 (NONE)' | str replace ' \((.+)\)$' ' $1' })
[$header] | append $body
| to text
| detect columns
| upsert 'pid' { |r| $r.pid | into int }
| rename --column { name: connection }
| reject 'command'
| join-table (ps -l) 'pid' 'pid'
| if $abbreviate_java_class_paths {
upsert 'classpath' { |r| $r.command | java-cmd classpath }
| upsert 'command' { |r| $r.command | java-cmd abbreviate-classpath }
} else { $in }
}
export def 'java-cmd classpath' [] {
str replace '.* -classpath +(.+\.jar) +.*' '$1' | split row ':'
}
export def 'java-cmd abbreviate-classpath' [] {
str replace '[^ ]*\.jar' '*.jar'
}
export def join-table [table: table, left_on: string, right_on: string] {
dfr into df | join ($table | dfr into df) $left_on $right_on | dfr into nu
}

View File

@@ -0,0 +1,136 @@
export def ensure-cache [cache paths action] {
mut cfgs = []
for i in $paths {
let cs = (do -i {ls ($i | into glob)})
if ($cs | is-not-empty) {
$cfgs = ($cfgs | append $cs)
}
}
let cfgs = $cfgs
let ts = ($cfgs | sort-by modified | reverse | get 0.modified)
if ($ts | is-empty) { return false }
let tc = (do -i { ls $cache | get 0.modified })
if not (($cache | path exists) and ($ts < $tc)) {
mkdir ($cache | path dirname)
do $action | save -f $cache
}
open $cache
}
export def 'str max-length' [] {
$in | reduce -f 0 {|x, a|
if ($x|is-empty) { return $a }
let l = ($x | str length)
if $l > $a { $l } else { $a }
}
}
def "nu-complete ssh host" [] {
rg -LNI '^Host [a-z0-9_\-\.]+' ~/.ssh | lines | each {|x| $x | split row ' '| get 1}
}
export def parse-ssh-file [group] {
$in
| parse -r '(?<k>Host|HostName|User|Port|IdentityFile)\s+(?<v>.+)'
| append { k: Host, v: null}
| reduce -f { rst: [], item: {Host: null} } {|it, acc|
if $it.k == 'Host' {
$acc | upsert rst ($acc.rst | append $acc.item)
| upsert item { Host : $it.v, HostName: null, Port: null, User: null, IdentityFile: null, Group: $group }
} else {
$acc | upsert item ($acc.item | upsert $it.k $it.v)
}
}
| get rst
| where {|x| not (($x.Host | is-empty) or $x.Host =~ '\*')}
}
export def ssh-list [] {
rg -L -l 'Host' ~/.ssh
| lines
| each {|x| cat $x | parse-ssh-file $x}
| flatten
}
def fmt-group [p] {
$p | str replace $"($env.HOME)/.ssh/" ''
}
def "ssh-hosts" [] {
let cache = $'($env.HOME)/.cache/nu-complete/ssh.json'
ensure-cache $cache [~/.ssh/config ~/.ssh/config*/* ] { ||
let data = (ssh-list | each {|x|
let uri = $"($x.User)@($x.HostName):($x.Port)"
{
value: $x.Host,
uri: $uri,
group: $"(fmt-group $x.Group)",
identfile: $"($x.IdentityFile)",
}
})
let max = {
value: ($data.value | str max-length),
uri: ($data.uri | str max-length),
group: ($data.group | str max-length),
identfile: ($data.identfile | str max-length),
}
{max: $max, completion: $data}
}
}
def "nu-complete ssh" [] {
let data = (ssh-hosts)
$data.completion
| each { |x|
let uri = ($x.uri | fill -a l -w $data.max.uri -c ' ')
let group = ($x.group | fill -a l -w $data.max.group -c ' ')
let id = ($x.identfile | fill -a l -w $data.max.identfile -c ' ')
{value: $x.value, description: $"\t($uri) ($group) ($id)" }
}
}
export extern main [
host: string@"nu-complete ssh" # host
...cmd # cmd
-v # verbose
-i: string # key
-p: int # port
-N # n
-T # t
-L # l
-R # r
-D # d
-J: string # j
-W: string # w
]
def "nu-complete scp" [cmd: string, offset: int] {
let argv = ($cmd | str substring ..$offset | split row ' ')
let p = if ($argv | length) > 2 { $argv | get 2 } else { $argv | get 1 }
let ssh = (ssh-hosts | get completion
| each {|x| {value: $"($x.value):" description: $x.uri} }
)
let n = ($p | split row ':')
if $"($n | get 0):" in ($ssh | get value) {
^ssh ($n | get 0) $"sh -c 'ls -dp ($n | get 1)*'"
| lines
| each {|x| $"($n | get 0):($x)"}
} else {
let files = (do -i {
ls -a ($"($p)*" | into glob)
| each {|x| if $x.type == dir { $"($x.name)/"} else { $x.name }}
})
$files | append $ssh
}
}
export def --wrapped scp [
lhs: string@"nu-complete scp",
rhs: string@"nu-complete scp"
...opts
] {
^scp -r ...$opts $lhs $rhs
}

View File

@@ -0,0 +1,68 @@
# Nix
Commands for working with [nix/nixos](https://nixos.org/).
### ns
Shorthand search (`nix search nixpkgs ...`) with much nicer output.
```shell
> nix search nixpkgs diesel
* legacyPackages.x86_64-linux.diesel-cli (2.1.0)
Database tool for working with Rust projects that use Diesel
* legacyPackages.x86_64-linux.diesel-cli-ext (0.3.13)
Provides different tools for projects using the diesel_cli
```
```shell
> ns diesel
╭───┬────────────────┬──────────────────────────────────────────────────────────────┬─────────╮
# │ package │ description │ version │
├───┼────────────────┼──────────────────────────────────────────────────────────────┼─────────┤
0 │ diesel-cli │ Database tool for working with Rust projects that use Diesel │ 2.1.0 │
1 │ diesel-cli-ext │ Provides different tools for projects using the diesel_cli │ 0.3.13 │
├───┼────────────────┼──────────────────────────────────────────────────────────────┼─────────┤
# │ package │ description │ version │
╰───┴────────────────┴──────────────────────────────────────────────────────────────┴─────────╯
```
### activation-script
Shows changed packages after running `nixos-rebuild switch/boot` and change in total size of installed packages. Changes that don't affect the installed size are filtered out. Intended to be added to `configuration.nix` of `NixOS`.
```
╭────┬──────────────────┬───────────────────────┬────────┬────────────╮
│ # │ Package │ Old │ New │ Diff │
├────┼──────────────────┼───────────────────────┼────────┼────────────┤
│ 0 │ nushell │ 0.94.1 │ 0.95.0 │ 192.1 KiB │
│ 1 │ hyprland │ 0.41.1 │ 0.41.2 │ 52.9 KiB │
│ 2 │ qtdeclarative │ 6.7.1 │ 6.7.2 │ 36.2 KiB │
│ 3 │ linux │ 6.9.6 │ 6.9.7 │ 17.7 KiB │
│ 4 │ qtbase │ 6.7.1 │ 6.7.2 │ 16.1 KiB │
│ 5 │ networkmanager │ 1.48.0 │ 1.48.2 │ 8.3 KiB │
│ 6 │ wireplumber │ 0.5.3 │ 0.5.4 │ -21.4 KiB │
│ 7 │ libbacktrace │ 0-unstable-2024-03-02 │ ∅ │ -110.4 KiB │
│ 8 │ woff2 │ 1.0.2 │ ∅ │ -155.5 KiB │
│ 9 │ libmanette │ 0.2.7 │ ∅ │ -226.0 KiB │
│ 10 │ webkitgtk │ 2.44.2+abi=6.0 │ ∅ │ -147.6 MiB │
│ 11 │ telegram-desktop │ 5.1.8 │ ∅ │ -219.4 MiB │
│ 12 │ │ │ │ │
│ 13 │ │ │ Total: │ -367.2 MiB │
╰────┴──────────────────┴───────────────────────┴────────┴────────────╯
```
### nufetch
nu alternative to `neofetch`/`hyfetch`.
```
╭──────────┬───────────────────────────────────╮
│ kernel │ 6.11.0 │
│ nu │ 0.98.0 │
│ │ ╭─────────────┬────────┬────────╮ │
│ packages │ │ environment │ number │ size │ │
│ │ ├─────────────┼────────┼────────┤ │
│ │ │ system │ 825 │ 5.7 GB │ │
│ │ │ sperber │ 352 │ 1.5 GB │ │
│ │ │ steam │ 929 │ 5.4 GB │ │
│ │ ╰─────────────┴────────┴────────╯ │
│ uptime │ 3hr 1min 18sec │
╰──────────┴───────────────────────────────────╯
```

View File

@@ -0,0 +1,10 @@
### add to configuration.nix
nix.settings.experimental-features = ["nix-command"];
system.activationScripts.diff = ''
if [[ -e /run/current-system ]]; then
${pkgs.nushell}/bin/nu -c "let diff_closure = (${pkgs.nix}/bin/nix store diff-closures /run/current-system '$systemConfig'); let table = (\$diff_closure | lines | where \$it =~ KiB | where \$it =~ → | parse -r '^(?<Package>\S+): (?<Old>[^,]+)(?:.*) → (?<New>[^,]+)(?:.*), (?<DiffBin>.*)$' | insert Diff { get DiffBin | ansi strip | into filesize } | sort-by -r Diff | reject DiffBin); if (\$table | get Diff | is-not-empty) { print \"\"; \$table | append [[Package Old New Diff]; [\"\" \"\" \"\" \"\"]] | append [[Package Old New Diff]; [\"\" \"\" \"Total:\" (\$table | get Diff | math sum) ]] | print; print \"\" }"
fi
'';

View File

@@ -0,0 +1,18 @@
# Search nixpkgs and provide table output
export def ns [
term: string # Search target.
] {
let info = (
sysctl -n kernel.arch kernel.ostype
| lines
| {arch: ($in.0|str downcase), ostype: ($in.1|str downcase)}
)
nix search --json nixpkgs $term
| from json
| transpose package description
| flatten
| select package description version
| update package {|row| $row.package | str replace $"legacyPackages.($info.arch)-($info.ostype)." ""}
}

View File

@@ -0,0 +1,8 @@
export def main [] {
{
"kernel": $nu.os-info.kernel_version,
"nu": $env.NU_VERSION,
"packages": (ls /etc/profiles/per-user | select name | prepend [[name];["/run/current-system/sw"]] | each { insert "number" (nix path-info --recursive ($in | get name) | lines | length) | insert "size" ( nix path-info -S ($in | get name) | parse -r '\s(.*)' | get capture0.0 | into filesize) | update "name" ($in | get name | parse -r '.*/(.*)' | get capture0.0 | if $in == "sw" {"system"} else {$in}) | rename "environment"}),
"uptime": (sys host).uptime
}
}

View File

@@ -0,0 +1,133 @@
## neovim configurations
# local vcs_root = require('lspconfig.util').root_pattern('.git/')
# function HookPwdChanged(after, before)
# vim.b.pwd = after
# local git_dir = vcs_root(after)
# vim.api.nvim_command('silent tcd! '..(git_dir or after))
# end
# function OppositePwd()
# local tab = vim.api.nvim_get_current_tabpage()
# local wins = vim.api.nvim_tabpage_list_wins(tab)
# local cwin = vim.api.nvim_tabpage_get_win(tab)
# for _, w in ipairs(wins) do
# if cwin ~= w then
# local b = vim.api.nvim_win_get_buf(w)
# local pwd = vim.b[b].pwd
# if pwd then return pwd end
# end
# end
# end
# function ReadTempDrop(path, action)
# vim.api.nvim_command(action or 'botright vnew')
# local win = vim.api.nvim_get_current_win()
# local buf = vim.api.nvim_create_buf(true, true)
# vim.api.nvim_win_set_buf(win, buf)
# vim.api.nvim_command('read '..path)
# vim.fn.delete(path)
# end
def nvim_tcd [] {
[
{|before, after|
if ($env.NVIM? | is-not-empty) {
nvim --headless --noplugin --server $env.NVIM --remote-send $"<cmd>lua HookPwdChanged\('($after)', '($before)')<cr>"
}
}
]
}
# nvim tcd
export def tcd [path?: string] {
let after = if ($path | is-empty) {
$env.PWD
} else {
$path
}
nvim --headless --noplugin --server $env.NVIM --remote-send $"<cmd>lua HookPwdChanged\('($after)', '($env.PWD)')<cr>"
}
export-env {
$env.config = ( $env.config | upsert hooks.env_change.PWD { |config|
let o = ($config | get -i hooks.env_change.PWD)
let val = (nvim_tcd)
if $o == null {
$val
} else {
$o | append $val
}
})
}
# drop stdout to nvim buf
export def drop [] {
if ($env.NVIM? | is-empty) {
echo $in
} else {
let c = $in
let temp = (mktemp -t nuvim.XXXXXXXX|str trim)
$c | save -f $temp
nvim --headless --noplugin --server $env.NVIM --remote-send $"<cmd>lua ReadTempDrop\('($temp)')<cr>"
}
}
export def nvim-lua [...expr: string] {
if ($env.NVIM? | is-empty) {
echo "not found nvim instance"
} else {
nvim --headless --noplugin --server $env.NVIM --remote-send $'<cmd>lua vim.g.remote_expr_lua = ($expr|str join " ")<cr>'
do -i { nvim --headless --noplugin --server $env.NVIM --remote-expr 'g:remote_expr_lua' } | complete | get stderr
}
}
export def opwd [] {
nvim-lua 'OppositePwd()'
}
export def nve [action ...file] {
if ($env.NVIM? | is-empty) {
nvim ...$file
} else {
let af = $file
| each {|f|
if ($f|str substring ..1) in ['/', '~'] {
$f
} else {
$"($env.PWD)/($f)"
}
}
let action = if ($file | is-empty) { $action | str replace -r 'sp.*$' 'new' } else { $action }
let cmd = $"<cmd>($action) ($af|str join ' ')<cr>"
nvim --headless --noplugin --server $env.NVIM --remote-send $cmd
}
}
export alias e = nve vsplit
export alias v = nve vsplit
export alias c = nve split
export alias x = nve tabnew
export def nvs [port: int=9999] {
nvim --headless --listen $"0.0.0.0:($port)"
}
export def nvc [
addr: string
--gui(-g)
] {
if $gui {
let gs = {
neovide: [--maximized --server $addr]
}
for g in ($gs | transpose prog args) {
if (which $g.prog | is-not-empty) {
^$g.prog ...$g.args
break
}
}
} else {
nvim --remote-ui --server $addr
}
}

View File

@@ -0,0 +1,5 @@
# Parsing Scripts
### Definition
These scripts should be used to demonstrate how to parse any file format, including `json`, `csv`, etc. Also, perhaps parsing of `external` commands. For example, on Windows, perhaps we could wrap `ipconfig.exe` so that the output was more nushell friendly.

View File

@@ -0,0 +1,18 @@
[
{
"name": "Brunello Cucinelli",
"shoes": [
{ "name": "tasselled black low-top lace-up", "price": 1000 },
{ "name": "tasselled green low-top lace-up", "price": 1100 },
{ "name": "plain beige suede moccasin", "price": 950 },
{ "name": "plain olive suede moccasin", "price": 1050 }
]
},
{
"name": "Gucci",
"shoes": [
{ "name": "red leather laced sneakers", "price": 800 },
{ "name": "black leather laced sneakers", "price": 900 }
]
}
]

View File

@@ -0,0 +1,21 @@
def look_for [word] {
open sample_andres.json |
flatten |
flatten |
insert comp {
get shoes_name |
split row " " |
enumerate | each {
[[idx, loc]; [$in.index, ($in.item | str index-of $word)]]
} | flatten
} |
flatten |
where comp.loc >= 0 |
flatten |
update idx { $in + 1 } |
reject name price loc |
rename nameWords targetWordIndex
}
print (look_for "leather" | to json --indent 4)
print (look_for "low-top" | to json --indent 4)

View File

@@ -0,0 +1,31 @@
# Prompt Scripts
### Definition
These scripts should be used to draw a custom command prompt in nushell. They can include anything that we think is appropriate for prompts such as `git` commands, `starship`, `oh-my-posh`, etc.
#### starship.nu
File is in [starship](./starship.nu)
This describe how to use starship to make a leftprompt, the repo of starship is [here](https://github.com/starship/starship).
This script set the output of starship as leftprompt
![starshipshow](./images/starship.png)
#### shell_space.nu
File is in [shell_space](./shell_space.nu)
Use the function of shells in nu, you can view the function with the command following
```
help shells
```
![shell_spaceshow](./images/shell_space.png)
#### jalon-git.nu
From https://github.com/JalonWong/nushell-prompt
![jalon-git](./images/jalon-git.png)

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