diff --git a/maths/math_functions.nu b/maths/math_functions.nu index 2479e27..cb371fd 100644 --- a/maths/math_functions.nu +++ b/maths/math_functions.nu @@ -33,3 +33,147 @@ def fact [num: int] { echo 'Error: can only calculate non-negative integers' } } + +### Added by kira +## constants +let pi = 3.1415926535897932 +let e = 2.7182818284590452 + +#Calculate roots of the quadratic function: ax^2+bx+x +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 { + 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 +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 | empty?) { echo 'prime' } else { echo 'not prime' } +} + +#Prime list <= n +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 +def mtable [n: int, max: int] { + seq 1 $max | each {|it| echo $"($it)*($n) = ($n * $it)"} +} + +#Check if year is leap +def isleap [year: int] { + if ( (($year mod 4) == 0 && ($year mod 100) != 0) || ($year mod 400) == 0 ) { echo "It is a leap year." } else { echo "It is not a leap year."} +} + +#Greatest common divisior (gcd) between 2 integers +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 +def lcm [a: int, b:int] { + if $a == $b && $b == 0 { + 0 + } else { + $a * ($b / (gcd $a $b)) + } +} + +#Decimal number to custom base representation +def dec2base [ + n: string #decimal number + b: string #base in [2,16] +] { + let base = if ( ($b | into int) < 2 || ($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 collect + } +} + +# Scale list to [a,b] interval +def scale-minmax [a, b,input?] { + let x = if ($input | 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 +def scale-minmax-table [a, b,input?] { + let x = if ($input | empty?) {$in} else {$input} + let n_cols = ($x | transpose | length) + let name_cols = ($x | transpose | column2 0) + + for $i in 0..($n_cols - 1) { + ($x | column2 $i) | scale-minmax $a $b | wrap ($name_cols | get $i) + } | reduce {|it, acc| $acc | merge {$it}} +} + +#sin function +def "math sin" [ ] { + each {|x| "s(" + $"($x)" + ")\n" | bc -l | into decimal } +} + +#cos function +def "math cos" [ ] { + each {|x| "c(" + $"($x)" + ")\n" | bc -l | into decimal } +} + +#natural log function +def "math ln" [ ] { + each {|x| "l(" + $"($x)" + ")\n" | bc -l | into decimal } +} + +#exp function +def "math exp" [ ] { + each {|x| "e(" + $"($x)" + ")\n" | bc -l | into decimal } +} + diff --git a/miscelaneous/downup-plot b/miscelaneous/downup-plot new file mode 100755 index 0000000..03ef98f --- /dev/null +++ b/miscelaneous/downup-plot @@ -0,0 +1,4 @@ +#!/bin/bash + +#requieres fast-cli +fast --single-line --upload | stdbuf -o0 awk '{print $2 " " $6}' | ttyplot -2 -t "Download/Upload speed" -u Mbps diff --git a/miscelaneous/nu_defs.nu b/miscelaneous/nu_defs.nu new file mode 100644 index 0000000..6050383 --- /dev/null +++ b/miscelaneous/nu_defs.nu @@ -0,0 +1,405 @@ +#copy current dir +def cpwd [] {pwd | tr "\n" " " | sed "s/ //g" | xclip -sel clip} + +#update-upgrade system (ubuntu) +def supgrade [] { + echo "updating..." + sudo aptitude update -y + echo "upgrading..." + sudo aptitude safe-upgrade -y + echo "autoremoving..." + sudo apt autoremove -y +} + +#open mcomix +def mcx [file] { + bash -c $'mcomix "($file)" 2>/dev/null &' +} + +#open file +def openf [file?] { + let file = if ($file | empty?) {$in} else {$file} + + bash -c $'xdg-open "($file)" 2>/dev/null &' +} + +#search for specific process +def psn [name: string] { + ps | find $name +} + +#kill specified process in name +def killn [name: string] { + ps | find $name | each {kill -f $in.pid} +} + +#jdownloader downloads info (requires a jdown python script) +def nujd [] { + jdown | lines | each { |line| $line | from nuon } | flatten | flatten +} + +# Switch-case like instruction +def switch [ + var #input var to test + cases: record #record with all cases + # + # Example: + # let x = 3 + # switch $x { + # 1: { echo "you chose one" }, + # 2: { echo "you chose two" }, + # 3: { echo "you chose three" } + # } + ] { + echo $cases | get $var | do $in +} + +#post to discord +def post_to_discord [message] { + let content = $"{\"content\": \"($message)\"}" + + let weburl = "webhook_url" + + post $weburl $content --content-type "application/json" +} + +#select column of a table (to table) +def column [n] { + transpose | select $n | transpose | select column1 | headers +} + +#get column of a table (to list) +def column2 [n] { + transpose | get $n | transpose | get column1 | skip 1 +} + +#short pwd +def pwd-short [] { + $env.PWD | str replace $nu.home-path '~' -s +} + +#string repeat +def "str repeat" [count: int] { + each {|it| let str = $it; echo 1..$count | each { echo $str } } +} + +#join 2 lists +def union [a: list, b: list] { + $a | append $b | uniq +} + +#nushell source files info +def 'nu-sloc' [] { + let stats = ( + ls **/*.nu + | select name + | insert lines { |it| open $it.name | size | get lines } + | insert blank {|s| $s.lines - (open $s.name | lines | find --regex '\S' | length) } + | insert comments {|s| open $s.name | lines | find --regex '^\s*#' | length } + | sort-by lines -r + ) + + let lines = ($stats | reduce -f 0 {|it, acc| $it.lines + $acc }) + let blank = ($stats | reduce -f 0 {|it, acc| $it.blank + $acc }) + let comments = ($stats | reduce -f 0 {|it, acc| $it.comments + $acc }) + let total = ($stats | length) + let avg = ($lines / $total | math round) + + $'(char nl)(ansi pr) SLOC Summary for Nushell (ansi reset)(char nl)' + print { 'Total Lines': $lines, 'Blank Lines': $blank, Comments: $comments, 'Total Nu Scripts': $total, 'Avg Lines/Script': $avg } + $'(char nl)Source file stat detail:' + print $stats +} + +#go to dir (via pipe) +def-env goto [] { + let input = $in + cd ( + if ($input | path type) == file { + ($input | path dirname) + } else { + $input + } + ) +} + +#go to custom bash bin path, must be added last in config.nu +def-env goto-bash [] { + cd ($env.PATH | last) +} + +#cd to the folder where a binary is located +def-env which-cd [program] { + let dir = (which $program | get path | path dirname | str trim) + cd $dir.0 +} + +#push to git +def git-push [m: string] { + git add -A + git status + git commit -am $"($m)" + git push origin main +} + +#get help for custom commands +def "help my-commands" [] { + help commands | where is_custom == true +} + +#web search in terminal (requires ddgr) +def gg [...search: string] { + ddgr -n 5 ($search | str collect ' ') +} + +#habitipy dailies done all (requires habitipy) +def hab-dailies-done [] { + let to_do = (habitipy dailies | grep ✖ | awk {print $1} | tr '.\n' ' ' | split row ' ' | into int) + habitipy dailies done $to_do +} + +#update aliases backup file from config.nu +def update-aliases [] { + let nlines = (open $nu.config-path | lines | length) + + let from = ((grep "## aliases" $nu.config-path -n | split row ':').0 | into int) + + open $nu.config-path | lines | last ($nlines - $from + 1) | save /path/to/backup/file.nu +} + +#update config.nu from aliases backup +def update-config [] { + let from = ((grep "## aliases" $nu.config-path -n | split row ':').0 | into int) + let aliases = "/path/to/backup/file.nu" + + open $nu.config-path | lines | first ($from - 1) | append (open $aliases | lines) | save temp.nu + mv temp.nu $nu.config-path +} + +#countdown alarm (requires termdown y mpv) +def countdown [ + n: int # time in seconds + ] { + let BEEP = "/path/to/sound/file" + let muted = (pacmd list-sinks | awk '/muted/ { print $2 }' | tr '\n' ' ' | split row ' ' | last) + + if $muted == 'no' { + termdown $n;mpv --no-terminal $BEEP + } else { + termdown $n + unmute + mpv --no-terminal $BEEP + mute + } +} + +#get aliases +def get-aliases [] { + open $nu.config-path | lines | find alias | find -v aliases | split column '=' | select column1 column2 | rename Alias Command | update Alias {|f| $f.Alias | split row ' ' | last} | sort-by Alias +} + +#compress every subfolder into separate files and delete them +def 7zfolders [] { + ^find . -maxdepth 1 -mindepth 1 -type d -print0 | parallel -0 --eta 7z a -t7z -sdel -bso0 -bsp0 -m0=lzma2 -mx=9 -ms=on -mmt=on {}.7z {} +} + +#compress to 7z using max compression +def 7zmax [ + filename: string #filename without extension + ...rest: string #files to compress and extra flags for 7z (add flags between quotes) + # + # Example: + # compress all files in current directory and delete them + # 7zmax * "-sdel" +] { + + if ($rest | empty?) { + echo "no files to compress specified" + } else { + 7z a -t7z -m0=lzma2 -mx=9 -ms=on -mmt=on $"($filename).7z" $rest + } +} + +#add event to google calendar, also usable without arguments (requires gcalcli) +def addtogcal [ + calendar? #to which calendar add event + title? #event title + when? #date: yyyy.MM.dd hh:mm + where? #location + duration? #duration in minutes +] { + + let calendar = if $calendar == null {echo $"calendar: ";input } else {$calendar} + let title = if $title == null {echo $"\ntitle: ";input } else {$title} + let when = if $when == null {echo $"\nwhen: ";input } else {$when} + let where = if $where == null {echo $"\nwhere: ";input } else {$where} + let duration = if $duration == null {echo $"\nduration: ";input } else {$duration} + + gcalcli --calendar $"($calendar)" add --title $"($title)" --when $"($when)" --where $"($where)" --duration $"($duration)" --default-reminders +} + +#show gcal agenda in selected calendars +def agenda [ + --full: int #show all calendars (default: 0) + ...rest #extra flags for gcalcli between quotes (specified full needed) + # + # Examples + # agenda + # agenda --full true + # agenda "--details=all" + # agenda --full true "--details=all" +] { + let calendars = "your_selected_calendars" + let calendars_full = "most_calendars" + + if ($full | empty?) || ($full == 0) { + gcalcli --calendar $"($calendars)" agenda --military $rest + } else { + gcalcli --calendar $"($calendars_full)" agenda --military $rest + } +} + +#show gcal week in selected calendards +def semana [ + --full: int #show all calendars (default: 0) + ...rest #extra flags for gcalcli between quotes (specified full needed) + # + # Examples + # semana + # semana --full true + # semana "--details=all" + # semana --full true "--details=all" +] { + let calendars = "your_selected_calendars" + let calendars_full = "most_calendars" + + if ($full | empty?) || ($full == 0) { + gcalcli --calendar $"($calendars)" calw $rest --military --monday + } else { + gcalcli --calendar $"($calendars_full)" calw $rest --military --monday + } +} + +#show gcal month in selected calendards +def mes [ + --full: int #show all calendars (default: 0) + ...rest #extra flags for gcalcli between quotes (specified full needed) + # + # Examples + # mes + # mes --full true + # mes "--details=all" + # mes --full true "--details=all" +] { + let calendars = "your_selected_calendars" + let calendars_full = "most_calendars" + + if ($full | empty?) || ($full == 0) { + gcalcli --calendar $"($calendars)" calm $rest --military --monday + } else { + gcalcli --calendar $"($calendars_full)" calm $rest --military --monday + } +} + +#get bitly short link (requires xclip) +def mbitly [longurl] { + if ($longurl | empty?) { + echo "no url provided" + } else { + let Accesstoken = "Token" + let username = "user" + let url = $"https://api-ssl.bitly.com/v3/shorten?access_token=($Accesstoken)&login=($username)&longUrl=($longurl)" + + let shorturl = (fetch $url | get data | get url) + + $shorturl + $shorturl | xclip -sel clip + } +} + +#translate text using mymemmory api +def trans [ + ...search:string #search query] + --from:string #from which language you are translating (default english) + --to:string #to which language you are translating (default spanish) + # + #Use ISO standar names for the languages, for example: + #english: en-US + #spanish: es-ES + #italian: it-IT + #swedish: sv-SV + # + #More in: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes +] { + + if ($search | empty?) { + echo "no search query provided" + } else { + let key = "api_kei" + let user = "user_email" + + let from = if ($from | empty?) {"en-US"} else {$from} + let to = if ($to | empty?) {"es-ES"} else {$to} + + let to_translate = ($search | str collect "%20") + + let url = $"https://api.mymemory.translated.net/get?q=($to_translate)&langpair=($from)%7C($to)&of=json&key=($key)&de=($user)" + + fetch $url | get responseData | get translatedText + } +} + +#check if drive is mounted +def is-mounted [drive:string] { + let count = (ls "~/media" | find $"($drive)" | length) + + if $count == 0 { + false + } else { + true + } +} + +#get phone number from google contacts (requires goobook) +def get-phone-number [search:string] { + goobook dquery $search | from ssv | rename results | where results =~ '(?P\+)(?P\d+)' +} + +#ping with plot (requires bash png-plot using ttyplot) +def nu-png-plot [] { + bash -c png-plot +} + +#plot download-upload speed (requires bash downup-plot using ttyplot) +def nu-downup-plot [] { + bash -c downup-plot +} + +#plot data table using gnuplot +def gnu-plot [ + data? #1 or 2 column table + --title:string #title + # + #Example: If $x is a table with 2 columns + #$x | gnu-plot + #($x | column 0) | gnu-plot + #($x | column 1) | gnu-plot + #($x | column 0) | gnu-plot --title "My Title" + #gnu-plot $x --title "My Title" +] { + let x = if ($data | empty?) {$in} else {$data} + let n_cols = ($x | transpose | length) + let name_cols = ($x | transpose | column2 0) + + let ylabel = if $n_cols == 1 {$name_cols | get 0} else {$name_cols | get 1} + let xlabel = if $n_cols == 1 {""} else {$name_cols | get 0} + + let title = if ($title | empty?) {if $n_cols == 1 {$ylabel | str upcase} else {$"($ylabel) vs ($xlabel)"}} else {$title} + + $x | to tsv | save data0.txt + sed 1d data0.txt | save data.txt + + gnuplot -e $"set terminal dumb; unset key;set title '($title)';plot 'data.txt' w l lt 0;" + + rm data*.txt | ignore +} \ No newline at end of file diff --git a/miscelaneous/png-plot b/miscelaneous/png-plot new file mode 100755 index 0000000..382bf87 --- /dev/null +++ b/miscelaneous/png-plot @@ -0,0 +1,3 @@ +#!/bin/bash + +ping 1.1.1.1 | sed -u 's/^.*time=//g; s/ ms//g' | ttyplot -t \"ping to 1.1.1.1\" -u ms diff --git a/weather/weatherdark.nu b/weather/weatherdark.nu new file mode 100644 index 0000000..b6b905e --- /dev/null +++ b/weather/weatherdark.nu @@ -0,0 +1,192 @@ +# Weather Script based on IP Address +# - Weather using dark weather api +# - Air polution condition using airvisual api +# - Street address using google maps api +# - Version 2.0 +export def-env weatherds [] { + get_weather (get_location 0) +} + +# location functions thanks to https://github.com/nushell/nu_scripts/tree/main/weather +def locations [] { + [ + [location city_column state_column country_column lat_column lon_column]; + ["http://ip-api.com/json/" city region countryCode lat lon] + ["https://ipapi.co/json/" city region_code country_code latitude longitude] + ["https://freegeoip.app/json/" city region_code country_code latitude longitude] + ["https://ipwhois.app/json/" city region country_code latitude longitude] + ] +} + +def get_location [index: int] { + let wifi = (iwgetid -r) + let loc_json = (fetch (locations | select $index).0.location) + + # if ip address in your home isn't precise, you can force a location + if $wifi =~ "my_wifi" { "your_lat,your_lon" } else { $"($loc_json.lat),($loc_json.lon)" } +} + +# dark sky +def fetch_api [loc] { + let apiKey = "ds_api_key" + let options = "?lang=en&units=si&exclude=minutely,hourly,flags" + + let url = $"https://api.darksky.net/forecast/($apiKey)/($loc)($options)" + + fetch $url +} + +# street address +def get_address [loc] { + let mapsAPIkey = "maps_api_key" + let url = $"https://maps.googleapis.com/maps/api/geocode/json?latlng=($loc)&sensor=true&key=($mapsAPIkey)" + + (fetch $url).results.0.formatted_address +} + +# wind description (adjust to your liking) +def desc_wind [wind] { + if $wind < 30 { "Normal" } else if $wind < 50 { "Moderate" } else if $wind < 60 { "Strong" } else { "Very Strong" } +} + +# uv description (standard) +def uv_class [uvIndex] { + if $uvIndex < 2.9 { "Low" } else if $uvIndex < 5.9 { "Moderate" } else if $uvIndex < 7.9 { "High" } else if $uvIndex < 10.9 { "Very High" } else { "Extreme" } +} + +# air pollution +def get_airCond [loc] { + let apiKey = "airvisual_api_key" + let lat = (echo $loc | split row ",").0 + let lon = (echo $loc | split row ",").1 + let url = $"https://api.airvisual.com/v2/nearest_city?lat=($lat)&lon=($lon)&key=($apiKey)" + let aqius = (fetch $url).data.current.pollution.aqius + + # clasification (standard) + if $aqius < 51 { "Good" } else if $aqius < 101 { "Moderate" } else if $aqius < 151 { "Unhealthy for some" } else if $aqius < 201 { "Unhealthy" } else if $aqius < 301 { "Very unhealthy" } else { "Hazardous" } +} + +# parse all the information +def get_weather [loc] { + + let response = (fetch_api $loc) + let address = (get_address $loc) + let air_cond = (get_airCond $loc) + + ## Current conditions + let cond = $response.currently.summary + let temp = $response.currently.temperature + let wind = $response.currently.windSpeed * 3.6 + let humi = $response.currently.humidity * 100 + let uvIndex = $response.currently.uvIndex + let suntimes = ($response.daily.data | select sunriseTime sunsetTime | select 0 | update cells {|f| $f | into string | into datetime -o -4 | into string}) + + let sunrise = ($suntimes | get sunriseTime | get 0 | split row ' ' | get 3) + let sunset = ($suntimes | get sunsetTime | get 0 | split row ' ' | get 3) + let vientos = (desc_wind $wind) + let uvClass = (uv_class $uvIndex) + + let Vientos = $"($vientos) \(($wind | into string -d 2) Km/h\)" + let humedad = $"($humi)%" + let temperature = $"($temp)°C" + + let current = { + "Condition": ($cond) + Temperature: ($temperature) + Humidity: ($humedad) + Wind: ($Vientos) + "UV Index": ($uvClass) + "Air condition": ($air_cond) + Sunrise: ($sunrise) + Sunset: ($sunset) + } + + ## Forecast + let forecast = ($response.daily.data | select summary temperatureMin temperatureMax windSpeed humidity precipProbability precipIntensity uvIndex | update windSpeed {|f| $f.windSpeed * 3.6} | update precipIntensity {|f| $f.precipIntensity * 24} | update precipProbability {|f| $f.precipProbability * 100} | update humidity {|f| $f.humidity * 100} | update uvIndex {|f| uv_class $f.uvIndex} | update windSpeed {|f| $"(desc_wind $f.windSpeed) \(($f.windSpeed | into string -d 2)\)"} | rename Summary "T° min (°C)" "T° max (°C)" "Wind Speed (Km/h)" "Humidity (%)" "Precip. Prob. (%)" "Precip. Intensity (mm)") + + ## plots (require custom command gnu-plot) + ($forecast | select "Humidity (%)") | gnu-plot + ($forecast | select "Precip. Intensity (mm)") | gnu-plot + ($forecast | select "Precip. Prob. (%)") | gnu-plot + ($forecast | select "T° max (°C)") | gnu-plot + ($forecast | select "T° min (°C)") | gnu-plot + + ## forecast + echo $"Forecast: ($response.daily.summary)" + echo $forecast + + ## current + echo $"Current conditions: ($address)" + echo $current +} + + +# Get weather for right command prompt (set in config.nu) +export def-env get_weather_by_interval [INTERVAL_WEATHER] { + let weather_runtime_file = (($env.HOME) | path join .weather_runtime_file.json) + + if ($weather_runtime_file | path exists) { + let last_runtime_data = (open $weather_runtime_file) + + let LAST_WEATHER_TIME = ($last_runtime_data | get last_weather_time) + + if ($LAST_WEATHER_TIME | into datetime) + $INTERVAL_WEATHER < (date now) { + let WEATHER = (get_weather_for_prompt (get_location 0)) + let NEW_WEATHER_TIME = (date now | date format '%Y-%m-%d %H:%M:%S %z') + + $last_runtime_data | upsert weather $WEATHER | upsert last_weather_time $NEW_WEATHER_TIME | save $weather_runtime_file + + $WEATHER + } else { + $last_runtime_data | get weather + } + } else { + let WEATHER = (get_weather_for_prompt (get_location 0)) + let LAST_WEATHER_TIME = (date now | date format '%Y-%m-%d %H:%M:%S %z') + + let WEATHER_DATA = { + "weather": ($WEATHER) + "last_weather_time": ($LAST_WEATHER_TIME) + } + + $WEATHER_DATA | save $weather_runtime_file + $WEATHER + } +} + +def get_weather_for_prompt [loc] { + + let response = (fetch_api $loc) + + ## current conditions + let cond = $response.currently.summary + let temp = $response.currently.temperature + let temperature = $"($temp)°C" + let icon = (get_weather_icon $response.currently.icon) + + let current = { + Condition: ($cond) + Temperature: ($temperature) + Icon: ($icon) + } + + echo $"($current.Icon) ($current.Temperature)" +} + +def get_weather_icon [icon: string] { + switch $icon { + "clear-day": {"☀️"}, + "clear-night": {"🌑"}, + "rain": {"🌧️"}, + "snow": {"❄️"}, + "sleet": {🌨️}, + "wind": {"🌬️"}, + "fog": {"🌫"}, + "cloudy": {"☁️"}, + "partly-cloudy-day": {"🌤️"}, + "partly-cloudy-night": {"🌑☁️"}, + "hail": {🌨}, + "thunderstorm": {"🌩️"}, + "tornado": {"🌪️"} + } +} \ No newline at end of file