LINUX.ORG.RU

Сообщения LINUX-ORG-RU

 

Получить WID из PID

 , window id, ,

Запускаю через скрипт приложение

  • (appname 2>&1 > /dev/null) & echo $!
  • Читаю результат $! получив PID отпочковавшейся дочки
  • Запускаю wmctrl -lp ищу в строке PID и забираю соответствующий WID
  • Всё, я довольный, могу через WID манипулировать окном и пришибать процесс через PID точно зная что есть активная пара PID/WID и я не пришибу случайно что-то иное.

Всё работает. Но с некоторыми приложениями например glxgears беда. PID я его получаю, а вот WID найти не могу, да я могу wmctrl без параметров запустить, мышкой кликнуть на окошечко и получить WID, но это не то, не получается зная лишь PID получить WID. С большинством приложений проблем нет, а тут уже не знаю где искать. Сейчас ситуация такая что я запускаю приложеньку, жду несколько секунд пытаясь получить WID окна, если не получилось, грохаю процесс, ну и типа фиг с ним, не судьба :(

Не сообщает _NET_WM_PID оно, жопка такая. Выхода нет? Ключ поверни и по-ле-те-ли И однозначно не определить?

Варианты поиска по заголовкам окон и по содержанию командной строки не прокатят, заголовка может не быть вовсе и могут быть много окон с пустыми заголовками. Блин :(

Решение:

LINUX-ORG-RU
()

Разбраинфакaлка данных на вашем ПеКа

 , , , ,

В прошлый раз данные на домашних ПеКа захренакались, настало время их расхренакать обратно с помощью квинтэссенции говнокода, обычно все хвалятся что пишут brainfuck интерпретатор там в 200 байт, а то и меньше, но у инвалидов мозга типа меня своя олимпиада, поэтому размер интерпретатора 1200+ строк и 45+ килобайт весом. И это я ещё сократил, оставив попытки раскручивать циклы поняв что это глупая затея лишь тогда когда сделал действительно корректную раскрутку циклов во время исполнения через собственно генерацию раскрученных трасс циклов. Ну и ладно.

Собственно вот зачем интерпретатор

Для возможности непрерывно исполнять код который генерируется через Браинфакалка данных вашего ПеКа по мере его генерации , а не просто загрузить всё и потом выполнять.

Конечно Lua не для этого и тормоза, но в режиме исполнения под Luajit вполне себе терпимо

Да, это в режиме тупой транcляции в Lua код и его исполнения.

Всё вроде бы я наигрался, эксперимент закончен. Может кому надо, есть утилита и модуль который можно использовать самостоятельно, дебаг, трассировка исполнения, возможность отключать часть или все оптимизации, и запускать из под разных реализаций Lua не через правку исходника, а через ключик. Всякая хрень с учётом типа конца строк EOL ,\r,\r\n,\n и поведения окончания данных EOF ибо некоторые браинфук программы хотят специфичных вещей.

Описание параметров

Usage:  braintractor -i [FILE] -o [FILE]
        braintractor -e ',+.+.+.+.+.+.+'
        cat mandelbrot.bf | braintractor

 Execute input brainfuck code with or without
 different optimisations like transplitter to
 lua code and execute him, repeated operations
 optimisation and cycles jump optimisation.
 Cheking brainfuck syntax is correct.
 Handle debug symbol `#` and allow trace all code
 in execution time with trace lua function.
 This brainfuck language interpretor not very faster but flexibly.

Arguments:
   -h --help      This help information
   -              Execute brainfuck source code from stdin
   -i [FILE]      Execute filename with brainfuck source code
   -e [TEXT]      Execute brainfuck source code from string
   -o [FILE]      Output filename for write execution output
                  if output not set out writed to stdout

   -fi [FILE]     Send data to brainfuck programm from file
   -si [TEXT]     Send data to brainfuck programm from string


   -dj            Disable cycles jump optimisation
   -dr            Disable repeated operations optimisation
   -dt            Disable transplitter to lua optimisation
   -dz            Disable zero cell [+] [-] [<] [>] optimisations
   -da            Disable all optimisations

   -ds            Disable stream execution

   -dl            Disable set newline after terminal ouput
   -dd            Disable '#' symbol in brainfuck source code
   -do            Disable (force) any output (tracer worked)

   -sb [NUMBER]   Source buffer size for stream execution
                  minimum=1, maximum=2^31. (Default:100)
                  If posible braintractor execute this
                  chunks size or load more source code

   -tr [TEXT]     Lua function for trace brainfuck execution

   -dn            Disable check newline in input reader.
                  By default enabled checking '\n' if
                  input data ended but no have '\n' force
                  add this EOL LF symbol as last input symbol
                  this useful for varian set input as string
                  like -s 'someinput' -> 'someinput\n' you
                  can set other variant for EOL not '\n'

   -l [TEXT]      Select lua implementation for execute
                  lua5.1, lua5.2, lua5.3, lua5.4, luajit
                  By default used system '#!/usr/bin/env lua'

   Some brainfuck programs expect different behavior for
   end of line. Setting bottom transparent fix input for
   different behavior end of line. LF , CR, CRLF. You can
   enable only one variant. If set more last disable other
   By default enabled -eof_lf if input no have '\n' in line end
   force added '\n' in last input data. Use -dn for disable it

   -eol_lf        Enable check end of line and force set LF == '\n'
                  if input have '\r' or '\r\n' this option
                  change it to single '\n'. (nix way)

   -eol_cr        Enable check end of line and force set CR == '\r'
                  if input have '\n' or '\r\n' this option
                  change it to single '\r'. (old osx way)

   -eol_crlf      Enable check end of line and force set CRLF == '\r\n'
                  if input have '\n' or '\r' this option change
                  it to two end of line symbols '\r\n'. (windows way)

   Some brainfuck programs expect different behavior for end of file
   some expect write '0' in memory cell, some need save cell value
   and skip write other value in cell and some needed write -1 in cell
   Options bottom can enable one of varians. By default enabled -eol_zero
   You can enable only one varian. If set more last disable other.

    -eof_zero      If no have data to read, write 0 in memory cell m[i]=0

    -eof_eof       If no have data to read, write -1 in memory cell m[i]=-1

    -eof_skip      if no have data save cell value m[i]=m[i] (it like clamp)

    -eof_same      same as -eof_skip, just alias, it's easier to remember :)


   Notice about default execution mode and configuration:

   By default execute source maked in strem mode, brainfuck
   source load in small chunck, chunck optimised and executed
   this makes it possible to execute code as it is received,
   without waiting for it to be fully loaded. Also, this is
   only possible if it is possible to isolate independent parts
   from the flow that are not included in the body of any loop
   You can set minimal buffer for load or disable stream mode

   By default debug symbol '#' executed, you can disable it
   No cell memory limit, you can use over 30000 cells
   No memory position limit, brainfuck code can use
   negative cell indexes. If you need check memory limit
   or check index allowed ranges you can use tracer -tr

   Notice about optimisations:

                  By default all optimisations is enabled.
                  You can disable some one or all. The more
                  you disable, the slower the code will run

   Notice about input data variants:

                  If input data taked from PIPE and brainfuck
                  have read ',' command need use -fi or -si options
                  for send data in brainfuck reader ',' command.

                  If input data from file -i or string -e
                  brainfuck read from stdin. Imposible
                  use PIPE for load source code and for
                  take input for brainfuck code. Or or.

   braintractor -e ',..'                   # ok - you take interactive input
   braintractor -i code.b                  # ok - you take interactive input
   echo ',..' | braintractor -fi /dev/tty  # ok - you take interactive input
   echo ',..' | braintractor -fi input.txt # ok - input from file
   echo ',..' | braintractor -si 'a'       # ok - input from string

   echo ',..' | braintractor              # error, stdin empty after PIPE
                                          # need direct send input data
                                          # need directly use -f or -s

   About trace function:

   If you set trace function, this function be executed
   in brainfuck execution loop for any operations. But
   if you no disable repeater optimisation -dr, tracer miss
   some repeated operations, for example this code
   '+++.+++' in tracer show 3 trace becouse +++ combine
   to single '+' next one '.' and again single '+'
   if you set -dr tracer show full 7 operations per symbol.

   Example tracer:

   c - brainfuck code symbol
   i - brainfuck cell memory index
   v - brainfuck cell memory value
   r - repeated counter after operations or 1
   p - source code position, depend of optimisations, set -da -ds for correct

   -tr 'function(c,i,v,r,p) print(c,i,v,r,p) end'

   For example you can disable output -do and all optimisations
   and just use custom tracer debugger for you brainfuck code

   For example check memory usage no more 10 cells, and check negative index

   -tr 'function(_,i) if i > 10 then error('MEM OVERFLOW!')   end end'
   -tr 'function(_,i) if i <  0 then error('NEGATIVE INDEX!') end end'

   Warning: tracer execute any lua code, ANY LUA CODE! This mean
   you need set correct code, no use copypaste code from internet.
   If tracer function incorrect this application crashed.

Код и документация тут:

Запускать можно прям из каталога, модуль подхватится который рядом лежит.

Локальные установка и удаление в $HOME/.local/

#Установка
make PREFIX=$HOME/.local install install-cli
#Удаление
make PREFIX=$HOME/.local uninstall uninstall-cli

Баги и чиcтка кода, оооой всё потом. Потому что нет времени очередная поделочка в процессе. Так и живём, тяп ляп и готово :)

Досвиданья.

LINUX-ORG-RU
()

Подсветка синтаксиса для brainfuck

 

Было бы неплохо, если возможно. Нужно редко, зато

Чисто для справки ссылки:

Test

>+++++[<++++>-]<--[>++++++++++++<-]>--------.>+++++++[<------->-]<+++.>+++++++[<
+++++++>-]<---.>++++++[<----->-]<+++.>++++++[<+++++>-]<--.>++++++++++++[>+++++++
++++<-]>---.>>+++++[<++++>-]<--[>++++++++++++<-]>-------.>++++++++++++[>++++++++
+++<-]>--.>+++++++[>+++++<-]>---.>>+++++[<++++>-]<--[>++++++++++++<-]>--------.>
+++++[<---->-]<+++.>+++++[<++++>-]<---.>+++++[<---->-]<++.>+++++[<++++>-]<--.>++
++++[<----->-]<++.>+++++[<++++++>-]<-.>++++++++++++[>+++++++++++<-]>---.>>+++++[
<++++>-]<--[>++++++++++++<-]>--------.>+++++[<------>-]<.>+++++[<++++++>-]<.>+++
+++[<----->-]<+++.>++++++[<+++++>-]<--.>++++++++++++[>+++++++++++<-]>--.>>+++++[
<++++>-]<--[>++++++++++++<-]>--------.>+++++[<----->-]<+++.>+++++[<+++++>-]<---.
>+++++[<----->-]<+.

Сокращение для указания подсветки ```bf норм было бы.


Отмена:
Геморная реализация и некому будет поддерживать. Ну и ладна

LINUX-ORG-RU
()

Браинфакалка данных вашего ПеКа

 , , , пора спать,

Договнокодил очередное ненужно. А именно транслятор произвольных данных в код на brainfuck который будучи исполненным выводит закодированные в нём данные. Текст, картинка, чво угодно.

Типа cat /dev/random | brainfucktor -o bigbrainfuck.b

Или устроить «матрицу» brainfucktor -i /dev/random

Так то это просто ради экспериментов, но может кому надо я фиг знаю, кодировщик в виде модуля Lua конечно же и утилита командной строки покрывающая все его возможности, из возможностей просто игра генерирования разного brainfuck кода из одних и тех же данных. Работает на любой версии Lua от 5.1 до 5.4+

Код тормоз, такой же как и я. Для оптимизации его надо целиком переписывать и на Сях, но в этом нет смысла, это забава для небольших данных, хотя жрать может любые размеры, перегнать 10 мегабайт уже вечность, так что это просто для мелочи, если вдруг надо :D

Описание параметров

Usage:  brainfucktor -i [FILE] -o [FILE]
        brainfucktor -e 'encode this text to brainfuck'
        cat file | brainfucktor - #read from pipe
        brainfuck photo.png -o photo.bf

Encode input data to code in brainfuck language

Arguments:

   -h --help     This help information
   -             Input read from stdin
   -i  [FILE]    Input  filename for read
   -o  [FILE]    Output filename for write
   -e  [TEXT]    Input from command line argument

   -cb [NUMBER]  Cycle body size factor (>=1 default=2 )
   -cs [NUMBER]  Cycle split factor     (>=1 default=16)
   -cd [NUMBER]  Cycle distance factor  (>=1 default=64)
   -vd [NUMBER]  Value distance factor  (>=1 default=8 )
   -ch [NUMBER]  Separate input by chunks size (>=1 default=1024 bytes)
   -ml [NUMBER]  Set max line size for split output ( >=1 default 80 bytes)
   -sl           Create single line output (this disabled -ml option)
   -pc           Print currect configuration for code generation

You can skip -i option and just set filename, but filename expect first

Пример вывода Hello World! с немного разными настройками генерации

brainfucktor -e 'Hello World!'
+++++++++++[>+++++++<-]>-----.>+++++[<++++++>-]<-.+++++++..+++.>+++++++[>+++++<
-]>---.>++++++++++[<++++++>-]<-----.>+++++[<+++++>-]<-.+++.------.--------.>+++
+++[>++++++<-]>---.
brainfucktor -e 'Hello World!' -vd 50
+++++++++++[>+++++++<-]>-----.+++++++++++++++++++++++++++++.+++++++..+++.>+++++
++[>+++++<-]>---.>++++++++++[<++++++>-]<-----.++++++++++++++++++++++++.+++.----
--.--------.>++++++[>++++++<-]>---.
brainfucktor -e 'Hello World!' -cd 4
+++++++++++[>+++++++<-]>-----.>++++++++++++[>+++++++++<-]>-------.+++++++..+++.
>+++++++[>+++++<-]>---.>++++++++++[>+++++++++<-]>---.>+++++++++++++[>+++++++++<
-]>------.+++.------.--------.>++++++[>++++++<-]>---.
brainfucktor -e "Hello World!" -vd 128
+++++++++++[>+++++++<-]>-----.+++++++++++++++++++++++++++++.+++++++..+++.-------
------------------------------------------------------------------------.+++++++
++++++++++++++++++++++++++++++++++++++++++++++++.++++++++++++++++++++++++.+++.--
----.--------.------------------------------------------------------------------
-.
brainfucktor -e "Hello World!" -vd 1 -cs 8
>+++[<++++>-]<-[>+++++++<-]>-----.>+++++[<++++++>-]<-.>+++[<+++>-]<--..>+[<+++>-
]<.>+++++++[>+++++<-]>---.>++++++++++[<++++++>-]<-----.>+++++[<+++++>-]<-.>+[<++
+>-]<.>++[<--->-]<.>+++[<--->-]<+.>++++++[>++++++<-]>---.

Если использовать модуль напрямую, то он гибкий, может жрать таблицу, файл, строку
и выплёвывать возвратом строки от функции или писать в таблицу, файл, функцию. Ввод обрабатывается поблочно, чанками его размер регулируется от 1 до 2^31.

Сгенерированный код при исполнении жрёт ячеек памяти в максимуме N*2 где N количество закодированных байт, в минимуме жрёт всего 2 ячейки памяти, а дальше их переиспользует. Для исполнения больших 50+ мегебайт блоков кода с циклами нужен интерпретатор brainfuck без ограничений на память в 30000 ячеек. :D

Код жирный, прям как я, поэтому сюда не влезет несмотря на то что я влез. Как мы недавно узнали нейроидиоты не могут в браинфук,
а это значит у нас есть средство борьбы со скайнетом, когда терминаторы придут и роботы заполонят эту плонету, мы будем общаться на этом простом и красивом языке :)

- использовать на свой страх и риск

Код и документация тут

Запускать можно прям из каталога, модуль подхватится который рядом лежит.

Локальные установка и удаление в $HOME/.local/

#Установка
make PREFIX=$HOME/.local install install-cli
#Удаление
make PREFIX=$HOME/.local uninstall uninstall-cli

Хоп и твой дистрибутив стал почти как Slackware :D

Изначально было всего 15 строчек. Но я нахлобучил дублирующегося кода и лапши на ifах до ~500 строк :D
Двойные комментарии ваще шедевр, надо было ещё и на китайском написать лол. Вроде всё.

Досвиданья.

LINUX-ORG-RU
()

GVim и встроенный терминал

 , , , ,

Блин, Vim а точнее GVim большой я в нём запутался. Короче использую встроенный в вим терминал :term всё хорошо, но захотелось вывод скролить мышкой, а он не скролится. Полез узнать почему вобщем надо перейти в обычный режим, но по Esc он не переходит туда ибо у терминала отдельное пространство чего-то там, ладно есть комбинации мышки ctrl+w N я не псих чтобы это каждый раз прожимать надо повесить на Esc, ладно повесил tnoremap <ESC> <C-W>N, теперь всё почти хорошо, а именно ввёл что надо в терминале нажал Esc вим захватил буфер терминала и перешёл в режим Normal теперь это просто буфер который я могу что хочу делать и мышкой скролить, но вот беда если теперь нажать i или a для ввода то эта дура при нажатии и одновременном входе в режим ввода в этом терминале выполняет последнее что было введено в шелл оболочке и надо после выхода из терминала по Esc входить в него через заглавную I тогда этой фигни нету. Блин, чё этот терминал так черезжопно там встроен. Не мне нравится, прям няяяяяяя, оч удобно, но ну вот захотел я мышкой в нём скролить и выходит в нём в обычный режим по Esc, но случается то что выше описал. Как нормально сделать и без побочных эффектов?

  • 1 Ввести :term открыть терминал
  • 2 Нажать Esc выйти в терминале из режима ввода в режим Normal
  • 3 Скролить мышкой буфер терминала в Normal режиме терминала
  • 4 Нажать i войти в терминале в режим ввода и писать туда команды

  • 1 - работает [ОК]
  • 2 - работает если в конфиге задан бинд tnoremap <ESC> <C-W>N [ОК]
  • 3 - работает если в конфиге задана set mouse=a полная поддержка мышки [ОК]
  • 4 - работает через жопу, при нажатии i исполняется команда в терминале последняя, надо жать I [НЕЕЕЕ ОК]
    • я не хочу жать I, я хочу жать i так же как для всего остального
      • я не хочу переназначать i на I из за этого для всего

Сейчас либо жать I для нормального перехода в режим ввода в терминале, или жать i и получать внезапно исполнение комманды в нём которая в башхистори последняя.

100 лет уже в конфиг вима не залезал, всё устраивало, но вот полез хотелки делать и застрял :( Я что-то, где-то не вижу или недопонимаю, хотелка с виду простая, но то что у терминала там свой скоуп, свои назначения клавиш только геморой дают. Блин. Как быть то.

dron@gnu:~$ vim  --version
VIM - Vi IMproved 9.1 (2024 Jan 02, сборка от Apr 27 2024 15:01:43)
Исправления: 1-377
dron@gnu:~$ uname -a
Linux gnu 6.7.12-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.7.12-1 (2024-04-24) x86_64 GNU/Linux

LINUX-ORG-RU
()

Опубликован релиз-кандидат эталонной реализации языка Lua 5.4.7-rc1

 , , ,

Опубликован релиз-кандидат эталонной реализации языка Lua 5.4.7-rc1
Группа Разработка

Язык Lua – это мощный, переносимый, легковесный, встраиваемый и простой язык программирования, разработанный и развиваемый Роберту Иерузалимски в PUC-Rio вот уже более 30 лет.

Это минорный релиз посвящённый исправлению ошибок и улучшению документации. К использованию приглашаются все, кого затронули ошибки прошлой версии и все, кто имеет желание протестировать текущую. Если вы заметили ошибку или желаете связаться с авторами языка, это возможно исключительно через список рассылки. Любые патчи и рекомендации приветствуются, но важно помнить что они с вашей стороны будут всегда нести рекомендательный характер и будут так восприняты.

( читать дальше... )

>>> Подробности (google.com)

LINUX-ORG-RU
()

Видео записывалка для вашего ПеКа

 , slop, , ,

Я внезапно открыл для себя утилиту slop, очень удобная и полезная в домашних делах. Ага я слоупок.
Надо было записать кусочек экрана несколько раз и удобно выделять мышкой область на экране для записи видео.

Наваял вот, может кому пригодится.

  • Переменная use_recorder задаёт то чем вы ходите записывать
    • ffmpeg
    • recordmydesktop
  • Если передать скрипту аргументы то они прокинутся к утилите записи
    • например record --no-sound если используется recordmydesktop
      • но прокидывайе аргументы с умом рм рф и прочую копипасту туда писать не надо.

Ключи под себя

  • ffmpeg быстро пишет и сразу кодирует без звука.
  • recordmydesktop со звуком и отложенным долгим кодированием

Сам использую нубский recordmydesktop так как вокруг него не надо с бубном бегать по поводу звука (он меня сломан на ПК и чисто программный идёт по сети)

touch $HOME/.local/bin/record
#copy-paste code
chmod +x $HOME/.local/bin/record
  • Прерывать запись через ctrl+C
  • Зависимости в теле написаны какие надо.

Если кажется многословным перепишете на bash, всё можно переписать на bash :)

#!/usr/bin/env lua
-----------------------------------------
-- Depends for recordmydesktop: ogv out
-- apt install lua slop recordmydesktop
-----------------------------------------
-- Depends for ffmpeg: mp4 out
-- apt install lua slop ffmpeg
-----------------------------------------
-- Use ffmpeg or recordmydesktop recorder
--local use_recorder = 'ffmpeg'
local use_recorder = 'recordmydesktop'
-------------------------------------------------------------------------------
local separator = ' '
local arguments = table.concat({...},separator)
local visualfmt = '-b 5 -c 0.5,1.0,0.5,0.8 -o'
local slop_pipe = io.popen('slop -f "%x %y %w %h" '..visualfmt)
local x,y , w,h = slop_pipe:read('*l'):match('(%d+) (%d+) (%d+) (%d+)')
-------------------------------------------------------------------------------
local out_filename = os.date('%Y-%m-%H-%M-%S');
-------------------------------------------------------------------------------
local command = {};
-------------------------------------------------------------------------------
if use_recorder == 'ffmpeg' then
   command = table.concat(
   {
       'ffmpeg ','-f x11grab';
                 '-video_size',w..'x'..h;
                 '-grab_x',x;
                 '-grab_y',y;
                 '-i :0.0';
                 '-framerate 60';
                 '-vcodec libx264';
                  arguments;
                  out_filename..'.mp4';
   },separator)
   print('Run command:\n'..command)
   os.execute(command)
   return 0
end
-------------------------------------------------------------------------------
if use_recorder == 'recordmydesktop' then
   command = table.concat(
   {
       'recordmydesktop','-x='..x;
                         '-y='..y;
                         '--width='..w;
                         '--height='..h;
                         '--fps=60';
                          arguments;
                         '-o',out_filename..'.ogv';
   },separator)
   print('Run command:\n'..command)
   os.execute(command)
   return 0
end
-------------------------------------------------------------------------------
print("[ERROR]: Bad 'use_recorder' value.")
return 1

Вроде мелочёвка, а очень и очень удобно.
Всё. Досвиданья.

LINUX-ORG-RU
()

Как понять что ты тупой?

 , , , профнепригодность,

Очень просто! Нужно встретить задачу которая понятна буквально на интуитивном уровне. Открыть редактор и не суметь её решить сходу.
В голове переклинивает, ты точно знаешь что тебе надо делать и ступоришься на том как делать. Замираешь и смотришь на экран как додик последний. Кабзда, если извилины шевелятся то у моих кататония. Это фиаско братан :D Я не знаю с чем это сравнить, это как налить чаю, взять ложку и думать, тебе туда соль сыпать или сахар и офигевать от того что ыт об этом вообще задумываешься. Это просто пример, такой шизы у меня нету. Но хотелось яркого сравнения.

Короче сижу я такой и думаю дай полистаю PIL четвёртое издание для Lua, а то память у меня как решето постоянно всё забываю и надо по кругу гонять одно и тоже, ну типа листаю и листаю, типа ну ага, ну эге и тут задачка банальная как банан.

Exercise 6.5: Write a function that takes an array and prints all combinations of the elements in the array.
(Hint: you can use the recursive formula for combination: C(n,m) = C(n -1, m -1) + C(n - 1, m). To generate
all C(n,m) combinations of n elements in groups of size m, you first add the first element to the result and
then generate all C(n - 1, m - 1) combinations of the remaining elements in the remaining slots; then you
remove the first element from the result and then generate all C(n - 1, m) combinations of the remaining
elements in the free slots. When n is smaller than m, there are no combinations. When m is zero, there is
only one combination, which uses no elements.)

Упражнение 6.5: Напишите функцию, которая принимает массив и выводит все комбинации элементов в массиве.
(Подсказка: вы можете использовать рекурсивную формулу для комбинации: C (n,m) = C(n -1, m -1) + C(n - 1, m). Чтобы сгенерировать
все C(n, m) комбинаций из n элементов в группах размером m, вы сначала добавляете первый элемент к результату и
затем генерируете все C(n - 1, m - 1) комбинации оставшихся элементов в оставшихся ячейках; затем вы
удаляете первый элемент из результата и затем генерируете все C(n - 1, m) комбинации оставшихся
элементов в свободных ячейках. Когда n меньше, чем m, комбинаций не существует. Когда m равно нулю, существует
только одна комбинация, в которой не используются элементы.)

Для таких же тупых как я, нужно вывести все комбинации из элементов массива, комбинации должны быть заданного размера, а не просто длинны массива, исходный массив не должен быть модифицирован, реализация должна быть на основе хвостовой рекурсии, которую Lua автоматически устраняет.

И йя не смог. Вот прям сразу взять и написать. Истории успеха это конечно здорово, когда всё получается, когда всё складно и ладно, выезжаешь во всё лишь получив вводные. Вот про это все пишут все это смакуют. А вот провалы, спотыкания на ровном месте, затупы вселенских масштабов. Они у вас бывают? А как часто? Есть тру стори, похожего характера, когда вас прям переклинивало/ет? В расчёт не берутся случаи когда вы я фиг знаю дебажите неизвестный вам протокол или делаете что-то для области знаний где для вас вся терминология в новинку, там то понятно сходу по определению невозможно ничего сделать. Но вот в обыденных ситуациях, ну или не совсем оных. Признавайтесь! Чё я один такой глупый? :D

А линукс тут при том что линукс для умных.

LINUX-ORG-RU
()

У кого на улице сугробы?

 , , , ,

Ну не сугробы, но пару сантиметров уже навалило. Метель стоит как в феврале.

LINUX-ORG-RU
()

Отрицательная масса у фундаментальных (и не только) «частиц»

 , , , ,

Беседа с физиком теоретиком: Анатолием Григорьевичем Шкловским и его теоретические выкладки по поводу отрицательной массы и как она проявляется. Влияя и объясняя как фундаментальные так и макроскопические процессы и явления.

Кратко – Допущение существования элементарных частиц с отрицательной массой. И объяснение через них таких вещей к примеру как наличие воды на земле как косвенное следствие вытеснения протонов из земного ядра и регистрируемые сверх энергетические космические лучи с энергиями в терраэлектронвольт и многое многое другое включая прямое объяснение огромного количества других уже существующих физических эффектов, явлений, наблюдений. То есть при должной теоретической части уже подтверждается текущими экспериментами (вернее теория объясняет то что в них происходит)

Исходя из описания имеет базу достаточную для экспериментальной проверки, а так же имеет теоретический фундамент вписывающийся в текущую фундаментальную модель мира, дополняя её, но явно заявленная как альтернативная теория в качестве основы которой стоит принцип наименьшего действия по модулю из которого следует лавина эффектов проявляющаяся в виде того что мы называем вселенная и тех явлений что мы пытаемся объяснить через науку называемую физикой. Принцип наименьшего действия по модулю это ключевая особенность теории (по мнению меня) позволяющая не нарушая законов и не создавая парадоксов дать новый взгляд (или проявить истинный) на фундаментальные механизмы образования и строения материи как таковой.

Ты физик? Жопа горит? :) Опровергни или бабабол :D
Дискас.

LINUX-ORG-RU
()

Чего Debian штормит?

 

Не ставится gnumeric полез поискать пакет

Service Unavailable

The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
Apache Server at packages.debian.org Port 443

А до этого микродрама

И там сообщения ниже по ходу драмы.

Раньше такой фигни не было. Есть новости? Мол «Мы там что-то обновляем блабла»? Не могу найти.

Полез уточнять

Да удалили из testing. Но без причины (вернее она есть, но не повод для удаления)

Чёблин опять на stable отказываться или на до unstable обновляться? :)

Смысла в этом посте нет, я просто побубнить. И apt новый == дура!

Я всё понимаю это testing специально на нём и сижу, но чёт со всех сторон по мелочи, то это то сё. Для меня всё это дикость, *ть лет всё как часы, и на тебе кучка мелких пакостей разом. Gnumeric через пару дней (или прямо сейчас) вернут, не страшно. Эт я так к слову что поисковик падать стал.

LINUX-ORG-RU
()

DOOM 30 Лет. МЕГАВАД от русского сообщества всем в подарок.

 , , ,

Сама новость и описание на gamedev.ru



Закидываете в один каталог

  • 30years.wad
  • DOOM2.WAD
  • GZDoom-g4.11.1-x86_64.AppImage

И запускаете

./GZDoom-g4.11.1-x86_64.AppImage -file 30years.wad

DOOM2.WAD подхватится сам

UDP: Тут ниже чёт панику наводят про звонки от киркоровых и шифровальщики. Помнитя, бинарники левые эта всегда апасна. А то мало ли… Ну и есть firejail (не советую с appimage люто тормозит, обычные архивы брать) или вируталки если что, а то мало ли чё! Воть

LINUX-ORG-RU
()

Вырос на годик 🥳

 , , , инкремент,

LINUX-ORG-RU
()

А у кого то работает CSGO Legacy?

 , , , ,

КС2 вышла, но непоиграть вулкана нету да и эмуляцию опкодов я ещё не допилил в форке op_emu. Но захотелось хоть в паблике побегать полчасика, качнул CSGO Legacy сменив параметрах бета версии в настройках запуска, а оно мне Ошибка сегментирования :( Смысла писать куда то им нет, поддержки игры больше нет.

Запустил под strace у меня валится после vfork Пока не особо разбирался, но пока разбираюсь может у кого вдруг работает и это чисто у меня проблемы.


Решение

cp "/home/$USER/.steam/steam/ubuntu12_32/steam-runtime/amd64/lib/x86_64-linux-gnu/libpng12.so.0.46.0" \
"/home/$USER/.steam/debian-installation/steamapps/common/Counter-Strike Global Offensive/bin/linux64/libpng12.so.0"

Путь до ubuntu12_32/... и steamapps/... может быть чуть разный

Игру запускать через терминал из каталога игры

  • ./csgo.sh Игра только с ботами

или

  • ./csgo.sh -steam Игра на паблик серверах

В ServerBrowser поломаны шрифты, оно прогружает список серверов но показывает пустоту, если кликнуть туда где должны быть названия сереров происходит подключение и можно гамать онлайн с людьми. Пока не знаю как шрифты пофиксить.

Через кнопку в стиме не запускается и через стимовое подключение к серверам не работает пишет что неправильный номер приложения, а через саму игру подключается, но не показывает, надо в пустоту просто кликнуть… Во казлы специально всё поломали :(

  • UPD переключить язык на английский в настройках игры в стиме.
LINUX-ORG-RU
()

Qemu + Android x86 + Поворот экрана.

 , , ,

Зашёл я значит сюда

Взял скрипт, перевёл его в Makefile.

#----------------------------------------#
THIS_DIR=$(shell pwd)
ANDROID_API=31
ANDROID_ARCH=x86_64
ANDROID_HOME=$(THIS_DIR)/emulator
PHONE_MODEL=Nexus_5
#----------------------------------------#
mkdir:
	mkdir -p $(ANDROID_HOME);
#----------------------------------------#
tools:
	export ANDROID_HOME=$(ANDROID_HOME); \
	sdkmanager "emulator"                \
	           "cmdline-tools;latest"    \
	           "platforms;android-31"    \
	           "platform-tools"
#----------------------------------------#
imgdep:
	export ANDROID_HOME=$(ANDROID_HOME);                 \
	$(ANDROID_HOME)/cmdline-tools/latest/bin/sdkmanager  \
	     "system-images;android-$(ANDROID_API);default;$(ANDROID_ARCH)"
#----------------------------------------#
create:
	export ANDROID_HOME=$(ANDROID_HOME);                            \
	$(ANDROID_HOME)/cmdline-tools/latest/bin/avdmanager create avd  \
	--tag default --package "system-images;android-$(ANDROID_API);default;$(ANDROID_ARCH)" --sdcard 64M \
	--device "$(PHONE_MODEL)" --name $(PHONE_MODEL)_API_$(ANDROID_API)
#----------------------------------------#
start_emulator:
	export ANDROID_HOME=$(ANDROID_HOME);                        \
	$(ANDROID_HOME)/emulator/emulator @Nexus_5_API_$(ANDROID_API)
#----------------------------------------#
create_emulator: mkdir tools imgdep create

Жму такой make create_emulator start_emulator и такой думаю, ща я буду устанавливать все игрыapk, а не копировать по тормозному bluetooh на железо… А оно мне, «Где мои 17 лет на большой каретной», предъявите говорит SSE4. Ну вот :(
Некоторые пишут что можно задать эмулятор как x86, но оно валится всё ещё на этапе загрузки. А не запуска как с x86_64

Ладна, попёрся сюда

Накатил в qemu android-x86-9.0-r2.iso пересобрал apk с поддержкой x86 и всё работает. Но!!!

Великая беда и я не нашёл в интернете ответа.
Может ли qemu сказать запущенной в нем ОС что экран перевернулся?
Или в android x86 что-то дёрнуть? Может через ndk как что дрыгнуть можно?

Просто в qemu android x86 работает в каком-то режиме планшета,
изменение размера окна просто растягивает пропорционально картинку и всё.

Запускается всё если что вот так, может важно. В ~/.bashrc функция

kvm-qrun() 
{
    kvm -drive file=$1,format=raw  --device virtio-vga-gl -display gtk,gl=on -m 4096 -cpu host -smp  4 --enable-kvm  -net user,hostfwd=tcp::9922-:22 -net nic
}

kvm-qrun android.qcow2

Есть мысли? Как экран то повернуть? Я понимаю что если получится оно реально будет верх ногами например так как откуда qemu знает что надо перевёрнутую картинку ещё раз перевернуть уже чисто для показа, но хоть как, или никак? :(

Если нет то ладно, хоть запускать можно всякое для проверки и то хорошо. Но, всё же вдруг как то можно.


UPD: Никак

LINUX-ORG-RU
()

И Снег и Сугробы и Ёлки на вашем ПеКа

 , , ,

--           Зависимости              -
---------------------------------------
-- curl    -  загрузка ёлочек         -
-- scrot   -  снимок рабочего стола   -
-- love2d  -  запуск снежка и ёлочек  -
---------------------------------------
-- Создать каталог `новый_год`        -
-- Создать в каталоге файл `main.lua` -
-- Скопировать в файл этот код.       -
-- Используя терминал запутсить из    -
-- созданного каталога программу      -
--                                    -
--   Вот так запустить  `love .`      -
---------------------------------------
--            Управление              -
---------------------------------------
-- Нажать 1 - установит фон рабочего  -
--            стола в программе, как  -
--            будто на нём идёт снег  -
---------------------------------------
-- Нажать 2 - убрать сугробы, но снег -
--            то падает и они вырастут-
--            снова, но другие уже :) -
---------------------------------------
-- Нажать 3 - Загрузить и отобразить  -
--            просту ёлочку           -
---------------------------------------
-- Нажать 4 - Загрузить и установить  -
--            нарядную новогоднюю ёлку-
---------------------------------------
-- Нажать 5 - Вернуть чёрный фон      -
---------------------------------------
--    Нажать esc или q для выхода     -
---------------------------------------
-- Программа проверяет время и если   -
---------------------------------------
-- Время 23:45 - Загружается и отобра -
--               жается простая ёлочка-
---------------------------------------
-- Время 00:00 - Загружается и отобра -
--               жается нарядная ёлка -
---------------------------------------
-- Эти действия по времени происходят -
-- автоматически предупреждая о под-  -
-- ходе и наступлении нового года гы  -
---------------------------------------
-- Устанавливать ли фон автоматически -
---------------------------------------
local autobackround = false; --вкл/выкл
---------------------------------------
local sugrob = {}
local snow   = {};
local snow_opacity = 0;
local screen_width = 0;
local screen_height= 0;
local tree_image = nil;
local background = nil;
local tree_opacity = 0;
local tree_url =
{
  [1] = 'https://i.ibb.co/f24xCMp/1.png';
  [2] = 'https://i.ibb.co/KLpSKdZ/2.png';
};
local once_call_tree_1 = true;
local once_call_tree_2 = true;
----------------------------------------
function get_app_path()
    return love.filesystem.getSaveDirectory()..'/';
end
function load_tree(id)
   if love.system.getOS() == 'Android' then
      if id == 1 then
         tree_image = love.graphics.newImage('tree_1.png');
      end
      if id == 2 then
         tree_image = love.graphics.newImage('tree_2.png');
      end
      tree_opacity = 0;
      return;
   end
   local path = get_app_path();
   os.execute('curl '..tree_url[id]..' --output '..path..'tree.png');
   if love.filesystem.getInfo('tree.png')  then
      tree_image = love.graphics.newImage('tree.png');
      tree_opacity = 0;
   end
end
function draw_tree()
    if tree_image then
    local w = love.graphics.getWidth()
    local h = love.graphics.getHeight()
    local sx,sy = w/tree_image:getWidth(),h/tree_image:getHeight();
    love.graphics.setColor(1,1,1,tree_opacity);
       love.graphics.draw(tree_image,0,0,0,sx,sy);
    end
end
function update_tree(dt)
    if tree_opacity < 1 then
       tree_opacity = tree_opacity + 0.1 * dt;
    end
end
function create_sugrob()
    if love.system.getOS() == 'Android' then
       return;
    end
    local x = love.graphics.getWidth()
    local y = love.graphics.getHeight()
    local s = x/y;
    for i=1,50 do
        local xp = love.math.random(0,x);
        local cs = love.math.random(s*25,s*75);
        table.insert(sugrob,{'fill',xp,y,cs,150})
    end
end
function draw_sugrob()
    if love.system.getOS() == 'Android' then
       return;
    end
    love.graphics.setColor(0.95,0.95,1,1);
    for i=1,#sugrob do
        love.graphics.circle(sugrob[i][1],sugrob[i][2],sugrob[i][3]+sugrob[i][5],sugrob[i][4]);
    end
end
function update_sugrob(dt)
    local x,y = love.window.getMode();
    for i=1,#sugrob do
        if sugrob[i][5] > 0 then
           sugrob[i][5] = sugrob[i][5] - love.math.random(0.0,i*0.05)
        end
    end
end
function create_snow()
    local x = love.graphics.getWidth()
    local y = love.graphics.getHeight()
    local s = x/y;
    for i=1,60 do
        local xp = love.math.random(0,x);
        local xy = love.math.random(0,y);
        local cs = love.math.random(s*1,s*10);
        table.insert(snow,{'fill',xp,xy,cs,0})
    end
end
function draw_snow()
    for i=1,#snow do
        love.graphics.setColor(0.95,0.95,1,snow_opacity);
        love.graphics.circle(snow[i][1],snow[i][2],snow[i][3],snow[i][4]+snow_opacity);
    end
end
function lerp(from, to, t)
  return t < 0.5 and from + (to-from)*t or to + (from-to)*(1-t)
end
function update_snow(dt)
    local x,y = love.window.getMode();
    if snow_opacity < 0.7 then
       snow_opacity = snow_opacity + 0.1 * dt;
    end
    for i=1,#snow do
        snow[i][3] = snow[i][3] + i * 0.5;
        if snow[i][5] == 1 then
           snow[i][2] = snow[i][2] + i * 0.25 + i * 0.5 + love.math.random(0,3);
       elseif snow[i][5] == 0 then
           snow[i][2] = snow[i][2] - i * 0.25 + i * 0.5 + love.math.random(0,3);
        end
        if(snow[i][3] > y + snow[i][4]) then
          snow[i][3] = -snow[i][4];
          snow[i][2] = love.math.random(0,x);
          snow[i][5] = love.math.random(-1,1);
        end
    end
end
local button_colors =
{
    {0.5,0.0,0.0,1},
    {0.0,0.5,1.0,1},
    {0.0,0.0,1.0,1},
    {0.5,0.5,1.0,1},
    {0.0,0.5,1.0,1},
}
local button_circles = {}
local show_controls  = false;
function create_controls()
   local x = love.graphics.getWidth()
   local y = love.graphics.getHeight()
   local pose_y = (y * 0.5);
   local radius = (x * 0.01) * 5;
   for i=1,5 do
       local pose_x = radius*i * 3.5;
       table.insert(button_circles,{'fill',pose_x,pose_y,radius,button_colors[i]})
   end
end
function draw_controls()
   if show_controls then
      local b = button_circles;
      for i=1,#button_circles do
          love.graphics.setColor(unpack(b[i][5]));
          love.graphics.circle(b[i][1],b[i][2],b[i][3],b[i][4]);
      end
   end
end
function update_controls(px,py)
   if show_controls then
       local b = button_circles;
       for i=1,#button_circles do
           local cx,cy,cr = b[i][2],b[i][3],b[i][4];
           if((px - cx)^2 + (py - cy)^2 < cr^2) then
              if i == 1 then set_background(); end
              if i == 2 then sugrob = {}; create_sugrob(); end
              if i == 3 then load_tree(1);   end
              if i == 4 then load_tree(2);   end
              if i == 5 then background=nil; end
           end
       end
    end
end
function love.displayrotated(index, orientation)
    sugrob = {};
    create_sugrob();
    snow = {};
    create_snow();
    snow_opacity = 0;
    tree_opacity = 0;
    button_circles = {};
    create_controls();
end
function love.mousepressed(x,y)
    if love.system.getOS() ~= 'Android' then
       update_controls(x,y)
       show_controls = not show_controls;
    end
end
function love.touchpressed(b,x,y)
    update_controls(x,y)
    show_controls = not show_controls;
end
function love.load()
    love.filesystem.write('init','x',1);
    if love.filesystem.getInfo('icon.png') then
       love.window.setIcon(love.image.newImageData('icon.png'));
    end
    love.window.setTitle("Маааленькой ёёёлочке холодно зимооой.")
    if love.system.getOS() == 'Android' then
       love.window.setMode(1280,720,{fullscreen=true,resizable=true,vsync=true});
       screen_width = love.graphics.getWidth()
       screen_height = love.graphics.getHeight()
    else
       love.window.setMode(0,0,{resizable=true,borderless=true})
       love.window.setFullscreen(true,'desktop');
       screen_width = love.graphics.getWidth()
       screen_height = love.graphics.getHeight()
       love.window.setMode(0,0,{resizable=true,borderless=true})
       love.window.maximize()
    end
    create_sugrob()
    create_snow()
    create_controls()
end
function set_background()
   if love.system.getOS() == 'Android' then
      return;
   end
   local x,y = love.window.getMode();
   love.window.minimize()
   love.timer.sleep(1)
   local path = get_app_path()
   local status = os.execute('scrot -a '..screen_width-x..','..screen_height-y..','..x..','..y..' -o '..path..'screen.png');
   love.window.restore()
   love.window.maximize()
   if love.filesystem.getInfo('screen.png') then
      background = love.graphics.newImage('screen.png');
   end
end
if autobackround then
   set_background()
end
function love.keypressed(key)
   if key == 'q' or key == 'escape' then
      love.event.quit()
   end
   if key == '1' then set_background(); end
   if key == '2' then sugrob = {}; create_sugrob(); end
   if key == '3' then load_tree(1);   end
   if key == '4' then load_tree(2);   end
   if key == '5' then background=nil; end
end

function love.update(dt)
    if os.date('%H%M') == '2345' then
       if once_call_tree_1 then
          load_tree(1);
          once_call_tree_1 = false;
       end
    end
    if os.date('%H%M') == '0000' then
       if once_call_tree_2 then
          load_tree(2);
          once_call_tree_2 = false;
       end
    end
    update_snow(dt)
    update_tree(dt)
    update_sugrob(dt)
end
function love.draw()
    if background then
       love.graphics.setColor(1,1,1,1);
       love.graphics.draw(background)
    end
    draw_tree();
    draw_sugrob();
    draw_snow();
    draw_controls();
end

Внешний вид. Видео. Досвиданья.


По просьбе @apt_install_lrzsz сборки


Добавил кнопки появляются и исчезают по нажатию на экране.
Как альтернатива нажатия 1,2,3,4,5.
На Андроиде часть не работает.


В истории правок этого сообщения есть прошлая версия, если с этой пробелмы, но прошлая только для ПК.

LINUX-ORG-RU
()

Воспроизведение ссылок через mpv на вашем ПеКа

 , , , , удобное

Суть, вешаем скрипт на горячую клавишу, например F8,
копируем или просто выделяем ссылку, нажимаем F8 и воспроизводятся видива/фота.
Мне удобно выделить ссылку с любым медиаконтентом, например

  • фильмом
  • ютубом
  • музыкой
  • картинкой
  • порнух… ой!

Нажать горячую клавишу и всё.

Зависимости: apt install mpv lua xclip

#! /bin/env lua
---------------
local function play_mpv()
    local appclip = nil;
    local youtudl = nil;
    local session = os.getenv('XDG_SESSION_TYPE');
    local have_mpv  = os.execute('mpv --version 2>/dev/null');
    local have_xclip = os.execute('xclip -version 2>/dev/null');
    local have_ytdlp  = os.execute('yt-dlp --version 2>/dev/null');
    local have_wlpaste = os.execute('wl-paste --version 2>/dev/null');
    local have_youbedl  = os.execute('youtube_dl --version 2>/dev/null');
    if(not have_mpv) then
      os.execute('notify-send "Для работы требуется mpv плеер"');
      os.exit(1)
    end
    if(not session) then
      os.execute('notify-send "Неизвестный тип сессии, задайте x11 или wayland"');
      os.exit(2);
    end
    if(have_xclip and session == 'x11') then
       appclip = 'xclip -o';
    end
    if(have_wlpaste and session == 'wayland') then
       appclip = 'wlpaste -p';
    end
    if(not appclip) then
       os.execute('notify-send "Нужно установить xclip для X11 или wl-paste для Wayland"');
       os.exit(3);
    end
    if(io.popen(appclip):read('*l'):sub(1,4)~='http') then
       os.execute('notify-send "Это не ссылка для воспроизведения"');
       os.exit(4);
    end
    youtudl = have_youbedl and 'youtube_dl' or nil;
    youtudl = have_ytdlp   and 'yt-dlp'     or youtudl;
    if(youtudl) then
       os.execute('notify-send Воспроизводится "$('..
       youtudl..' --skip-download --get-title  "$('..appclip..')")\n"$('..appclip..')"" &');
    else
       os.execute('notify-send "Неизвестное название"');
    end
    local success, meta , code = os.execute('mpv --keep-open=yes --loop "$('..appclip..')" > /dev/null 2>&1');
    if tonumber(code) ~= 0 or success == nil then
       os.execute('notify-send -u normal Ошибка-mpv:'..meta..':'..code);
       os.exit(5);
    end
end
-- run run run
-- дрынь на-на
play_mpv();

Ну и предупреждение.

- ИСПОЛЬЗОВАТЬ НА СВОЙ СТРАХ И РИСК, Я НЕ НЕСУ НИКАКОЙ ОТВЕТСТВЕННОСТИ
- ВСЁ ПРЕДОСТАВЛЯЕТСЯ КАК ЕСТЬ, ЛЮБЫЕ СОМНЕНИЯ ДОЛЖНЫ ВЕСТИ
- К ОТКАЗУ ОТ ИСПОЛЬЗОВАНИЯ
- ТЕКСТ ИЗ БУФЕРА ОБМЕНА ПОПАДАЕТ В ИНТЕРПРЕТАТОР !!!!!!!!!
- В ОБОЛОЧКУ BASH КАК СТРОКА И ЕСЛИ ТАМ ЧТО НЕ ТАК ИЛИ ЭДАК
- И ВНЕЗАПНО ИСПОЛНИЛОСЬ ЧТО-ТО НЕ ТО, ТО ЭТО ИСКЛЮЧИТЕЛЬНО ВАША ВИНА И ВАШИ ПРОБЛЕМЫ

Тест: Выделить ссылку и нажать F8 (иксы автоматически копируют выделенное есчё)

Да, примитив. Но зато очень удобно.
Досвиданья :3

LINUX-ORG-RU
()

Трассировка вызова функций - Call Нunter

 , , трассировка,

Разбирал тут хлам и нашёл у себя пару поделок для трассировки вызова функций, я уже не помню что я именно хотел, вроде хотел отладить что-то замудрёное и не понимал кто кого вызывает поэтому понавтыкал трассировку, но да ладно может кому пригодится. Суть есть короткие макросы которые вставляются в конец и начало функций, и всё. При работе программы будет показано кто кого вызывает. Реализаций две, чуть разные и чуть по разному показывают. Есть ограничение на количество вызовов, в первой реализации запись вызовов явно ограничена и при превышении будет неточность так как вызовы записываются все, во второй чуть получше, там подход к фреймам вызовов и они лишь должны уместится в размер фрейма, но нет полной трассировки как в первом случае. Ну компромисс, либо так, либо сяк. По сути, это ненужный тупак, но в своё время мне помогло. Каталог в котором валялись сорцы я в своё время назвал пафосно и по детски call hunter типа охотник за вызовами или позвоните Хантеру хехехех :D Ой лол, ладно. Пусть как есть так и будет, чё уж там :D Ну, ну и всё.

Первый вариант

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define IDXMAX 1062

#define RS static struct { int ok; char * file; char *  func;}HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__= {.file = __FILE__, .func = (char*)&__func__,.ok=1};\
hunter_record_start((void *)&HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__);\

#define RE { HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__.ok = 0; hunter_record_end(); };\

unsigned long long idx = 0;
struct hunter_call
{
     int    ok;
     char * file;
     char * func;
};

struct hunter_record_data
{
    struct hunter_call * call;
    unsigned long long parent;
};

struct hunter_record_data  record[IDXMAX];

unsigned long long curent=0;

void hunter_print()
{
    for (int i = 0; i < idx; ++i)
    {
        unsigned long long prev = record[i].parent;
        unsigned long long prev_index = 0;
        while(record[prev].call != record[0].call)
        {
            prev = record[prev].parent;
            prev_index++;
        }
        while(prev_index--)
        {
            printf("│   ");
        }
        if(i==0)
        {
            printf("┣━━━━━━ frame ━━━━━━━>\n");
            printf("%s:%s() \n",record[i].call->file,record[i].call->func);
        }else{
            printf("└─> %s:%s() \n",record[i].call->file,record[i].call->func);
        }
     }
     unsigned long long prev = record[curent].parent;
     unsigned long long prev_index = 0;
     while(record[prev].call != record[0].call)
     {
         prev = record[prev].parent;
         prev_index++;

     }
     prev_index++;
     while(prev_index--)
     {
        printf("│   ");
     }
     printf("┗━> backtrace from ━━━> %s:%s() \n",record[curent].call->file,record[curent].call->func);
}

int overflow = 0;
unsigned long long overflow_count=0;
void hunter_record_start(void * data)
{
    struct hunter_call * hunter = (struct hunter_call*)data;
    if(idx == IDXMAX-1)
    {
      printf("============ stack is full, please set '#define IDXMAX %lld' for more data ===========\n",++overflow_count+IDXMAX);
      overflow=1;
      return;

    }else{
        record[idx].call = hunter;
        record[idx].parent = curent;
        curent = idx;
        idx++;
    }
}

void hunter_record_end()
{
  if(overflow)
  {
      return;
  }
  if(record[curent].call->ok != 0)
  {
      printf("\n In file -> %s in funtion -> %s() not set 'RE' \n\n",record[curent].call->file,record[curent].call->func);
      exit(1);
  }
  curent = record[curent].parent;
}
/*
#undef  RS
#define RS

#undef RE
#define RE
*/
void function_5() {RS   hunter_print(); RE}
void function_4() {RS   int x= 10; while(x--) function_5();  RE}
void function_3() {RS   function_4();  function_4(); function_4();  RE}
void function_1() {RS   function_3();   RE}
void function_2() {RS   function_1();  function_1(); function_1();  RE}
int main()
{
   RS
   for (int i = 0; i < 2; ++i)
   {
       function_2();
   }
   RE
}

Выхлоп будет такой.

...
│   └─> cc.c:function_1() 
│   │   └─> cc.c:function_3() 
│   │   │   └─> cc.c:function_4() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   └─> cc.c:function_4() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   └─> cc.c:function_4() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   └─> cc.c:function_5() 
│   │   │   │   │   ┗━> backtrace from ━━━> cc.c:function_5()

Вторая реализация

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#if defined( _WIN32)  || defined( _WIN64 )  || defined( __CYGWIN__ )
#include <windows.h>
#endif
enum
{
  RED     = 31,
  GREEN   = 32,
  YELLOW  = 33,
  BLUE    = 34,
  PURPULE = 35,
  AQUA    = 36,
  DEFAULT = 39,
};

//-----------------------------------------------------------------------------
static void colorset(int color)
{
#if defined( __unix__  )
    if(isatty(fileno(stderr)) && isatty(fileno(stdout)))
    {
        printf("\x1B[%dm",color);
    }
#elif defined( _WIN32)  || defined( _WIN64 )  || defined( __CYGWIN__ )
    HANDLE handle_1 = (HANDLE) _get_osfhandle(fileno(stdout));
    DWORD mode_1;
    HANDLE handle_2 = (HANDLE) _get_osfhandle(fileno(stderr));
    DWORD mode_2;
    if(GetConsoleMode(handle_1,&mode_1) && GetConsoleMode(handle_2,&mode_2))
    {
       printf("\x1B[%dm",color);
    }
#endif
}

#define IDXMAX 127

#define RS \
struct hunter_call\
{\
     int    ok;\
     char * file;\
     char * func;\
     struct hunter_call * parent;\
     struct hunter_call * children;\
     time_t time_s;\
     time_t time_e;\
     unsigned long calls;\
};\
static struct hunter_call HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__= {.calls=0,.file = __FILE__, .func = (char*)&__func__,.ok=1,.parent=NULL,.children=NULL,.time_e=0,.time_s=0};\
hunter_record_start((void *)&HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__);\
HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__.time_s = clock();\

#define RE  HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__.time_e =clock();  HUNTER_RECORD_TOKEN##__FILE__##__LINE__##__func__.ok = 0; hunter_record_end(); \


unsigned long long idx = 0;
struct hunter_call
{
     int    ok;
     char * file;
     char * func;
     struct hunter_call * parent;
     struct hunter_call * children;
     time_t time_s;
     time_t time_e;
     unsigned long calls;
};

struct hunter_call * record = NULL;
struct hunter_call * curent = NULL;

void hunter_print( )
{
    setbuf(stdout,NULL);
    curent->time_e = clock();

    struct hunter_call * buff = record;
    while(buff != NULL)
    {
        if(buff == record)
        {
            colorset(AQUA);
            printf("┣━━━━━━ frame ━━━━━━━> \n");
            colorset(DEFAULT);
            printf("%s:%s()",buff->file,buff->func);
            colorset(GREEN);
            printf(" time %f sec (calls %ld)\n", difftime(curent->time_e,buff->time_s)/CLOCKS_PER_SEC,buff->calls);
            colorset(DEFAULT);
        }else{
            printf("└─> %s:%s()",buff->file,buff->func);
            colorset(GREEN);
            printf(" time %f sec (calls %ld)", difftime(curent->time_e,buff->time_s)/CLOCKS_PER_SEC,buff->calls);
            colorset(DEFAULT);
            if(buff == curent)
            {
                printf(" ──>\n");
            }else{
                printf("\n");
            };
        }
        if(buff == curent) {break;}
        buff = buff->children;
    }
    colorset(YELLOW);
    printf("┗━> backtrace from ━━━> %s:%s() \n",curent->file,curent->func);
    colorset(DEFAULT);
}

int overflow = 0;
unsigned long long overflow_count=0;
void hunter_record_start(void * data)
{
    colorset(DEFAULT);
    struct hunter_call * hunter = (struct hunter_call*)data;
    if(curent == NULL)
    {
        curent = hunter;
        hunter->parent   = NULL;
        curent = hunter;
        record = curent;
        hunter->calls++;
    }else if(curent != hunter){
        curent->children = hunter;
        hunter->parent   = curent;
        curent = hunter;
        hunter->calls++;
    }
}

void hunter_record_end()
{
    colorset(DEFAULT);
    if(curent->ok != 0)
    {
        printf("\n In file -> %s in funtion -> %s() not set 'RE' \n\n",curent->file,curent->func);
        exit(1);
    }
    curent = curent->parent;
}
#define HP hunter_print();
/*
#undef  RS
#define RS

#undef RE
#define RE

#undef HP
#define HP
*/
void function_x() {RS  int x=1000000; while(x--){};  HP  RE}
void function_5() {RS  function_x();  HP   RE}
void function_4() {RS  function_5();   function_5(); function_5();  HP RE}
void function_3() {RS  function_4();  HP  RE}
void function_1() {RS  function_3(); HP RE}
void function_2() {RS  function_1();  function_1(); function_1(); HP RE}
void function_6() {RS  function_4();  function_2(); HP RE}
int main()
{
   RS
   for (int i = 0; i < 2; ++i)
   {
     function_6();
   }
   RE
}

Выхлоп

┣━━━━━━ frame ━━━━━━━> 
cc-list.c:main() time 0.006517 sec (calls 1)
└─> cc-list.c:function_6() time 0.006508 sec (calls 1)
└─> cc-list.c:function_4() time 0.006503 sec (calls 1)
└─> cc-list.c:function_5() time 0.006499 sec (calls 1)
└─> cc-list.c:function_x() time 0.006495 sec (calls 1) ──>
┗━> backtrace from ━━━> cc-list.c:function_x() 
┣━━━━━━ frame ━━━━━━━> 
cc-list.c:main() time 0.006615 sec (calls 1)
└─> cc-list.c:function_6() time 0.006606 sec (calls 1)
└─> cc-list.c:function_4() time 0.006601 sec (calls 1)
└─> cc-list.c:function_5() time 0.006597 sec (calls 1) ──>
┗━> backtrace from ━━━> cc-list.c:function_5() 
┣━━━━━━ frame ━━━━━━━> 
cc-list.c:main() time 0.009705 sec (calls 1)
└─> cc-list.c:function_6() time 0.009696 sec (calls 1)
└─> cc-list.c:function_4() time 0.009691 sec (calls 1)
└─> cc-list.c:function_5() time 0.002997 sec (calls 2)
└─> cc-list.c:function_x() time 0.002995 sec (calls 2) ──>
┗━> backtrace from ━━━> cc-list.c:function_x() 
┣━━━━━━ frame ━━━━━━━> 
cc-list.c:main() time 0.009788 sec (calls 1)
└─> cc-list.c:function_6() time 0.009779 sec (calls 1)
└─> cc-list.c:function_4() time 0.009774 sec (calls 1)
└─> cc-list.c:function_5() time 0.003080 sec (calls 2) ──>
┗━> backtrace from ━━━> cc-list.c:function_5() 
┣━━━━━━ frame ━━━━━━━> 
cc-list.c:main() time 0.012853 sec (calls 1)
└─> cc-list.c:function_6() time 0.012844 sec (calls 1)
└─> cc-list.c:function_4() time 0.012839 sec (calls 1)
└─> cc-list.c:function_5() time 0.002990 sec (calls 3)
└─> cc-list.c:function_x() time 0.002986 sec (calls 3) ──>
┗━> backtrace from ━━━> cc-list.c:function_x() 
┣━━━━━━ frame ━━━━━━━> 
cc-list.c:main() time 0.012935 sec (calls 1)
└─> cc-list.c:function_6() time 0.012926 sec (calls 1)
└─> cc-list.c:function_4() time 0.012921 sec (calls 1)
└─> cc-list.c:function_5() time 0.003072 sec (calls 3) ──>
┗━> backtrace from ━━━> cc-list.c:function_5() 

...

Валяется уже давно, я не уверен что оно вообще доделано.
Мне даже свой код читать лень :D.
Но раз лежит мёртвым грузом, то можно и выложить. Вдруг, кому нечто подобное надо. Выкладываю как есть, лишь проверил что оно компилируется и работает.
Но нужно допиливать, только вот мне уже это ненужно. По крайней мере сейчас.
Вроде всё. Досвиданья.

LINUX-ORG-RU
()

Дёргание SOшки из Love файла - обходной путь.

 , , , ,

Ну… не совсем из love файла, но около того.
В общем так, для начала сразу скажу что делать так не надо.
Но если очень хочется то можно.

В чём суть, вы например написали программу/игру на Love2D и вам вдруг ну очень хочется добавить к ней вашу библиотеку типа libcool.so в которой что-то делается и вы эту библиотеку вызываете из вашего lua кода, только вот беда. Если вы создали love файл mycoolgame.love и положили в него libcool.so ваш код не сможет загрузить библиотеку libcool.so ибо mycoolgame.love это zip архив. Ну, не получится и всё тут. Но если очень хочется то есть черезжопный метод, мы внутри нашего love файла создадим архив с нашей библиотекой и возможно дополнительными файлами, при запуске, мы монтируем этот архив и распаковываем в каталог игры и автоматически добавляем пути до распакованных файлов в cpath и path.

Например вот наша библиотека которую мы хотим распространять вместе с нашей игрой прямо в love файле.

#include <stdio.h>

#ifdef LUAJIT
#include <luajit-2.1/lua.h>
#include <luajit-2.1/lualib.h>
#include <luajit-2.1/lauxlib.h>
#else
#include <lua5.1/lua.h>
#include <lua5.1/lualib.h>
#include <lua5.1/lauxlib.h>
#endif

int example_c_function(lua_State* L)
{
    int a = lua_tointeger(L,1);
    a+=a;
    lua_pushnumber(L,a);
    lua_pushstring(L,"hello from c");
    return 2;
}

int luaopen_lib(lua_State* L)
{
    static const struct luaL_Reg nativeFuncLib [] =
    {
         {"example_c_function", example_c_function},
         {NULL, NULL}
    };
    luaL_register(L, "lib", nativeFuncLib);
    return 1;
}

Соберём её

gcc -DLUAJIT=1 main.c `pkg-config --libs --cflags luajit` --shared -o lib.so

Аахивируем её

mkdir libs
cp lib.so libs/lib.so
zip -r9 libs.zip libs

А вот собственно сама суть и сам механизм распаковки и импорта путей.

function autoreq(zip)
    if not zip then
       print("[autoreq] failed get zip archive for unpack, argument is 'nil'")
       return false;
    end
    local function unpack(dirname,mount_point,base)
        local items = love.filesystem.getDirectoryItems(mount_point)
        if items then
            for _,val in pairs(items) do
                local path = dirname..'/'..val;
                local path_mount = mount_point..'/'..val;
                if love.filesystem.getInfo(path_mount,'directory') then
                   package.path  = package.path  ..';'..base..'/'..path..'/?.lua;';
                   package.cpath = package.cpath ..';'..base..'/'..path..'/?.so;';
                   love.filesystem.createDirectory(path)
                   unpack(path,path_mount,base)
                 elseif love.filesystem.getInfo(path_mount,'file')then
                        print("[autoreq] unpack -> "..val)
                        love.filesystem.write(path,love.filesystem.read(path_mount));
                else
                   print("[autoreq] ok -> "..val)
                end
            end
        end
    end
    local base = love.filesystem.getSaveDirectory();
    print("[autoreq] check depends in '"..base.."'")
    local dirname = "libs"
    local mount_point = "_autoreq_libs_"
    local dir = love.filesystem.createDirectory(dirname)
    local dir = love.filesystem.createDirectory(mount_point)
    data, err = love.filesystem.newFileData(zip)
    if not data then
       print("[autoreq] failed get zip archive for unpack -> '"..zip.."'")
       return false;
    end
    local success,msg = love.filesystem.mount(data,mount_point)
    unpack(dirname,mount_point,base);
    love.filesystem.setRequirePath ( package.path  );
    love.filesystem.setCRequirePath( package.cpath );
    local success,msg = love.filesystem.unmount(data);
    love.filesystem.remove(mount_point);
    print("[autoreq] all done okey")
    return true;
end

autoreq("libs.zip"); -- вызываем распаковку архива с библиотекой и импорта путей
require('lib'); -- вызываем нашу библиотеку

function love.load()
print(lib.example_c_function()) -- вызываем функцию из неё
end

Создаём love файл с нашей программой и её зависимостями

zip -r9 coolgame.love  main.lua libs.zip

Запускаем

love coolgame.love 
[autoreq] check depends in '/home/dron/.local/share/love/coolgame'
[autoreq] unpack -> lib.so
[autoreq] all done okey
0	hello from c

Всё работает, наша soшка может распространяться в обычном love файле. Будет создана такая структура каталогов. В автоматическом каталоге игры.

dron@gnu:~/.local/share/love$ tree 
.
└── coolgame
    └── libs
        └── libs
            └── lib.so

4 directories, 1 file
dron@gnu:~/.local/share/love$ 

Ну вот собственно и всё. На деле можно в lib.zip насовать произвольные файлы, с произвольными каталогами, например выполнить сборку openssl/luasec/luasocket

luarocks --tree `pwd`/luasec install openssl
luarocks --tree `pwd`/luasec install luasec
zip -9 -r libs.zip luasec -x 'luasec/lib/luarocks*'

И получившийся libs.zip просто добавить в свой love файл тем самым получив всё что нужно для работы с https в вашей программе. Я так и сделал в своей проверялке новостей например. Работать будет всё абсолютно прозрачно, ничего в коде учитывать и менять не надо. В том и прелесть. Ну разве что один раз вызвать autoreq('libs.zip') и всё.

Да, теряется смысл в переносимости love файлов ведь теперь там платформоспецифичные библиотеки таскаются. Но это просто вариант таскания с собой soшки если уж надо, но без всяких appimage упаковок и прочего, по иному дёрнуть внешнюю библиотеку из своей поставки из архива, просто никак нельзя. Но порой вот надо бывает. Я голову ломал довольно долго если честно пока не допёрло. Может кому пригодится.

Вроде всё. Досвиданья.

LINUX-ORG-RU
()

Android + sdkmanager + пути

 , , ,

Как экспортировать пути до утилит SDK/NDK если использовать sdknamager?

Есть проект, для него устанавливаю зависимости по сборке

	export ANDROID_SDK_ROOT=$(HOME)/.love-android-build-dir/ANDROID-SDK \
	sdkmanager --install "platforms;android-33";    \
	sdkmanager --install "ndk;23.2.8568313";        \
	sdkmanager --install "platform-tools;33.0.0";   \
	sdkmanager --install "build-tools;33.0.0";      \
	sdkmanager --install "cmdline-tools;latest";    \
	sdkmanager --licenses;

Потом этот проект собирается. Всё ок

export ANDROID_SDK_ROOT=$(HOME)/.love-android-build-dir/ANDROID-SDK; \
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64; \
./gradlew assembleNormalRecord;

sdkmanager NDK + SDK файлы раскидывает вот так

dron@gnu:~/.love-android-build-dir/ANDROID-SDK$ tree -L 2
.
├── build-tools
│   ├── 33.0.0
│   └── 33.0.1
├── cmdline-tools
│   └── latest
├── licenses
│   ├── android-sdk-license
│   ├── android-sdk-preview-license
│   ├── android-sdk-preview-license-old
│   └── intel-android-extra-license
├── ndk
│   ├── 23.2.8568313
│   └── 25.2.9519653
├── platforms
│   ├── android-33
│   └── android-34
└── platform-tools
    ├── adb
    ├── dmtracedump
    ├── e2fsdroid
    ├── etc1tool
    ├── fastboot
    ├── hprof-conv
    ├── lib64
    ├── make_f2fs
    ├── make_f2fs_casefold
    ├── mke2fs
    ├── mke2fs.conf
    ├── NOTICE.txt
    ├── package.xml
    ├── sload_f2fs
    ├── source.properties
    ├── sqlite3
    └── systrace

16 directories, 19 files
dron@gnu:~/.love-android-build-dir/ANDROID-SDK$ 

Я хочу собрать luasocket для android, для этого пишу Android.mk кидаю его в исходники luasocket и теперь я хочу вызвать просто ndk-build и вот тут затык. sdkmanager не просто разворачивает окружения, а там ещё всякие ndk/23.2.8568313/blabla nkd/25.2.9519653/blabla и прочие, когда собираю проект то просто указываю ANDROID_SDK_ROOT и gradlew с прочим Ant говном понимают что и откуда из этой каши брать. Образно я тоже понимаю, но если раньше в пути нужно было просто прописать 1 раз путь до NDK/SDK + JAVA_HOME то с sdkmanager непонятно, так как он плодит кучи каталогов с кучей всего пересекающегося, разбитых по версиям, не руками же всё каждый раз прописывать? в смысле пути до утилит и прочих программ из SDK/NDK Можно ли как-то у sdkmanager или от установленных им зависимостей по сборке запросить пусти чтобы их добавить к PATH автоматически на основе того что он же наустанавливал? И просто собрать soшку через ndk-build?

Андроид боль :( Хочется ругаться и стукнуть по столу, а ещё хочется что-то сломать. Но я пока держусь :3

LINUX-ORG-RU
()

RSS подписка на новые темы