Русский
Русский
English
Статистика
Реклама

Терминал

Перевод Что JavaScript-разработчику следует знать о Curl

28.06.2020 14:08:19 | Автор: admin


Доброго времени суток, друзья!

Представляю Вашему вниманию перевод статьи What JavaScript Developers Should Know About Curl автора Valery Karpov.

Curl это популярный инструмент командной строки, часто используемый для отправки HTTP-запросов. Curl поддерживает большое количество протоколов, однако как Node.js-разработчик вы, скорее всего, будете использовать его для отпраки http-запросов к RESTful API.

Документация curl представляет собой перечень из 383 флагов командной строки, поэтому в ней очень трудно найти то, что ищешь. В этой статье я хочу поделиться с вами некоторыми часто используемыми мной шаблонами. Для примеров будет использоваться сервис httpbin.org.

Отправка http-запроса


Для начала убедитесь в том, что у вас установлен curl, выполнив команду curl --version.

$ curl --versioncurl 7.58.0 (x86_64-pc-linux-gnu) libcurl/7.58.0 OpenSSL/1.1.1 zlib/1.2.11 libidn2/2.0.4 libpsl/0.19.1 (+libidn2/2.0.4) nghttp2/1.30.0 librtmp/2.3Release-Date: 2018-01-24Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL 

Для отправки запроса необходимо запустить curl url. Например, для отправки GET-запроса к https://httpbin.org/get?answer=42 следует запустить curl https://httpbin.org/get?answer=42.

$ curl https://httpbin.org/get?answer=42{  "args": {    "answer": "42"  },   "headers": {    "Accept": "*/*",     "Host": "httpbin.org",     "User-Agent": "curl/7.58.0",     "X-Amzn-Trace-Id": "Root=1-5ee8d737-b39c6a466892725bbb52b916"  },   "origin": "69.84.111.39",   "url": "https://httpbin.org/get?answer=42"}

После успешного завершения запроса curl возвращает тело http-ответа. Для того, чтобы заставить curl вернуть весь ответ, включая заголовки, используйте флаг -i.

$ curl -i https://httpbin.org/get?answer=42HTTP/2 200 date: Tue, 16 Jun 2020 14:30:57 GMTcontent-type: application/jsoncontent-length: 801server: istio-envoyaccess-control-allow-origin: *access-control-allow-credentials: truex-envoy-upstream-service-time: 2{  "args": {    "answer": "42"  },   "headers": {    "Accept": "*/*",     "Content-Length": "0",     "Host": "httpbin.org",     "User-Agent": "curl/7.58.0",     "X-Amzn-Trace-Id": "Root=1-5ee8d7a1-cb3954c09299eb9e0dff70a6",     "X-B3-Parentspanid": "dffc55451e64b5fc",     "X-B3-Sampled": "0",     "X-B3-Spanid": "8e233a863fb18b6c",     "X-B3-Traceid": "45bd12a9067fb5c0dffc55451e64b5fc",     "X-Envoy-External-Address": "10.100.91.201",     "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=c1ff14671b3e24ee794f9a486570abf8ccc9d622846611d3f91a322db4d480cd;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"  },   "origin": "69.84.111.39,10.100.91.201",   "url": "http://httpbin.org/get?answer=42"}

Это полный http-ответ. Заголовками ответа являются строки от date: до x-envoy-upstream-service-time:.

Загрузка файлов


Wget самый распространенный инструмент для загрузки файлов посредством командной строки. Он входит в комплект большинства диструбутивов Linux. Однако в OSX его нет.

Команда wget url аналогична команде curl -OL url. Опция это опция --remote-name, которая говорит curl сохранить тело ответа в локальном файле. Опция -L говорит curl следовать перенаправлениям.

Например, ниже представлено изображение с Unsplash, его URL https://images.unsplash.com/photo-1506812574058-fc75fa93fead.



Для загрузки этого изобюражения необходимо выполнить следующее:

$ curl -OL https://images.unsplash.com/photo-1506812574058-fc75fa93fead  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                 Dload  Upload   Total   Spent    Left  Speed100 12.1M  100 12.1M    0     0  3927k      0  0:00:03  0:00:03 --:--:-- 3927k

Опция -O говорит curl использовать строку после последнего / в качестве имени файла. В приведенном примере изображение будет сохранено в текущей директории с именем photo-1506812574058-fc75fa93fead. Для определения имени файла используйте опцию (строчная буква о).

$ curl -o miami-beach.jpg https://images.unsplash.com/photo-1506812574058-fc75fa93fead  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                 Dload  Upload   Total   Spent    Left  Speed100 12.1M  100 12.1M    0     0  6083k      0  0:00:02  0:00:02 --:--:-- 6083k$ ls -l miami-beach-jpg-rw-rw-r-- 1 val val 12788445 Jun 16 11:03 miami-beach.jpg

Отправка авторизованного запроса


Заголовок авторизации используется для включения в запрос данных для авторизации при обращении к RESTful API. Для добавления указанных данных необходимо использовать флаг -H. Например, если ваш ключ интерфейса (API key) my-secret-token, вы можете включить его в http-запрос следующим образом:

$ curl -H "Authorization: my-secret-token" https://httpbin.org/get{  "args": {},   "headers": {    "Accept": "*/*",     "Authorization": "my-secret-token",     "Host": "httpbin.org",     "User-Agent": "curl/7.58.0",     "X-Amzn-Trace-Id": "Root=1-5ee8e1a5-a3aa30e0765a7980b04ca4a0"  },   "origin": "69.84.111.39",   "url": "https://httpbin.org/get"}

Обратите внимание, что httpbin.org возвращает заголовки http-запроса в теле ответа в свойстве headers.

Curl также поддерживает авторизацию по-умолчанию посредством флага -u. В следующем примере мы отправляем запрос с именем пользователя user и паролем pass:

$ curl -i -u "user:pass" https://httpbin.org/basic-auth/user/passHTTP/2 200 date: Tue, 16 Jun 2020 15:18:45 GMTcontent-type: application/jsoncontent-length: 47server: istio-envoyaccess-control-allow-origin: *access-control-allow-credentials: truex-envoy-upstream-service-time: 1{  "authenticated": true,   "user": "user"}

Вот что происходит при отправке неправильного имени пользователя или пароля:

$ curl -i -u "user:wrongpass" https://httpbin.org/basic-auth/user/passHTTP/2 401 date: Tue, 16 Jun 2020 15:18:51 GMTcontent-length: 0server: istio-envoywww-authenticate: Basic realm="Fake Realm"access-control-allow-origin: *access-control-allow-credentials: truex-envoy-upstream-service-time: 12

Отправка POST-запроса, содержащего JSON


Флаг -X говорит curl, какой метод следует использовать: PUT, POST и т.д. По-умолчанию curl использует метод GET, поэтому писать curl -X GET не нужно.

Флаг -X часто используется совместно с флагом -d, позволяющим добавить тело запроса. В следующем примере показано как отправить POST-запрос, содержащий некоторый json:

$ curl -X POST -d '{"answer":42}' https://httpbin.org/post{  "args": {},   "data": "",   "files": {},   "form": {    "{\"answer\":42}": ""  },   "headers": {    "Accept": "*/*",     "Content-Length": "13",     "Content-Type": "application/x-www-form-urlencoded",     "Host": "httpbin.org",     "User-Agent": "curl/7.58.0",     "X-Amzn-Trace-Id": "Root=1-5ee8e3fd-8437029087be44707bd15320",     "X-B3-Parentspanid": "2a739cfc42d28236",     "X-B3-Sampled": "0",     "X-B3-Spanid": "8bdf030613bb9c8d",     "X-B3-Traceid": "75d84f317abad5232a739cfc42d28236",     "X-Envoy-External-Address": "10.100.91.201",     "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=ea8c3d70befa0d73aa0f07fdb74ec4700d42a72889a04630741193548f1a7ae1;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"  },   "json": null,   "origin": "69.84.111.39,10.100.91.201",   "url": "http://httpbin.org/post"}

Обратите внимание, что по-умолчанию значением заголовка Content-Type является application/x-www-form-urlencoded. Для json это является неверным, поэтому для определения Content-Type следует использовать флаг -H:

$ curl -X POST -d '{"answer":42}' -H "Content-Type: application/json" https://httpbin.org/post{  "args": {},   "data": "{\"answer\":42}",   "files": {},   "form": {},   "headers": {    "Accept": "*/*",     "Content-Length": "13",     "Content-Type": "application/json",     "Host": "httpbin.org",     "User-Agent": "curl/7.58.0",     "X-Amzn-Trace-Id": "Root=1-5ee8e45e-ad875af4f83efd4379b86c34",     "X-B3-Parentspanid": "5f4f33d1c5ea13aa",     "X-B3-Sampled": "0",     "X-B3-Spanid": "a062c9bf2ebfd4bd",     "X-B3-Traceid": "44aa8d62412ae34d5f4f33d1c5ea13aa",     "X-Envoy-External-Address": "10.100.86.47",     "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=2f0b3331fe4d512975b4b82583a55dd5d1196023d0dfce9e0abed246991c5b67;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"  },   "json": {    "answer": 42  },   "origin": "69.84.111.39,10.100.86.47",   "url": "http://httpbin.org/post"}

Отправка PUT-запроса, содержащего JSON-файл


Флаг -d также поддерживает отправку данных из локальных файлов.

Например, представим, что у нас есть файл data.js, содержащий такие данные:

{"answer": 42}

Для отправки PUT-запроса с этим файлом в качестве тела запроса вы можете присвоить флагу -d значение @data.json. Префикс @ говорит curl загрузить тело запроса из файла data.json:

$ curl -X PUT -d '@data.json' -H "Content-Type: application/json" https://httpbin.org/put{  "args": {},   "data": "{\"answer\":42}",   "files": {},   "form": {},   "headers": {    "Accept": "*/*",     "Content-Length": "13",     "Content-Type": "application/json",     "Host": "httpbin.org",     "User-Agent": "curl/7.58.0",     "X-Amzn-Trace-Id": "Root=1-5ee8e745-37c4ef06326b7b4354a16b94",     "X-B3-Parentspanid": "a4f8f91f4f1b051e",     "X-B3-Sampled": "0",     "X-B3-Spanid": "a018b1a3fcebdc68",     "X-B3-Traceid": "7b48b01dc3f632eea4f8f91f4f1b051e",     "X-Envoy-External-Address": "10.100.91.201",     "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=6035260d9d551af6c1907270653214e8d3195abbdd19078c1c84fd9a4106f260;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"  },   "json": {    "answer": 42  },   "origin": "69.84.111.39,10.100.91.201",   "url": "http://httpbin.org/put"}

Заключение


Резюмируя, вот опции curl, которые я нахожу самыми полезными:

  • -X определяет метод запроса, например, curl -X POST url
  • -d определяет тело запроса в виде строки в PUT и POST-запросах. Используйте @ для извлечения данных из файла
  • -H определяет заголовок запроса, например, curl -H "Authorization: my-secret-token" url
  • -u аутентификационные данные для стандартной авторизации
  • -O сохраняет тело запроса в файл
  • -i показывает полный ответ, включая заголовки

Curl полезный инструмент взаимодействия с API посредством командной строки, независимо от того, сторонний это API или API, который вы разрабатываете. Для быстрого тестирования curl подходит лучше, чем Axios в Node.js или настройка запроса в Postman, если вы знакомы с их синтаксисом.

Благодарю за потраченное время. Надеюсь, оно было потрачено не зря.
Подробнее..

Перевод Изготовление контроллера терминала IBM 3270

23.06.2020 10:15:03 | Автор: admin

IBM 3270 это терминал компьютерного мейнфрейма. Я давно восхищаюсь мейнфреймами от IBM, и особенно этими терминалами. У ранних моделей, 3278 и 3279, была уникальная эстетика, а их блочная система работы заметно отличается от той, которой пользовались вездесущие терминалы серии VT.



Терминал IBM 3278-2 и его пра-пра-правнук, ThinkPad X1, на котором запущен оес. Терминал подсоединён к современному z14 при помощи TN3270.

Не один я хотел попробовать подсоединить настоящий терминал от IBM к эмулятору Hercules [программный эмулятор мейнфреймов IBM (System/370, System/390, zSeries/System z) и совместимых (Amdahl)]. К сожалению, довольно трудно найти контроллер терминала IBM 3174 с интерфейсом Ethernet или Token Ring, версией софта с поддержкой TCP/IP и в рабочем состоянии. К тому же они огромные, шумные, и их сложно обслуживать, поскольку софт на них приходится загружать при помощи редких флоппи-дисков 5" объёмом 2,4 Мб если повезёт, бывают ещё варианты с жёстким диском на 20 Мб. Поэтому я решил сделать собственный контроллер, а в процессе узнать что-то новое.

Немного истории IBM 3270


Судя по записям компании IBM, информационная система 3270 была представлена в 1972 году, а культовый терминал 3278 через пять лет, в 1977. Цветные терминалы появились в 1979 с 3279. Сложновато не запутаться в моделях и годах!

3270 один из самых узнаваемых терминалов, работающих по блочной системе. Поток данных 3270 позволяет программисту описать целый экран, содержащий текст, защищённый от редактирования, доступные для редактирования поля и атрибуты его форматирования. Доступные для редактирования поля позволяют вводить или изменять данные. Вместо того, чтобы отправлять каждое сделанное вами нажатие клавиши сразу на хост, как это происходит у символьных терминалов, этот терминал хранит ввод у себя, пока вы не нажмёте особую клавишу к примеру, Enter. Только после этого весь ввод отправляется на хост блоком данных. Такая система улучшает воспринимаемую отзывчивость компьютера в случае медленной или ненадёжной связи. Также это снижает требования по мощности хоста, и позволяет подключать к нему гораздо больше блочных терминалов, чем символьных. В чём-то это весьма напоминает заполнение формы на HTML-странице.

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

Терминалы соединяются с контроллером коаксиальным кабелем по топологии звезда. При помощи балуна можно превратить её в более привычную схему подключения по витой паре, хотя, как мне кажется, IBM предпочла бы, чтобы вы использовали их систему подключения. Контроллер соединяется с мейнфреймом по разным интерфейсам, в зависимости от того, местный это контроллер или удалённый. Кроме того, подключение менялось со временем. Среди интерфейсов присутствовали:
  • Parallel Channel
  • ESCON Channel
  • X.21
  • V.35
  • Token Ring
  • Ethernet


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


Контроллеры терминалов от IBM по часовой стрелке, начиная снизу слева: 3174-1L, 3174-23 (без передней крышки), 3174-61R и 3274-41D.

Другие компании, включая Memorex, производили совместимые терминалы и контроллеры. С распространением персональных компьютеров терминалы начали менять на ISA, PCMCIA и потом PCI-карточки, позволявшие подсоединять по тому же коаксиальному кабелю ПК с эмулятором. Позднее, с развитием LAN и TCP/IP эти подсоединения заменил телнет TN3270, которому не требовалось специальное железо или коаксиальный кабель.

Для клиентов, обзаведшихся сетью TCP/IP, но всё ещё пользующихся большим количеством физических терминалов, поздние варианты контроллеров 3174 предлагали возможность соединять их с мейнфреймом телнетом по TCP/IP. Для подсоединения к Hercules нам нужны именно такие контроллеры. Меня очень интересовал тот факт, что они также предлагали эмуляцию VT100, с помощью которой терминал 3270 можно было соединить с хостом на UNIX или VMS так, будто бы это был VT100. Для меня это было странным ведь терминал заточен под блочную передачу, поэтому эмуляция VT100 кажется невозможной.

Последним терминалом от IBM стал 3483, представленный в конце 1990-х. К тому времени терминалы напоминали уже тонких клиентов и использовали стандартные мониторы VGA и клавиатуры с интерфейсом PS/2.

Разбираемся в протоколе


Изначальный мой поиск навёл меня на описание кабельного подключения и потока данных для 3270. Всё это было хорошо описано, однако там ничего не сказано о протоколе передачи данных между терминалом и контроллером. Его детали я смог найти, только раскопав технические описания устаревших на сегодня чипов, использовавшихся для создания интерфейсов с ПК. Их производили CHIPS и National Semiconductor:
  • CHIPS 82C570
  • NS DP8340
  • NS DP8341
  • NS DP8344


Устройства соединяются друг с другом коаксиальным кабелем с характерным импедансом 93 . Кабель этот имеет тип RG-62 в отличие от сетей на Ethernet 10BASE2, использующих топологию шины и кабель с импедансом в 50 . Для уменьшения шума в длинных участках кабеля используется разностная передача сигналов, и максимальная рекомендованная длина отрезка между устройствами по спецификации составляет 1,5 км.

Данные идут с битрейтом в 2,3587 Мб/с в Манчестерском кодировании. Эта схема обеспечивает перепад напряжения с низкого уровня на верхний уровень (или наоборот) в рамках каждого бита, что гарантирует надёжную передачу данных до получателя. В каждом кадре содержится одно или несколько 10-битных слов. Каждое слово начинается с бита синхронизации и заканчивается битом чётности. Начало и конец кадра отмечают уникальные последовательности.


Вместо тысячи слов или, как в данном случае, 10 бит. Команда чтения состояния, отправленная с контроллера на терминал.

Все коммуникации инициирует контроллер. Он отправляет на терминал кадр, содержащий управляющее слово и опциональные слова с данными (что-то типа параметров). Терминал отвечает кадром, содержащим одно или несколько слов с данными.

Оказалось, что терминалов существует два типа CUT и DFT. CUT перекладывают обработку потока данных 3270 на управляющий модуль, и преобразуют их в базовые операции вроде движения курсора по адресу или записи символов в буфер дисплея (он же кадровый буфер). Большую часть функций, которые люди ассоциируют с терминалом 3270, выполняет контроллер то есть, логика терминала CUT проще, чем у сравнимого по функциональности VT1000. Терминалы DFT могут обрабатывать поток данных 3270 самостоятельно, и контролер просто передаёт поток на терминал.

Подробную документацию протокола я веду на GitHub.

Hello world


На eBay до сих пор можно найти передатчики DP8340 и приёмники DP8341 от National Semiconductor, поэтому я купил их и некоторые другие компоненты, перечисленные в техническом описании. Сначала я думал собрать интерфейс с нуля, однако эти интегральные схемы передатчика и приёмника в итоге обеспечили передачу данных.

Я также нашёл контроллер IBM 3174-23R для установки в стойку с интерфейсом Token Ring, и решил, что больше мне ничего и не надо. К сожалению, дискета с управляющей программой оказалась испорченной, и загрузить получалось только диск диагностики. Диагностическая программа показывала менюшки на терминале, чего хватило для перехвата части трафика между терминалом и контроллером для последующего анализа.

Я сделал простую схему приёмника по описанию DP8341 на макетной плате, подключил её к Arduino Mega, и при помощи т-коннектора подключился между контроллером и терминалом. Я был в восторге, впервые увидев поднятие напряжения на контакте DATA AVAILABLE и вызов моего обработчика прерываний. На то, чтобы надёжно считывать данные с приёмника, у меня ушло некоторое время. Вскоре я обнаружил, что памяти в 8 Кб на Arduino Mega мне уже не хватает, а поток данных шёл слишком быстро, чтобы в реальном времени скидывать их на ПК по последовательному порту.

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

Я также перехватил счётчик адресов загрузки и команды на запись данных, связанные с буфером дисплея. Адрес извлечь было легко, однако сначала я не нашёл данных, записываемых в буфер дисплея, в ожидаемой мною кодировке EBCDIC (я ждал её, учитывая схему работы диагностического интерфейса на терминале). Также это была и не ASCII оказалось, что терминал использует свою кодировку символов. Как она называется, я не знаю, и отсылок к ней я не нашёл. Большую часть кодировки я смог разметить при помощи диагностического интерфейса. А когда я добавил на макетную плату передатчик DP8340, то смог полностью разметить все символы сначала, конечно же, выведя на экран hello world!

У терминала 3270 есть строка состояния, которая выводится в самом низу экрана. Ею, за исключением текущей позиции курсора, управляет контроллер. Сбивает с толку, что строка состояния начинается с адреса 0 в буфере экрана, хотя находится в самом низу а адрес 80 соответствует верхней левой ячейке в режиме 80 столбцов. Также кодировка символов в строке состояния отличается от остальных, и в неё входят много необычных символов.

В итоге я смог написать библиотеку для Python, pycoax, для сериализации и десериализации кадров 3270. Код на Python работает на ПК и общается с Arduino по последовательному порту (физически через USB).

Наконец, я разработал свою первую печатную плату при помощи KiCad и отправил на изготовление в JLCPCB. Спустя неделю и $15, я получил 5 шилдов для Arduino, готовых к сборке. Плата работает значительно лучше макетной, количество ошибок заметно уменьшилось. Да, и признаюсь, что мне пришлось заказывать плату дважды, поскольку в первый раз я совершил ошибку при разводке.


Arduino Mega и шилд-интерфейс для коаксиала

Создание oec


Моей целью было создать замену контроллеру IBM 3174, которую можно было бы использовать совместно с Hercules. Теперь, когда я понял, что терминал типа CUT не обрабатывают поток данных 3270 самостоятельно, я понял, что реализовать сначала эмуляцию VT100 будет гораздо проще, чем TN3270.
Я нашёл pyte, обеспечивающий эмуляцию VT100 в памяти, и поддерживающий подключение к процессу (типа командной оболочки или SSH). Мне нужно было только опрашивать терминал на предмет нажатий клавиш, передавать их процессу, обновлять эмулятор pyte, передавая ему выходные данные с процесса, а потом выводить эмулированный экран терминала на сам терминале. А кроме этого ещё нужно было следить, включен терминал или отключен, и отслеживать здоровье процесса.

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

Вдохновившись pyte, я написал pytn3270, быблиотеку TN3270 на чистом Python, обеспечивающую похожую эмуляцию в памяти. Для интеграции с контроллером потребовалось сопоставить атрибуты полей байту атрибутов терминала 3270. Я мог бы использовать x3270, однако мне хотелось лучше разобраться в протоколе telnet и потоке данных 3270. Для протокола TN3270 я реализовал необходимый минимум но его достаточно для подключения к z/OS, а библиотека на чистом Python может оказаться полезной и вне этого проекта.

На сегодня oec ещё далёк от поддержки абсолютно всех функций контроллера IBM 3174, однако пользоваться им можно. Скачать его можно с GitHub.

Будущее


Во-первых, хочу добавить меню связи, чтобы можно было выбирать хоста (пока что мы умеем подключаться только к одному хосту) и поддержку нескольких логических терминалов. Потом добавлю поддержку EAB и TN3270E для этого мне нужно будет реализовать некоторые функции в pytn3270, которых пока не хватает.

Пока я работаю над интерфейсом на основе FPGA, чтобы не полагаться на устаревшие микросхемы от National Semiconductor и в процессе изучаю протокол и немного Verilog.
Подробнее..

Zx spectrum128, CPM 2.2 и терминал на STM32F407

28.10.2020 02:10:35 | Автор: admin
Нарисовавши черно-белый Spectrum48 за $3 на телевизоре и получив вопросы как: а почему не цветной, а почему без музыки, а где НЕИГРУШКИ решил поправить и опубликовать менее бюджетную версию, Spectrum128+СP/M, примерно на $25 железа.


Мне могут возразить это уже дорого, можно купить Raspberry или другой Linux board на эти деньги, однако реализация на STM32 имеет несколько выигрышных черт, таких как:
1 Время готовности при включении меньше пары секунд.
2 Лаг на клавиатуру меньше одного фрейма (20 миллисекунд, примерно как на настоящем, железном спектруме)
3 Эмулятор на STM мне нравится больше, так как у эмуляторов на Linux, а также и других эмуляторов есть фатальный недостаток их писал не я.
4. Можно питаться от батареек.

Подробнее о реализации
Подсистема звука:
2 ШИМ канала 16 bit, на частоте 44100, работают постоянно и вытягивают из Fifo звук. С другой стороны в Fifo пишет текущий процесс. Это или ZX spectrum (Z80 эмулятор), или MP3 player decoder. Если нет места для звука, то процесс ждет сканируя клавиатуру. Z80, в свою очередь, отрабатывает один кадр и пишет эвенты связанные со звуком в очередь событий звука такие как speaker ON-OFF и AY 8910.С каждым эвентом идет и счетчик клоков Z80. По окончании кадра в 20 миллисекунд симуляции (4-8 миллисекунд stm32 ), рендерится кадр на экран(только изменения) и события звука из очереди рендерятся соотвественно в Fifo звука. Если он забит значит мы торопимся, и нужно подождать. Таким образом осуществляется синхронизация времени между симулируемой и симулирующей системами. При чтении ТAP файлов (виртуального магнитофона ), звук рендерится плотнее, с более коротким шагом, в 3-5 раз, и виртуальное время течет быстрее, соотвественно загрузка скорее чем с физического магнитофона. Впрочем можно ускорение отключить, с клавиатуры (F11-F12).
ШИМ, а не DAC, для звука выбран специально. Он позволяет уменьшить помехи от питания и вынести усилитель класса D наружу и организовать регулировку громкости питающим ключи напряжением. Даже простейший, на паре транзисторов, дает более качественный звук, чем просто усиление сигнала с шумного DACa (плата STM покупная, китайская, готовая. С ошибками.)
Чип AY-3-8910 не то что бы сильно сложный, но документация на него скорее предназначена для пользователей и интеграторов, а не для эмуляции/симуляции. О многом приходилось скорее догадываться и смотреть по коду разных эмуляторов, чем просто сесть и написать по документации. Возможно, что где-то и не угадал И фокус написать его нетребовательным к СPU ресурсам. Вроде получилось.

Подсистема видео:
Изменения цвета бордера (если они были) записывается в специальную очередь с клоками процессора. Это будет видно при загрузке с магн. Ну и некоторые игры обновляют его на ходу, для спецэффектов.
После этого, когда z80 отработал свои такты на 20 миллисекунд кадр рендерится.
То есть трюки с изменением кадра на ходу в демках работать будут не все. Но с играми проблем не замечено.
Контроллер обычный, параллельный 16bit FSMC <-> ILI9341 c SPI тачем ( работает, но не нигде не используется).

z80:
Это эмуляция CMOS версии Z80. Салат из разных мест, но большей частью из FUSE и немного моего творчества тоже (в основном на обьем и скорость). Тест zexall проходит.

Клавиатура:
USB host HID device контроллер от STM. C USB роутерами работать не будет. Все претензии к ST, они поленились и я тоже. Конкретно на том боарде, что я использую нужно удалить резистор R21 1.5K: 3.3v<->USB D+.

Disk:
Примерно так отформатирован у меня, но думаю, что не все критично:
Partition 1 type Start 2048: W95 FAT32 (b)
Attributes: 80
Filesystem UUID: xxxx-xxxx
Filesystem: vfat

Корневые директории(для этого кода именно так):
ZX48
сюда класть программы для spectrum48.Форматы: .TAP,.Z80,.SNA
ZX128
сюда класть программы для spectrum128.Форматы: .TAP,.Z80,.SNA
MP3
попробуйте угадать? И форматы?

Видео тест Спектрума:
www.youtube.com/watch?v=WKQc5I55Ji8
Бонус. Реализован слой согласования с CP/M 2.2 от Grant Searle's.
www.searle.wales

Мужик сделал отличную работу по реализации CP/M на Z80 (отдельно) и FPGA (другая система)
Там и BIOS и образ диска с дофига программ, утилит и компиляторов:
Си, Лисп, Ада, Паскаль,Cobol, Алгол,Forth,APL,Fortran,PL/I,Basic всякий, muMath & muSimp (CAS math package), игры, редакторы всего 240 мега. Это сегодня пару страниц текста, а тогда, во времена CP/M столько не было ни у кого.
Подробнее здесь:
obsolescence.wixsite.com/obsolescence/multicomp-fpga-cpm-demo-disk


Ну и видео тест CP/M:
www.youtube.com/watch?v=-h3XCy79aJw

Я немного добавил к эмулятору z80 на STM32 слой обращения к диску и терминал экрана: клавиатуры, микс ANSI и VT100. Надо будет допроверить и доделать. В основном работает, CATCHUM и Turbo Pascal исправны. Запускается CP/M когда видит диск отсюда, по первым двум байтам образа:
obsolescence.wixsite.com/obsolescence/multicomp-fpga-cpm-demo-disk
Если диска вообще нет, то запускается в режиме Spectrum 128 в меню.
Что не сделано:
1. Чтение и запись с физического магнитофона, магнитофон купил, жду пустые кассеты с Али.
2. Вообще любая запись в спектруме не написана.(В CP/M есть запись)
2.".TGZ" формат?

Что еще:
Хм. Положил перед собой железо, выбираю:

Слева направо, сверху вниз:
Stm32h743, программер на stm32f103, Xilinx XC6SLX16, на ней программер для альтеры, Altera ep2c5 & PSRAM 8M, Zynq7010(на али распродажи по $15!!! ) ,W600-pico (60MHz m3+280 ram $2) ,ESP32-CAM with PSRAM 8M (очень дешевая но мало свободных ножек).
Нижний ряд: Еще Xilinx XC6SLX16,Xilinx XC6SLX9, ANLOGIC (22k lut+SDRAM), ALTERA EP4CE15F23C8, еще W600 за $1- но мало ножек.
Справа от клавиатуры белый магнитофон для демонстрации загрузок компьютеров внукам.
Нет ничего дороже $30 Особенно интересно для тех, кто хочет учить Zynq7010 это FPGA 28 K LUT + 2 ARM cores ~600MHz + flash 128MB + ddr 256MB +ETH100. Видимо распродают контрольные платы от битмайнеров. Удивился и купил.
Эмулятор z80 прогонял на них на всех, кроме программера для альтеры и магнитофона. На некоторых и эмулятор 80286-го прогнал.

для тех кто хочет повторить
Искать:
STM32F407VET6 Development Board Cortex-M4 STM32 minimum system learning board ARM core board +3.2 inch LCD TFT With Touch Screen. Проверял только с 3.2 экраном, чип ILI9341.
source:
github.com/sdima1357/spectrum128_cpm
Подробнее..

Что не так с вашей консольной программой?

14.04.2021 12:16:12 | Автор: admin

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

Но как часто мы обсуждаем наши повседневные инструменты с точки зрения читабельности, хотя пишем под web и каждый день используем консольные утилиты? Сегодня Андрей Светлов расскажет, что со всем этим делать, и чем он пользуется для консолей. Помимо того, что Андрей CPython Core developer и понемногу развивает Python, в свободное от работы время он эксперт по asyncio, со-автор aiohttp, yarl, multidict и прочим популярным библиотекам.

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

Информативность

Это самая первая и очевидная проблема. Например, у всем известного Dockera вывод это простыня ровного, скучного и не выделяемого текста. В нем просто трудно ориентироваться:

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

Размер шрифта и экрана

Снова тот же Docker. Если экран не очень широкий, если шрифт большой или вертикальный экран, то Docker перестает помещаться и выводится на две строки:

И это еще не худший случай, тут можно о чем-то догадаться. А если у вас широченная таблица, которая начинает схлопываться в 3, 4 и более строчек, то разобраться в ней в таком виде решительно невозможно.

А ведь на консоли уже можно делать то, что давным-давно изобрели в мобильных приложениях responsive design когда размер текста перестраивается в зависимости от размера экрана. Минус только один никто за нас не написал удобные библиотеки-помогайки, всё приходится делать самим.

Scrolling & Pager

Вот хороший пример: на скриншоте Manual page от git супер-популярная, хорошая, и между прочим, очень продуманная программа. Manual page позволяет скроллить вывод вверх-вниз, искать текст с помощью pager, и что-то еще выделять стилями. И если у вас на экране списки файлов, объектов, какие-то большие и длинные таблицы, то это хорошая помощь:

Светлый/темный цвет фона

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

Что из этого следует? Возвращаемся к примеру от Github. Вот вывод команды (неважно какой, сейчас это статус моих pull requests) на темном фоне:

И он же со светлой схемой:

Выглядит одинаково хорошо, и к такому выводу нужно стремиться. Но чтобы этого достичь, придется себя ограничивать.

ЦВЕТА И СТИЛИ

Все, что мы можем использовать, чтобы не рябило в глазах пяток цветов и еще несколько стилей:

На этом выбор цветов для нас закончен! Конечно, такая очень узкая палитра не позволяет использовать полноцветные терминалы и точно перенести всё, что ваш UX дизайнер нарисовал в Фотошопе. Но зато у нее есть одно чудесное свойство: если приглядеться, то видно, что, например, желтый это не классический желтый, а немного золотистый, чтобы выглядело хорошо. И все цвета подобраны программой терминала так же. Если меняется тема, то программа снова подскажет, как правильно, хорошо, контрастно и красиво нарисовать этот цвет для терминала.

И пока мы остаемся в этом цветовом диапазоне, с выводом у нас всё будет нормально. Но как только начинаем изобретать что-то свое, начинаются проблемы то, что выглядело хорошо в вашем окружении, у соседа начинает смотреться отвратительно.

Обычно мы, конечно, выбираем понятные всем цвета:

  • Зеленый все хорошо;

  • Красный плохо;

  • Желтый warning.

Но если хотим большего, у нас есть подсказка для команды LS есть соглашение, каким цветом мы будем выводить файлы и папки. Это обеспечивается двумя переменными среды. Первая исторически появилась в виде LSCOLORS и рассказывает, как рисовать файлы и папки: по две буквы на одну позицию. Позиция это папка (нормальный файл, сокет, что-то еще). В документации или в интернете это всё есть. Первая буква отвечает за цвет шрифта (букв), вторая за цвет фона. Я попытался раскрасить так, как у меня закодировано на моей рабочей станции

Второй вариант немножко похитрее: помимо обозначений для папок и символических ссылок, можно еще рассказывать, какие окончания файлов рендерить:

И если у вас вывод, похожий на файлы, и там можно применить эти цвета, стоит написать простенький парсер и самому отформатировать вывод. Достоинство всё то же: эти цвета для LS настроены темой вашего терминала. В терминале они выглядят хорошо, естественно, сбалансировано и ваша программа при их использовании будет выглядеть так же.

Смайлики

Смайлики нельзя недооценивать, это очень хорошая вещь простенький значок, но позволяет быстро сориентироваться на экране:

Но нужно помнить, что смайликов очень и очень много, таблица Unicode также очень большая в результате не все символы отображаются одинаково хорошо. Например, смайлик улыбающийся человечек на Windows-консоли, как правило, не отображается: ?

Поэтому выбирайте простые символы, смотрите, как они рендерятся в разных режимах и проверяйте это на всех платформах (Windows, MAC, Ubuntu). И математические символы в том числе. Везде есть хитрые смайлики, с которыми могут быть проблемы.

Shell

Еще нужно помнить, что терминал существует не сам по себе. Консольные программы, в нем запускаются под разными shell: sh, bash, zsh, fish, cmd.exe, powershell или еще какие-то. Программа должна работать с выбранным shell без проблем, в том числе на Windows. Но на практике мы видим разницу в том, как shell авто-дополняет ввод и как (и в каком терминале) выводятся символы. Поэтому проверяйте и на своем shell, и на тех, которые будут у пользователей.

TTY навсегда?

Помимо shell и интерактивного режима, на который в консолях тратится большая часть усилий по пользовательскому дизайну, программы у нас могут запускаться и без терминала. И когда мы, например, перенаправляем вывод через py в grep, чтобы что-нибудь там поискать, или записываем в файл, или запускаем из-под cron, HTTP-сервера или еще чего-нибудь функция os.isatty() будет возвращать false:

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

Windows, любовь моя

К сожалению, мир консольных программ делится не только на темный и светлый фон, а еще на Windows и всех остальных. Если на posix системах (тех же MAC и Linux) всё весьма похоже, то на Windows есть много отличий, например:

  • less more. Стандартная прокрутка less отсутствует, вместо нее есть куда более гадкое и неудобное more.

  • \n \r\n. Возврат каретки другой.

  • dim / gray. Серого цвета нет (но на MAC, кстати, тоже бардак по поводу цвета, поэтому и надо всё проверять).

  • ANSI escape символы, которые как раз делают расцветку и прочие полезные вещи, по умолчанию выключены, но это легко поправить.

  • -\|/. Многие символы, как я говорил, не работают. Например, здесь наш специалист по UX создал дизайнерский спиннер у нас он должен крутиться треугольниками, а не палочками, как у всех остальных. Почему бы и нет? Но на Windows он крутится одинаковыми квадратиками, то есть не работает.

Инструменты

Расскажу теперь, какими чудо-инструментами можно (и нужно) пользоваться при создании консольных программ и их интерфейсов. Некоторые инструменты действительно чудо там и молоток есть, и напильник, иногда и кувалда встречается. Единственный нюанс. Так как консольная утилита вещь маргинальная и нишевая, ее разработчики создают сами для себя, то инструментарий может быть не таким классным, каким бы он мог быть, и не таким доведенным до ума, как для web-программ, например.

CLICK

Я очень рекомендую Click от славного парня Армена Ронахена. Это инструмент со своими особенностями, но он гораздо лучше и мощнее, чем встроенный в Python argparse. Если вы сомневаетесь, используйте Click.

В нем есть набор утилит (функций), чтобы выводить тексты со стилями можно печатать или накладывать стиль, чтобы получилась строка с анти-последовательностями. Можно снимать стили, использовать pager:

Кроме того, у Click есть маленькая, но очень приятная и удобная фича он автоматически убирает стили для не-терминала (non-TTY). Click сам понимает, когда вывод идет не на полноценный терминал, а, например, куда-нибудь в файл он автоматически снимает все стили и делает click.unstyle. Конечно, вы можете сделать unstyling сами, вместо использования click. Но в любом случае избегайте перенаправления в файл покореженного текста с кучей непонятных значков.

PYTHON PROMPT TOOLKIT

Второй инструмент чудесная штука, которая используется, например, в IPython, BPython, в других shell это инструмент для создания полноценных приложений. Но нас сейчас интересуют вопросы ввода-вывода и здесь Prompt Toolkit решает все вопросы.

Сначала мне показалось, что Prompt Toolkit избыточен потому что для работы хватает и Click. Например, если нужен progressbar, есть всем известный tqdm. Великолепная библиотека, которая решает ровно одну задачу, но делает это хорошо. А еще есть и click.progressbar().

Prompt Toolkit же позволяет легко и просто создавать различные варианты ввода-вывода, используя стили, шапки и прочие штуки. Например, есть обновляемый виджет для progressbar. Вроде бы ничего особого, но у Prompt Toolkit это не один виджет для progressbar.

Из Prompt Toolkit можно собирать очень сложные вещи, используя layout, виджеты, компоновку. А если чего-то нет из коробки, это можно написать.

Благодаря слоям, в Python Prompt Toolkit можно легко отрисовать несколько progressbar-ов по одному на слой загружаемого образа таких же, как например, делает Docker pool:

ВСЁ ПРОПАЛО, ШЕФ! ИЛИ "ГДЕ МОЙ КУРСОР?"

Мелочь, которая в свое время попортила мне немало крови.

Распространенная тема: есть консольная программа, которая рисует чудесные виджеты, рассказывает, как Docker Image тянется на много потоков, даже не моргает и отрисовывает всё гладко. Но если ее внезапно закрыть, может, например, пропасть курсор потому что в последнем режиме курсор спрятали, а обратно не вернули. Бывает, что вы в терминале печатаете, а курсор не мигает на экране. Есть и более сложные способы испортить консоль, загнав ее в какой-нибудь режим, который не предназначен для интерактивного вывода.

Чтобы этого не было, основная программа при выходе должна напечатать магическую скрипт-последовательность на экран:

Это так называемый Soft Reset, который сбрасывает режимы. Например, тот же less умеет переключаться для полноэкранного скроллинга в альтернативный режим. Но если ваша программа пытается реализовать функциональность как old less, то без магического скрипта при выходе надо будет переключаться обратно вручную.

ASYNCIO + CLICK

Я не могу не рассказать про asyncio!

Но Click из коробки не работает с asyncio от слова совсем! Он это не умеет, он написан немного раньше, и они совсем не дружат. Поэтому самым простым решением будет написать AsyncioRunner(), который будет не функцией, а классом, а run можно вызывать несколько раз. Это бывает удобно, например, когда запускаем асинхронный код для проверки типов входных параметров и вдобавок что-то еще run запускаются друг за другом в одном и том же контексте:

И что важно AsyncioRunner() работает при этом как асинхронный контекстный менеджер, то есть по завершению работы чистит за собой.

Мы у себя используем простое правило: неблокирующий код (тот, который выполняется мгновенно) может быть синхронным, пока Click не читает файлы, не лезет в интернет или еще что-нибудь такое не делает. Но как только нам нужно запускать асинхронный код, мы пользуемся AsyncioRunner(). Легко создается какой-нибудь декоратор, который внутри async-команд сделает все, что нам надо:

ASYNCIO + PROMPT_TOOLKIT

А вот Asyncio + Prompt_Toolkit работают вместе великолепно даже из коробки. Prompt_Toolkit знает об asyncio, а Prompt_async это стандартная штука Prompt_Toolkit, которая и запускает основную программу. Детали читайте в документации:

WINDOWS не отпускает

Windows из коробки не умеет пользоваться escape-последовательностью у нее свой набор функций, чтобы поменять цвет, сделать жирным, стереть экран и т.д. Это дико неудобно.

Давно известный проект Colorama работает почти со всеми escape-последовательностями, подменяя собой stdout и stderr. Он парсит то, что печатается, находит там escape-последовательности и убирает их. Вместо этого вызываются разные Windows-функции для того, чтобы поменять тот же самый цвет букв или цвет фона. Но Colorama работает только с подмножеством ANSI-символов.

Полного набора escape-последовательностей, между нами говоря, не существует. Есть много разных терминалов. Начиная от древних и заканчивая актуальными (те же MAC- и Linux-терминалы), у которых хоть и есть некоторые разные escape-последовательности, но в целом они хорошо пересекаются.

Но, к счастью, сейчас наступила эпоха Windows 10. К счастью, потому что в ней можно перевести экран в режим, который обрабатывает escape-последовательности (по умолчанию он не включен). Этот режим позволяют включить две простые функции, вызвать их из Python при помощи ctypes это упражнение на пару минут:

АВТОЗАПОЛНЕНИЕ

В Click оно есть из коробки, но не для Windows. Так уж получилось. Может быть, в следующих версиях будет по-другому. Для Unix-мира оно есть, и это уже хорошо.

Здесь декоратор принимает click.argument от autocompletion то есть функция вызывается тогда, когда в процессе вывода мы нажимаем табуляцию, как обычный Bash, а еще лучше Zsh как это делают shell для большого количества команд.

ВАЛИДАЦИЯ

В Click, разумеется, есть стандартные типы чисел, дат и файлов. Но если хочется сделать нестандартный тип, например, URL, то мы можем написать класс для параметра (будем его указывать в аргументе или опции), и Click автоматически вызовет метод convert, давая возможность нашему коду проверить, преобразовать тип и т.д.:

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

Подробнее..

Квеструм по ашановски (ux)

21.01.2021 00:20:21 | Автор: admin

Чтобы покупателям не было скучно стоять в очередях, Ашан добавил веселый квест, разобраться с которым под силу далеко не каждому .

обобщенный вариант оформленияобобщенный вариант оформления

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

внешний вид терминалов с небольшими различиями. снизу терминал для безналичной оплатывнешний вид терминалов с небольшими различиями. снизу терминал для безналичной оплаты

1. Проблемы

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



Порядок при первом использовании

- Понять что нужно делать
- Найти сканер или нечто похожее
- Отсканировать чек с qr-кодом
- Найти куда вносить купюры
- Внести купюры
- Найти куда вносить монеты
- Внести монеты
- Найти откуда брать сдачу
- Взять сдачу
- Найти откуда брать чек
- Взять чек об оплате (а почему их два?)
- Понять какой чек нужен на выходе
- Выйти

Ура! так выглядел обыденный процесс покупки пакета молока после работы.

"Почти на каждом этапе покупатель должен что-то искать и в чем-то разбираться"


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

2. Проблемы оформления

  • На кислотном красном нормально читаться будет только белый

  • Белые подложки усиливают общую контрастность, выделяя все и не выделяя ничего

  • Текст у сканера закрывается корзинкой для сдачи мелочи при виде сверху

  • Нет привычной структуры, акцентов, иерархии, линии считывания. Глаз вынужден скакать

  • Инструкция на мониторе показывает схематически неправильный терминал,
    несуществующий штрих-код, и указывает на несуществующий сканер

3. Возможное решение


Меньше шума, больше информации

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

Самый сильный акцент ушел на область сканера. Это первый и основной шаг. Рядом со сканером
схематический чек с qr-кодом. Покупатель может не знать, что это такое, но штуку с похожим рисунком ему только что дали на кассе и он держит ее в руках.

два варианта оформления (темные области слепые зоны при виде сверху)два варианта оформления (темные области слепые зоны при виде сверху)

Направляющие и подсказки


Второй по важности этап оплата.

Добавим акцент на купюроприёмник,
но гораздо слабее, чем на чек.

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


Добавим стрелку к оплате монетами. Этот этап происходит одновременно с оплатой купюрами,
но менее важен.

другие варианты. из-за вторичной подложки акцент сохраняется на купюрах. справа безналичная оплатадругие варианты. из-за вторичной подложки акцент сохраняется на купюрах. справа безналичная оплата


Дополнительно едва выделим область выдачи второго чека, и добавим символ штрих-кода, чтобы еще перед выходом показать, какую часть сканировать на выходе.

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

Если приблизить цвета ближе к реальным, сканер и оплата купюрами сразу же бросаются в глаза своей контрастностью.



такое оформление не требует никаких технических изменений

"Это решение уже завтра можно напечатать на плёнке и расклеить на каждый терминал"

4. Варианты без привязки к цвету корпуса


Белый вариант

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


Зеленый вариант

Спокойный и не нагруженный вариант. Хорошо выглядит в сочетании с белым и белой заставкой на экране, но немного превращается в кашу с зеленой.


















можно придумать еще несколько вариантов оформления цифр, чека, стрелок

(почти)Идеальные варианты в сферическом вакууме

Если отойти от существующих корпусов, и только следовать физическим ограничениям каждого
из внутренних устройств (купюроприёмник, чек, монетоприёмник ), можно упростить интерфейс и взаимодействие еще сильнее.

купюроприёмники разнесены, чтобы влез банк с купюрами. монетоприёмник сохраняет привычную ориентациюкупюроприёмники разнесены, чтобы влез банк с купюрами. монетоприёмник сохраняет привычную ориентациюразличные цвета еще сильнее упрощают акцентирование, а разделение на модули помогает не запутаться/различные цвета еще сильнее упрощают акцентирование, а разделение на модули помогает не запутаться/

Чек на выходе

После пробивания товаров, кассир дает чек с qr-кодом, это чек для терминала. Сам терминал выдает стандартный чек об оплате, который обычно сразу сминается и летит в урну. Однако на дверцах на выходе стоит сканер без подсказок, какой чек из двух нужно отсканировать. Вдобавок к этому руки покупателя заняты в этот момент покупками, сдачей, и двумя чеками, а возможно и тростью, ребенком, рюкзаком.

Сканеру нужен штрих-код, нарисованный внизу стандартного чека об оплате, чек с qr-кодом
не подойдет. После оплаты покупок, терминалу точно известно, что товары по qr-коду были оплачены, ведь терминал сам напечатал чек об оплате. Не совсем понятно почему дверцы
не распознают qr-код. Но если это вдруг технически невозможно, около сканера на выходе нарисуем подобную инструкцию. Возможно даже с подписью для большей ясности на новичка

В некоторых магазинах вместо первого qr-кода дают обычный чек со штрих-кодом, который, однако, также не сработает на сканер на выходе и создаст еще больше путаницы внешней идентичностью со вторым чеком

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

Подробнее..

Создание терминала для СКУД и УРВ

21.06.2021 12:17:59 | Автор: admin

Вступление

Ранее, в предыдущих статьях, я рассказывал о бизнес-процессах, которые можно закрыть различными решениями нашего программного обеспечения, однако настало время рассказать о разработке железа, а именно терминале, который способен служить 2 целям - контролю доступа и учету рабочего времени в связке с нашей системой учета рабочего времени.

Историю можно начать с того, что наша компания очень долгое время сотрудничает со всемирно известной сетью фастфудов - KFC (на территории Беларуси и Украины). Головной болью такой сферы, как HoReCa, был и будет учет рабочего времени сотрудников. Учитывая огромную текучку кадров, в том числе и обычных студентов, которые пришли подработать на непродолжительное время, становится сложно проконтролировать, сколько часов отработано тем или иным сотрудником. Плюс немаловажным моментом стало то, что сотрудники часто перемещаются с ресторана на ресторан, а это требует дополнительного контроля. Как же быть?

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

Поэтому был придумал предельно простой и быстрый сценарий действий на терминале:

  1. Прийти на рабочее место, подойти к терминалу и пройти идентификацию (приложить палец, карту к считывателю или ввести PIN)

  2. Выбрать на тачскрине Работа, после чего отправиться на свое рабочее место и приступить к работе

  3. При необходимости перерыва подойти к терминалу, пройти идентификацию, выбрать Перерыв

  4. При возвращении на рабочее место - подойти к терминалу, пройти идентификацию, выбрать Работа

  5. По окончанию рабочей смены подойти к терминалу, пройти идентификацию и выбрать Завершить работу.

То есть все события должны были фиксироваться на терминале, после чего все данные залетали бы на облако системы рабочего времени TARGControl. И там, административным персоналом, формировались табели и отчеты по объектам (ресторанам), что позволило бы корректно начислять заработную плату сотрудникам.

Разработка

Имея на руках техническое задание, была разработана структурная и функциональная схема. Далее пошло самое интересное: мы начали рассматривать различные варианты одноплатных компьютеров, которые бы смогли обеспечить нужный функционал терминала. Среди вариантов были следующие компьютеры: Banana Pi M4, Orange Pi PC+, ODROID-C4, NanoPi M4 и Raspberry PI Computer Module 3+. Произведем небольшое сравнение данных моделей.

Banana Pi M4

Orange Pi PC+

ODROID-C4

NanoPi M4

Raspberry PI CM3+

Память

Слот MicroSD с поддержкой расширения до 256 ГБ и флэш-память eMMC 8 ГБ с поддержкой до 64 ГБ

TF-карта (макс. 32ГБ) / слот для карты eMMC

8 ГБ флэш-память EMMC

1x разъем EMMC (доступно 8/16/32/64 ГБ)

1 слот Micro SD

нет встроенной eMMC, но есть разъем eMMC,
1 слот для MicroSD до 128 GB

8 GB eMMc + поддержка 1 слота microSD

RAM

1 GB DDR4 (опционально 2 GB)

1GB DDR3

4GB DDR4

Двухканальный 2GB DDR3-1866

1GB LPDDR2 SDRAM

CPU

Realtek RTD1395 ARM Cortex-A53 Quad-Core 64 Bit 1.8 GHz

H3 Quad-coreCortex-A71.2 GHz

Amlogic S905X3 Quad-Core Cortex-A55 ARMv8.2-A 64-bit 1.5GHz

RK3399- Cortex-A72 + Quad Core Cortex-A531.8 GHz

Broadcom BCM2837B0 с четырьмя ядрами Cortex A53 1.2 GHz

GPU

Mali 470 MP4 GPU OpenGL ES 1.1/2.0

Mali400MP2 GPU 600MHz
с поддержкой OpenGL ES 2.0

Mali-G31, поддержка OpenGL ES 3.2 и API Vulkan последнего поколения

Mali-T864поддержка OpenGL ES1.1/2.0/3.0/3.1, OpenCL, DX11 и AFBC

Broadcom VideoCore IV

Сеть

Ethernet 10/100/1000 Мбит / с
Опциональный USB-ключ Wi-Fi. Поддержка PoE

10/100 Ethernet RJ45

RJ45 Ethernet порт (10/100/1000)

Порт Gbps Ethernet

10/100 для подключения маршрутизатора или коммутатора с функцией PoE

После детального изучения и анализа цены (все модели находились в примерно одном ценовом диапазоне на момент их анализа - 2019 год), мы все же пришли к выводу, что лучше всего подойдет Raspberry PI Computer Module 3+. Почему Raspberry ? Да, некоторые характеристики уступают конкурентам, однако главным преимуществом стало то, что по Raspberry банально больше поддерживаемых библиотек и лучше техническая поддержка, т.к Raspberry на рынке с 2012 года и вокруг него сформировалось активное комьюнити.

Решение со встроенной памятью eMMC, предусмотренное в CM3, позволяет не использовать флеш-карту в качестве носителя ОС. Большое количество циклов перезаписи eMMC повышает надежность и срок службы памяти по сравнению с флеш-картами. При этом мы зарезервировали разъем для SD карт. Сразу можно сказать, что заявленной памяти для терминала хватает с лихвой, ибо сохраняемые события весят от силы пару килобайт. Что касается хранения фотографий, то здесь все сложнее: программно мы поставили ограничение в 5000 фото, но так как у нас зарезервирована флеш-карта, то данный лимит можно расширить до приемлемого значения.

Разработку управляющей платы мы начали с организации необходимых питающих напряжений. На нашей плате нам необходимо было обеспечить 3 значения напряжений: 5.0В, 3.3В и 1.8В. Внешний источник питания у нас 12В 3А. Для получения 5В и 3.3В мы использовали схему на основе широтной импульсной модуляции. Для источника питания 1.8В мы задействовали линейный понижающий преобразователь. Это выглядит, примерно, следующим образом.

Схема питания терминалаСхема питания терминала

Исходя из схемы видно, что для электрической части терминала была организована схема защиты питания от короткого замыкания и переполюсовки.

Отметим также и схему защиты питания внешних считывателей, представленную ниже.

Схема защиты питания считывателя от диверсийСхема защиты питания считывателя от диверсий

То есть если закоротить питание, считыватель уйдет в защиту (питание считывателя отключится), а терминал продолжит работу. Номиналы резисторов R51 и R52 задают выходной ток. Изменяя номинал резистора R51 можно менять ток ограничения в значительных пределах (у нас стоят заданные на схеме номиналы исходя из рассчитанной нами нагрузки).

Питание мы организовали, самое время перейти к периферии.

К слову, Raspberry поддерживает UART-интерфейс и 2 USB версии 2.0. Через один из доступных USB мы решили организовать доступ к Ethernet с помощью микросхемы LAN9514 . Второй USB используется для подключения периферии, например индикатор алкоголя. Также задействовав GPIO для подключения кнопок, электромагнитных замков, защёлок, алкостестера в дискретном режиме работы и картаприемников.

Схема реализации Ethernet и USBСхема реализации Ethernet и USB

У CM3 на борту всего 2 UART. Один нам пригодится для организации интерфейса RS-485, а второй - debug. Поэтому мы использовали микросхему FT4232HL, для увеличения количества интерфейсов. У нее есть входной интерфейс USB, который поддерживает связь с LAN9514, он же в свою очередь коннектится с CM3.

Схема расширения количества UART-овСхема расширения количества UART-ов

Вот теперь у нас стало больше на целых 4 UARTa (задействуем всего 2). Один используется для подключения биометрического модуля отпечатков пальцев от южнокорейского производителя Suprema-SFM6020-OP6-8M/16M (8M - 5К отпечатков, 16М- 25К отпечатков).

Второй для подключения карточного модуля 7941D (поддерживает 2 частоты Emarine (125 кГц) и Mifare (13,56 МГц).

Suprema-SFM6020-OP6-8MSuprema-SFM6020-OP6-8M

Один из выделенных UART, как и планировали, мы задействовали под RS-485, позволяющий подключать внешние карточные или биометрические считыватели, а также передавать информацию во внешние системы при необходимости интеграции. Схема 485-го представлена ниже.

RS-485RS-485

В этой схеме мы прибегли к некоторым хитрым схемотехническим решениям, объединив и подключив линии RE и DE через транзистор, что позволило нам автоматизировать на аппаратном уровне переключение режимов приема/передачи.

Что касается интеграции с другими системами традиционным для СКУД способом, для передачи минимальной информации у нас организован выходной Wiegand. Есть и два входных Wiegand'а для подключения внешних считывателей. Ниже представлены их электрические принципиальные схемы.

Входной WiegandВходной WiegandВыходной WiegandВыходной Wiegand

Немаловажным моментом будет, что терминал имеет 2 реле для управления замком, турникетом или шлагбаумом. Рассмотрим данный момент на примере подключения турникета (стандартная ситуация для СКУД). Есть два режима управления турникетом, потенциальный режим и импульсный. При потенциальном режиме управления для разблокировки турникета в направлении А срабатывает выход L1 OUT (в направлении В выход L2 OUT). При окончании данного времени или при совершении прохода выходной сигнал возвращается в исходное состояние.

В импульсном режиме для разблокировки выхода L1 OUT и L2 OUT срабатывают кратковременно, посылая управляющий импульс на турникет (обычно 0,2-0,3 секунды). При получении импульса турникет разблокируется в соответствующем направлении на время 5 секунд либо пока не будет совершен проход в данном направлении.

Для контроля прохода в направлении А или направлении В используются две линии, на которые контроллер турникета выдает импульсные сигналы при совершении прохода в том либо другом направлении. Данные импульсные сигналы подключаются к входам SENS1 для прохода в направлении А и SENS2 для прохода в направлении В.

Например, для работы с турникетами PERCo в контроллере должен быть установлен импульсный режим управления. Для этого время срабатывания сигналов L1 OUT и L2 OUT должно быть установлено в пределах от 0,2 до 1 секунды.

Подключение турникета PERCoПодключение турникета PERCo

Как описано в самом начале статьи, по нашему техническому заданию, на терминале должна была быть организована фотофиксация, поэтому решили выбрать камеру от Raspberry, которая в терминалах имеет 2 исполнения:

  1. RPi D - 72.4 градуса обзор, 5 mpx, размер камеры 25x24 мм (старое исполнение).

  2. RPi G - 160 градусов обзор, 5 mpx, размер камеры 25x24 мм (теперь используем только этот вариант).

Схема организации интерфейсов DSI и CSIСхема организации интерфейсов DSI и CSI

Выбирая дисплей, выбор снова пал на знакомый бренд - 7-ми дюймовый touch-screen от Raspberry с разрешением 800x480 и DSI интерфейсом.

Исходя из размеров дисплея, считывателя и общей компоновки плат, были определены габариты корпуса для терминала - 210 x 173 x 44. Корпус решено было сделать цельнометаллическим алюминиевыми с гальваническим покрытием, что обеспечивало хотя бы минимальную вандалоустойчивость. Дисплей, конечно же, так не защищен.

Корпус терминалаКорпус терминала

Собрав все воедино мы получили терминал данного вида.

Знакомьтесь, терминал D1!Знакомьтесь, терминал D1!

Немного отклоняясь от темы, можно сказать, что мы были обмануты Raspberry, когда они в 4-ом поколении Compute Module поменяли форм-фактор и мы уже не смогли его просто заменить в нашей текущей плате и были вынуждены переходить на новое поколение путем разработки новой платы, но об этом в следующих статьях.

На данный момент с 2019 года нашей компаний было продано более 500 терминалов данной модели, а это показывает, что решение оказалось весьма успешным и надежным. В данной статье я коснулся лишь одной части - железа, однако большая работа была проделана и над прошивкой терминала. В следующей статье я расскажу, как реализована программная часть терминала. В случае возникновения вопросов или критических замечаний, прошу последовать в комментарии для бурного обсуждения!

Подробнее..

Джентльменский набор команд Linux Часть 1

30.10.2020 14:07:40 | Автор: admin


Закон Парето применим ко многим сферам, в том числе и к работе с терминалом Linux, ведь всего нескольких десятков команд позволит легко справляться с большинством задач. Мы выбрали 40 наиболее полезных команд, использование которых способно сильно облегчить жизнь при работе с Linux. Статья не претендует на статус истины в последней инстанции или максимально подробного руководства, а очередность команд обусловлена лишь алфавитным порядком.


Джентльменский набор команд Linux Часть 1:


  1. alias
  2. cat
  3. cd
  4. chmod
  5. chown
  6. curl
  7. df

1. alias


Команда alias создает ярлык другой команды или последовательности команд Linux.


Синтаксис команды alias:


alias имя="значение"alias имя="команда аргумент"alias имя="/путь/к/файлу"

alias позволяет:


  • Быстрее вводить команды.
  • Исправлять частые опечатки.

    Довольно распространенная ситуация, когда вместо команды ls вводится sl. В результате пользователь получает сообщение об ошибке:


Подробнее..

Вышел Windows Terminal Preview 1.5

19.11.2020 10:11:44 | Автор: admin
Мы вернулись с очередным выпуском Windows Terminal! Терминал Windows перешел на версию 1.4 и включает функции, описанные в сообщении блога о версии 1.4. Windows Terminal Preview была переведена на версию 1.5 и включает функции, описанные ниже, в этой статье. Вы можете загрузить обе версии из Microsoft Store или со страницы выпусков GitHub. Давайте узнаем, что нового!



Полная поддержка гиперссылок


Мы улучшили функциональность гиперссылок, чтобы автоматически обнаруживать ссылки внутри вашего терминала. Эти ссылки активны и открываются в вашем браузере по умолчанию с помощью Ctrl + Click.



Звонок


Терминал Windows теперь поддерживает символ BEL. Вы можете включить или отключить звонок с помощью настройки профиля bellStyle.

"bellStyle": "audible","bellStyle": "none"

Поддержка эмодзи в значках профиля


Теперь вы можете использовать смайлики в качестве значков профиля во всем терминале, установив в качестве значка своего профиля смайлик.



Примечание. Список переходов не поддерживает смайлики в виде значков, поэтому ваши профили будут указаны без смайлов.

Настройка порядка переключения вкладок


Параметр useTabSwitcher обновлен! Теперь вы можете указать mru или inOrder, что включит переключатель вкладок с перечислением вкладок либо в порядке их последнего использования, либо в порядке их расположения в терминале.

// Включает tab switcher"useTabSwitcher": "mru","useTabSwitcher": "inOrder"// Отключает the tab switcher"useTabSwitcher": "disabled"

Фоновое изображение


В настройку backgroundImage добавлена новая опция! Вы можете установить фоновое изображение на desktopWallpaper, которое установит фоновое изображение терминала в качестве обоев рабочего стола.

Режимы запуска фокусуровки


В настройку launchMode добавлены новые режимы запуска. Теперь вы можете указать терминал для запуска в режиме фокусировки или режиме максимальной фокусировки. Режим фокусировки скрывает вкладки и строку заголовка.

"launchMode": "focus","launchMode": "maximizedFocus"

Отключение анимаций


Мы добавили анимацию при создании и закрытии панелей. Если вы хотите отключить анимацию во всем приложении терминала, вы можете использовать глобальный параметр disableAnimations.

"disableAnimations": true

Примечание. Если у вас отключена анимация на уровне ОС, вы не увидите анимацию внутри терминала, если не установите для disableAnimations значение false.

Улучшения палитры команд


Reconfigured > prefix


Мы переключили префикс > в режим действия внутри палитры команд, что соответствует функциональности палитры команд VS Code. Обратный интервал удалит символ > и переведет вас в режим командной строки, позволяя запускать аргументы командной строки.



Кнопка назад


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



Поисковые запросы полужирным шрифтом


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



Новые действия


Текстовое поле переименования открытой вкладки


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



Масштаб панели


Вы можете использовать действие togglePaneZoom, чтобы развернуть панель так, чтобы она соответствовала всему содержимому окна терминала.



Исправление ошибок


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

Вышел Windows Terminal Preview 1.6

03.02.2021 10:04:43 | Автор: admin

Добро пожаловать на наш первый релиз Windows Terminal 2021 года! Этот релиз приносит новые функциидля Windows Терминал Preview1.6, а такжеперемещает Windows Терминал вверсию 1.5, которая включает в себя функции изэтой статьи. Вы можете загрузить обе версии из Microsoft Store или состраницы релизов GitHub.Ниже приведены некоторые из основных моментов в этом выпуске, однако мы рекомендуем изучитьполные заметки о релизе, чтобыузнать все, что улучшилось с версией 1.6.

Настройки пользовательского интерфейса

Это, наконец, здесь! Windows Терминал Preview теперь включает в себя альфа-релиз нового UI настроек. Пользовательский интерфейс настроек еще не связан по умолчаниюине будет открываться при нажатии кнопки настройки в выпадающем меню, так что вам нужно будет добавить действие в файл settings.json, чтобы использовать его либо с command palette, либо с помощью клавиатуры.

Как открыть пользовательский интерфейс настроек

Чтобы привязать пользовательский интерфейс настроек к "Ctrl+Shift+," добавьте следующее в массив actions (или keybindings, если у вас более старая версия файла настроек):

{ "command": { "action": "openSettings", "target": "settingsUI" }, "keys": "ctrl+shift+," },

Настройки резервных копий файлов

Пока пользовательский интерфейс настроек остается в режиме предварительного просмотра, мы будем создавать резервные копии ваших предыдущих файлов настроек на случай, если что-то пойдет не так с редактированием ваших настроек, и вам нужно будет вернуться. Эти файлы резервных копий можно найти в том же месте, что и файл settings.json. Самый простой способ перемещаться здесь - щелкнуть правой кнопкой мыши вкладку файла settings.json в Visual Studio Code и выбрать Reveal in File Explorer.

Что дальше

Мы все еще активно работаем над пользовательским интерфейсом настроек и будем постоянно отправлять обновления. Вот несколько вещей, над которыми мы сейчас работаем:

  • Интуитивно понятная навигация.

  • Добавление действий и привязок клавиш в пользовательский интерфейс настроек.

  • Предоставление функциональности для изменения порядка ваших профилей.

Если вы хотите следить за развитием пользовательского интерфейса настроек, не стесняйтесь следить за этой темой на GitHub.

Startup actions

Вы когда-нибудь хотели запустить свой терминал в нестандартной конфигурации? Что ж, сегодня радостный день! Теперь вы можете установить действия при запуске (Startup actions) в своих глобальных настройках, чтобы настроить запуск вашего терминала. Параметр startupActions принимает аргументы командной строки wt. Более подробную информацию об аргументах командной строки можно найти на нашем сайте документации.

// Запуск терминала с множеством вкладок"startupActions": "new-tab; new-tab"// Запуск терминала с одной вкладкой, разделенной на панель PowerShell и панель Ubuntu"startupActions": "split-pane -p PowerShell ; split-pane -p Ubuntu"

Индикатор прогресса

Терминал теперь будет отображать индикатор выполнения на вкладке и панели задач всякий раз, когда будет получена последовательность OSC 9; 4. Более подробную информацию об оставшихся задачах и документацию по индикатору прогресса можно найти на GitHub.

Пиксельные шейдеры

В качестве новой экспериментальной функции теперь вы можете использовать пиксельные шейдеры HLSL в своем профиле. Некоторые примеры шейдеров можно найти в нашем репозитории.

"experimental.pixelShaderEffect": "C:\\temp\\invert.hlsl"

Этот параметр пока недоступен в пользовательском интерфейсе настроек и доступен только при редактировании файла settings.json.

Новые действия

Прокрутка истории вверх и вниз

Вы можете использовать команды scrollToTop и scrollToBottom для прокрутки до начала или конца текстового буфера.

{ "command": "scrollToTop", "keys": "ctrl+shift+home" },{ "command": "scrollToBottom", "keys": "ctrl+shift+end" }

Сосредоточьтесь на последней использованной панели

Действие moveFocus приобрело новое направление, которое позволяет вам переходить к последней использованной панели с помощью клавиатуры.

{ "command": { "action": "moveFocus", "direction": "previous" }, "keys": "ctrl+alt+left" }

Перемещение вкладок

Теперь вы можете перемещать вкладки назад (влево) и вперед (вправо) используя клавиатуру с помощью команды moveTab.

{ "command": { "action": "moveTab", "direction": "backward" }, "keys": "" },{ "command": { "action": "moveTab", "direction": "forward" }, "keys": "" }

Другие новинки

  • Действие splitPane и аргумент командной строки split-pane, sp теперь принимают параметр размера для определения размера панели.

  • Также был добавлен аргумент командной строки move-focus, поэтому вы можете указать, на какой панели фокусироваться при запуске терминала с помощью командной строки.

  • Теперь вы можете указать цвет вкладки для каждой новой вкладки или панели через командную строку с помощью --tabColor #rrggbb.

  • Терминал теперь поддерживает последовательность ConEmu OSC 9;9, которая устанавливает текущий рабочий каталог. Если вы запускаете OSC 9;9;, при создании дубликата этой панели или вкладки будет использоваться указанный вами путь Windows.

  • Когда вы выпускаете BEL, терминал будет отображать значок колокольчика на вкладке. Вы также можете теперь установить стиль колокольчика на визуальный, что приведет к миганию панели задач.

  • Теперь у вас может быть двойной курсор подчеркивания в терминале.

  • Палитра команд теперь поддерживает launchMode, который может иметь значение action или commandLine.

Подробнее..

Давайте напишем Linux терминал

13.01.2021 14:06:06 | Автор: admin

Приветствие

Всем привет! Хочу поделиться своим опытом написания собственного терминала Linux используя Posix API, усаживайтесь поудобнее.

Итоговый результатИтоговый результат

Что должен уметь наш терминал

  1. Запуск процессов в foreground и background режиме

  2. Завершение background процессов из терминала

  3. Поддержка перемещения по директориям

Как устроена работа терминала

  1. Считывание строки из стандартного потока ввода

  2. Разбиение строки на токены

  3. Создание дочернего процесса с помощью системного вызова fork

  4. Замена дочернего процесса на необходимый с помощью системного вызова exec

  5. Ожидание завершения дочернего процесса (в случае foreground процесса)

Немного про системный вызов fork()

Простыми словами системный вызов fork создает полный клон текущего процесса, отличаются они лишь своим идентификатором, т. е. pid.

Рассмотрим пример:

#include <stdio.h>#include <unistd.h>#include <wait.h>int main() {    pid_t pid = fork();        if (pid == 0) {        printf("I'm child process!\n");        } else {        printf("I'm parent process!\n");        wait(NULL);    }        return 0;}
Что выведет данная программа:

I'mparentprocess!
I'mchildprocess!

Что же произошло? Системный вызов fork создал клон процесса, т. е. теперь мы имеем родительский и дочерний процесс.

Чтобы отличить дочерний процесс от родительского в коде достаточно сделать проверку. Если результат функции fork равен 0 - мы имеем дело с дочерним процессом, если нет - с родительским. Это не означает, что в операционной системе id дочернего процесса равен 0.

Причем, порядок выполнения дочернего и родительского процесса ничем не задекларирован. Все будет зависеть от планировщика операционной системы. Поэтому в конце блока родительского процесса добавлена строчка wait(NULL), которая дожидается окончания дочернего процесса.

Подробнее про exec()

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

Системный вызов exec заменяет текущий процесс сторонним. Естественно, сторонний процесс задается через параметры функции.

Рассмотрим пример:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <wait.h>int main() {    pid_t pid = fork();        if (pid == 0) {        execlp("ls", "ls", "-l", NULL);        exit(1);    } else {        waitpid(pid, NULL, 0);    }        return 0;}
Что выведет данная программа

total 16
-rwxr-xr-x 1 runner runner 8456 Jan 13 07:33 main
-rw-r--r-- 1 runner runner 267 Jan 13 07:33 main.c

Что произошло?

Родительский процесс как обычно ожидает завершения дочернего процесса. В это время после системного вызова exec происходит замена дочернего процесса на консольную утилиту ls, она была взята для примера.

Можно сказать мы реализовали простой терминал, вся логика заключается именно в этом.

Перейдем к полноценной реализации

Часть 1. Чтение строки с консоли.

Изначально нам надо уметь считывать строку из командной строки. Думаю, с этим не возникнет сложностей.

char* readline() {    char*   line = NULL;    size_t  size = 0;    ssize_t str_len;    // Reading line from stdin    if ((str_len = getline(&line, &size, stdin)) == -1) {        // Logging all errors except Ctrl-D - terminal shutdown        if (errno != 0) {            printf("[ERROR] Couldn't read from stdin\n");        }        free(line);        printf("\n");        return NULL;    }    // Remove useless \n symbol if exists    if (line[str_len - 1] == '\n') {        line[str_len - 1] = '\0';    }    return line;}

В данной функции происходит чтение строки с применением функции getline. После чего, если в конце строки имеется символ переноса строки, удаляем его.

Обратите внимание, что при чтении могут возникнуть ошибки, одна из них - нажатие сочетания клавиш ctrl-D. Однако это штатный случай завершения работы терминала, следовательно в данном случае не должна выводиться ошибка.

Часть 2. Разбиение строки на токены.

В данной части будет представлена реализация разбиения строки на массив токенов.

#define DEFAULT_BUFF_SIZE 16#define TOKENS_DELIMITERS " \t"

Определения начальной длины массива и разделителей строки.

char** split(char* line) {    size_t position  = 0;    size_t buff_size = DEFAULT_BUFF_SIZE;    char* token;    // Allocate memory for tokens array    char** tokens = (char**)malloc(sizeof(char*) * buff_size);    if (tokens == NULL) {        printf("[ERROR] Couldn't allocate buffer for splitting!\n");        return NULL;    }    // Tokenize process    token = strtok(line, TOKENS_DELIMITERS);    while (token != NULL) {        // Emplace token to array        tokens[position++] = token;        // If array free space ended - increase array        if (position >= buff_size) {            buff_size *= 2;            tokens = (char**)realloc(tokens, buff_size * sizeof(char*));            if (tokens == NULL) {                printf("[ERROR] Couldn't reallocate buffer for tokens!\n");                return NULL;            }        }        // Getting next token        token = strtok(NULL, TOKENS_DELIMITERS);    }    // Place NULL to the end of tokens array    tokens[position] = NULL;    return tokens;}

Код выглядит довольно громоздким, однако в нем нет ничего сложного.

Очередной токен получается с использованием функции strtok. После чего данный токен копируется в массив токенов. Если в массиве токенов не достаточно места, массив увеличивается в 2 раза.

Завершается всё добавлением завершающего токена равного NULL, т. к. функция exec() ожидает наличие данного завершающего токена.

Часть 3. Выполнение процессов.

Структура хранения списка запущенных процессов.

Напишем определения структур для foreground и background процессов, fg_task и bg_task. А также определение структуры для хранения всех процессов tasks.

// Struct of background taskstruct bg_task_t {    pid_t  pid;           // Process id    bool   finished;      // Process state    char*  timestamp;     // Process state    char*  cmd;           // Command cmd};typedef struct bg_task_t bg_task;// Struct of foreground taskstruct fg_task_t {    pid_t pid;     // Process id    bool finished; // Process state};typedef struct fg_task_t fg_task;// Struct of all tasksstruct tasks_t {    fg_task  foreground; // Process id of foreground bg_task    bg_task* background; // Background task list    size_t   cursor;     // Cursor of background tasks    size_t   capacity;   // Background array capacity};typedef struct tasks_t tasks;

Создадим в коде глобальную переменную типа tasks, которая и будет хранить все наши запущенные процессы.

// Global variable for storing active taskstasks t = {    .foreground = {        .pid = -1,        .finished = true    },    .background = NULL,    .cursor = 0,    .capacity = 0};

Вспомогательные функции добавления процессов.

Установка foreground процесса выглядит банально и не нуждается в комментировании.

void set_foreground(pid_t pid) {    t.foreground.pid = pid;    t.foreground.finished = 0;}

Добавление background процесса выглядит посложнее.

int add_background(pid_t pid, char* name) {    // Temp background task variable    bg_task* bt;    // If end of free space in background array - increase size    if (t.cursor >= t.capacity) {        t.capacity = t.capacity * 2 + 1;        t.background = (bg_task*)realloc(t.background, sizeof(bg_task) * t.capacity);        if (t.background == NULL) {            printf("[ERROR] Couldn't reallocate buffer for background tasks!\n");            return -1;        }    }    // Print info about process start    printf("[%zu] started.\n", t.cursor);    // Save task in temp variable    bt = &t.background[t.cursor];    // Save process info in array    bt->pid = pid;    bt->finished = false;    time_t timestamp = time(NULL);    bt->timestamp = ctime(&timestamp);    bt->cmd = strdup(name);    // Move cursor right    t.cursor += 1;    return 0;}

На деле же все проще. Смотрим есть ли место в массиве для хранения информации о процессе. Если его недостаточно - увеличиваем длину массива в 2 раза. После чего происходит добавление структуры bg_task в массив и последующее заполнение полей структуры информацией о процессе.

Данная функция возвращает -1 в случае неудачи.

Вспомогательные функции для завершения процессов.

Добавим функцию экстренного завершения foreground процесса. Данная функция с помощью системного вызова kill с параметром SIGTERM завершает процесс по id процесса.

void kill_foreground() {    if (t.foreground.pid != -1) {        // Kill process        kill(t.foreground.pid, SIGTERM);        // Set finished flag        t.foreground.finished = true;        printf("\n");    }}

Также добавим функцию для завершения background процесса.

int term(char** args) {    char* idx_str;      // Cursor in index arg    int   proc_idx = 0; // Converted to int index arg    if (args[1] == NULL) {        printf("[ERROR] No process index to stop!\n");    } else {        // Set cursor in index arg        idx_str = args[1];        // Convert string index arg to int        while (*idx_str >= '0' && *idx_str <= '9') {            proc_idx = (proc_idx * 10) + ((*idx_str) - '0');            // Move cursor to right            idx_str += 1;        }        // Kill process if process index not bad        // and target process not finished        if (*idx_str != '\0' || proc_idx >= t.cursor) {            printf("[ERROR] Incorrect background process index!\n");        } else if (!t.background[proc_idx].finished) {            kill(t.background[proc_idx].pid, SIGTERM);        }    }    return CONTINUE;}

Данная функция принимает в себя массив токенов вида {"term", "<bg task index>", NULL}. После чего преобразует токен индекса background задачи в число. Убивает background задачу посредством системного вызова kill.

Непосредственно запуск процессов.

Для удобства введем функцию is_background, определяющую является ли задача фоновым процессом. Данная функция просто проверяет наличие & в конце.

int is_background(char** args) {    // Current position in array    int last_arg = 0;    // Finding last arg in array    while (args[last_arg + 1] != NULL) {        last_arg += 1;    }    // Checking if task is background`    if (strcmp(args[last_arg], "&") == 0) {        // Remove '&' token for future executing        args[last_arg] = NULL;        // Return true        return 1;    }    // Return false if: '&' wasn't founded    return 0;}

Введем функцию launch которая будет запускать background процесс если в конце присутствует токен &, иначе будет запускаться foreground процесс.

int launch(char** args) {    pid_t pid;        // Fork process id    int   background; // Is background task    // Checking if task is background    background = is_background(args);    // Create child process    pid = fork();    // If created failure log error    if (pid < 0) {        printf("[ERROR] Couldn't create child process!\n");    }    // Child process    else if (pid == 0) {        // Try launch task        if (execvp(args[0], args) == -1) {            printf("[ERROR] Couldn't execute unknown command!\n");        }        exit(1);    }    // Parent process    else {        if (background) {            // Try add background task to array            if (add_background(pid, args[0]) == -1) {                // Kill all processes and free                // memory before exit                quit();            }        } else {            // Set foreground task to store            set_foreground(pid);            // Wait while process not ended            if (waitpid(pid, NULL, 0) == -1) {                // Logging error if process tracked with error                // Except when interrupted by a signal                if (errno != EINTR) {                    printf("[ERROR] Couldn't track the completion of the process!\n");                }            }        }    }    return CONTINUE;}

То, что происходит в этой функции уже должно быть все понятно.

  1. Создается дубликат процесса с помощью системного вызова fork

  2. Заменяем дочерний процесс на требуемый с помощью системного вызова exec

  3. Определяем является ли процесс фоновым

  4. Если процесс фоновый - просто добавляем его в список bacground задач

  5. Если процесс не фоновый - дожидаемся окончания выполнения процесса

В функции присутствует неизвестная функция quit. Ее мы разберем в следующем блоке.

Вспомогательные функции для терминала.

Введем функцию execute, которая в зависимости от первого токена выбирает нужное действие.

int execute(char** args) {    if (args[0] == NULL) {        return CONTINUE;    } else if (strcmp(args[0], "cd") == 0) {        return cd(args);    } else if (strcmp(args[0], "help") == 0) {        return help();    } else if (strcmp(args[0], "quit") == 0) {        return quit();    } else if (strcmp(args[0], "bg") == 0) {        return bg();    } else if (strcmp(args[0], "term") == 0) {        return term(args);    } else {       return launch(args);    }}

Данная функция пропускает действие, если первый токен NULL. Переходит в директорию, если первый токен cd. Выводит справку о пользовании, если первый токен help. Завершает работу терминала, если первый токен quit. Выводит список background задач, если первый токен bg. Убивает процесс по индексу, если первый токен term.

Во всех других случаях запускается процесс.

Реализация вспомогательных функций.

#define CONTINUE 1#define EXIT     0

Значение CONTINUEозначает дальнейшее исполнение главного цикла терминала. Значение EXITпрерывает выполнение главного цикла программы.

int cd(char** args) {    if (args[1] == NULL) {        printf("[ERROR] Expected argument for \"cd\" command!\n");    } else if (chdir(args[1]) != 0) {        printf("[ERROR] Couldn't change directory to \"%s\"!\n", args[1]);    }    return CONTINUE;}
int help() {    printf(        "Simple shell by Denis Glazkov.                               \n\n"        "Just type program names and arguments, and hit enter.          \n"        "Run tasks in background using '&' in the end of command.     \n\n"        "Built in functions:                                           \n"        "  cd   <path>        - Changes current working directory      \n"        "  term <bg_task_idx> - Prints list of background tasks        \n"        "  help               - Prints info about shell                \n"        "  bg                 - Prints list of background tasks        \n"        "  quit               - Terminates shell and all active tasks\n\n"        "Use the man command for information on other programs.         \n"    );    return CONTINUE;}
int quit() {    // Temp background task variable    bg_task* bt;    // Disable logging on child killed    signal(SIGCHLD, SIG_IGN);    // Kill foreground process    if (!t.foreground.finished) {        kill_foreground();    }    // Kill all active background tasks    for (size_t i = 0; i < t.cursor; i++) {        // Place background task to temp variable        bt = &t.background[i];        // Kill process if active        if (!bt->finished) {            kill(bt->pid, SIGTERM);        }        // Free memory for command name        free(bt->cmd);    }    return EXIT;}

Функция quit отключает все callback функции по событию SIGCHLD - т. е. функции, выполняющиеся когда дочерний элемент был завершен. После этого завершает все активные процессы.

#define PRIMARY_COLOR   "\033[92m"#define SECONDARY_COLOR "\033[90m"#define RESET_COLOR     "\033[0m"

Основные цвета терминала.

int bg() {    // Temp background task variable    bg_task* bt;    for (size_t i = 0; i < t.cursor; i++) {        // Store background task in temp variable        bt = &t.background[i];        // Print info about task        printf(            "[%zu]%s cmd: %s%s;%s pid: %s%d; %s"            "state: %s%s;%s timestamp: %s%s", i,            SECONDARY_COLOR, RESET_COLOR, bt->cmd,            SECONDARY_COLOR, RESET_COLOR, bt->pid,            SECONDARY_COLOR, RESET_COLOR, bt->finished ? "finished" : "active",            SECONDARY_COLOR, RESET_COLOR, bt->timestamp        );    }    return CONTINUE;}

Часть 4. Главный цикл терминала.

#include <stdlib.h>#include <signal.h>#include "include/shell.h"int main() {    char*  line;   // User input    char** args;   // Tokens in user input    int    status; // Status of execution    // Add signal for killing foreground child on ctrl-c    signal(SIGINT, kill_foreground);    // Add signal for handling end of child processes    signal(SIGCHLD, mark_ended_task);    // Shell is running while    // status == CONTINUE    do {        // Printing left shell info        display();        // Reading user input        line = readline();        if (line == NULL) {            exit(1);        }        // Parse line to tokens        args = split(line);        if (args == NULL) {            free(line);            exit(2);        }        // Try execute command        status = execute(args);        // Free allocated memory        free(line);        free(args);    } while (status);    return 0;}

Здесь и происходит вся магия. Взгляните на следующие строки. С помощью функции signal задаются callback функции на заданные события.

// Add signal for killing foreground child on ctrl-csignal(SIGINT, kill_foreground);// Add signal for handling end of child processessignal(SIGCHLD, mark_ended_task);

Событие SIGINT- срабатывает при нажатии комбинации ctrl-C, которое в дефолтном поведении завершает работу программы. В нашем же случае мы переназначаем его на завершение foreground процесса.

Событие SIGCHLD - срабатывает при завершении дочернего процесса созданyого с помощью системного вызова fork. В нашем случае мы переопределяем его на пометку фоновой задачи как выполненной с помощью функции mark_ended_task.

void mark_ended_task() {    // Temp background task variable    bg_task* bt;    // Get process id of ended process    pid_t pid = waitpid(-1, NULL, 0);    // Handle foreground process    if (pid == t.foreground.pid) {        t.foreground.finished = true;    }    // Handle background process    else {        // Search and remove process form background tasks array        for (size_t i = 0; i < t.cursor; i++) {            // Place task to temp variable            bt = &t.background[i];            if (bt->pid == pid) {                // Print info about process end                printf("[%zu] finished.\n", i);                // Set new state for background process                bt->finished = 1;                break;            }        }    }}

Все что описано в главном цикле терминала можно описать словами:

  1. Вывод информации о пользователе и текущей директории с помощью функции display

  2. Чтение строки из стандартного потока ввода

  3. Разбиение строки на токены

  4. Выполнение ранее описанной функции execute, которая в зависимости от массива токенов выполняет нужное нам действие.

Нам осталось реализовать одну оставшуюся функцию display. Которая получает информацию о текущей директории с помощью функции getcwd и имя пользователя с помощью функции getpwuid.

void display() {    // Try get and print username with color    uid_t uid = geteuid();    struct passwd *pw = getpwuid(uid);    if (pw != NULL) {        printf("%s%s%s:", PRIMARY_COLOR, pw->pw_name, RESET_COLOR);    }    // Try get and print current directory with color    char cwd[MAX_DIRECTORY_PATH];    if (getcwd(cwd, MAX_DIRECTORY_PATH) != NULL) {        printf("%s%s%s", SECONDARY_COLOR, cwd, RESET_COLOR);    }    // Print end of shell info    printf("# ");}

Часть 5. Итоговый результат.

Итоговый результатИтоговый результат

Надеюсь, данный материал полезен. Если вам есть чем дополнить данный материал, буду рад услышать ваши мысли в комментариях.

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

Подробнее..

Всего лишь меняем модель эмулятора Android устройства

22.01.2021 16:14:24 | Автор: admin

Пролог

Казалось бы, на первый взгляд весьма простая задача. Некоторые читатели могли еще в те бородатые времена лазить по всяким 4пда, рутить свой сенсорный самсунг, менять содержимое файла build.prop и показывать наивным ламерам свой iPhone 15+ Max Pro. Однако, как оказалось, и как оно часто бывает, не все так просто и здесь есть свои подводные камни. Статья призвана помочь простым работягам избежать все кочки да ямы на пути к своей цели!

Дисклеймер

Сразу предупрежу, что люблю писать подобные статьи довольно подробно, не ради объема и многобукав, а ради максимального погружения в проблему и способ ее решения. Обратите внимание, что я работаю на macOS, поэтому все команды в терминале будут ориентированы под данную ОС. Также, следует отметить, что проворачиваювсе это для API 30, то есть для самого последнего на момент написания статьи. Как говорят интернеты, сложности по этой теме начались с API 29.

Зачем это нужно?

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

Ради контекста вкратце расскажу зачем это понадобилось мне. Я получил .apk с багом где-то внутри приложения. Однако пройти дальше первого экрана в этом приложении я не смог. Дело в том, что при запуске, с сервера приходит список разрешенных для запуска устройств и ни мой народный Ксяоми, ни мой эмулятор в этот список не входит. Вот и додумался поменять имя модели устройства на одно из разрешенных. Рутить свой личный телефон не хотелось, поэтому решил шаманить с эмулятором.

Экран не пустивший меня дальшеЭкран не пустивший меня дальше

Достаем build.prop

Как уже говорилось в начале статьи, за имя производителя и модель устройства отвечает системный файл build.prop, который находится в корне устройства в папке system/. Однако при попытке просмотреть его, не говоря уже о редактирование, мы получим отказ в доступе:

Для решения этой проблемы необходимо в терминале обратиться к adb и запросить root права следующей командой: adb root. И вот и первый подводный камень, а именно вывод следующего сообщения: adbd cannot run as root in production builds. Это из-за того что при создании эмулятора мы выбрали вариант с установленными Google сервисами:

Простое решение - создать эмулятор без установленных Google сервисов, после чего повторить команду adb root. После чего в консоле должно появится сообщение: restarting adbd as root что говорит об успешном проведении операции. Естественно если с самого начала у вас был эмулятор без Google сервисов, то скорее всего с adb root и выше описанной проблемой вы не столкнулись.

Отлично, теперь мы видим содержимое файла build.prop:

Редактируем build.prop

Сохраним файл build.prop в любое удобное место для дальнейшего редактирования выделенной красным области на скриншоте выше. Я сохранил прямо на рабочий стол:

Вносим необходимые изменения. Просмотрев логи запросов и ответов предоставленного мне .apk я нашел приходящий с сервера список разрешенных устройств. То есть, для моих целей нужно поменять два значения на PIXEL 3A XL (как вы поняли, здесь вы можете указывать необходимую именно вам модель):

Сохраняем изменения и заливаем файл обратно на эмулятор. Делается это при помощи команды adb push (кстати, скачать файл с эмулятора можно при помощи adb pull если у вас вдруг аллергия на GUI).

Вводим команду в терминал: adb push build.prop system/

И получаем ошибку:

adb: error: failed to copy 'build.prop' to 'system/build.prop': remote couldn't create file: Read-only file system

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

Запускаем эмулятор с доступом на перезапись системных файлов

Для этого нужно выполнить следующую команду в терминале (чтобы скорее всего получить еще одну ошибку):

emulator -avd Pixel3XLAPI30 -writable-system -no-snapshot -nocache

итак здесь Pixel3XLAPI30 - это название нашего эмулятора который мы будем запускать в режиме записи, получить это имя можно выполнив команду emulator -list-avds

-writable-system - собственно тот самый флаг и виновник торжества.

-no-snapshot -nocache - просто советую ввести чтобы избавиться от любого возможного мусора, который может помешать нашему плану-капкану.

После у нас либо запуститься эмулятор (несколько секунд запускается, так что если тупит то так и должно быть) либо получаем ошибку следующего типа:

PANIC: Missing emulator engine program for 'x86' CPU.

БЕЗ ПАНИКИ! Не удивительно, что интернет уже решал подобную проблему.

Что бы и нам порешать с этим нужно в файле .bash-profile (или если у вас zsh то в файле .zshenv) находящийся в корне вашего профиля macOS, добавить дополнительные пути. Вот как это выглядит у меня:

export ANDROIDHOME=~/Library/Android/sdk

есть такая переменная ANDROIDHOME и с ее участием редактируем переменную PATH:

export PATH=$ANDROIDHOME/emulator:$ANDROIDHOME/tools:$PATH

Чтобы изменения вступили в силу перезапускаем терминал (или вводим source ~/.bash_profile) (или source ~/.zshenv). Результат можно проверить выполнив команду echo $PATH и убедиться что в переменной PATH появился добавленный нами путь.

Пробуем запустить эмулятор еще раз.

emulator -avd Pixel3XLAPI30 -writable-system -no-snapshot -nocache

Теперь он должен был успешно запустится.

Активируем доступ на перезапись системных файлов

Из описания флага -writable-system:

-writable-system make system & vendor image writable after 'adb remount'

делаем вывод что теперь нам нужно выполнить adb remount. Для этого открываем новое окно терминала и выполняем сначала команду adb root, что бы adb remount сработало.

После adb remount, будет сообщение что эмулятор нужно перезапустить. Сделать это можно командой adb reboot. Но и здесь не все так просто. Очередной подводный камень об который мы разбили еще один ноготь на пальцах ног. Если сделатьadb reboot то все просто напросто зависает НАВСЕГДА. Настолько навсегда, что придется удалять эмулятор и создавать его заново. Интернет и с этим столкнулся и даже баг создали на гуглов. И благо нашлось решение. Чтобы эмулятор не зависал нужно добавить пару команд до adb remount.

Итак по порядку:

  1. Делаем adb root

  2. Теперь делаем adb shell avbctl disable-verification

  3. Если вы вдруг остались в shell то введите exit

  4. Перезагружаем эмуляторadb reboot и ждем

  5. Снова делаем adb root

  6. И вот теперь можно делать adb remount

Ура! Теперь мы можем записывать файлы в системную папку нашего эмулятора. Можем пушнуть наш отредактированный build.prop файл: adb push build.prop system/. Сделаем adb reboot и убеждаемся что ничего не поменялось Имя модели не изменилось...

Редактируем правильный build.prop

Вернемся к началу и заметим, что значения ro.product.product.name и ro.product.product.model не соответствует тому, что отображается в настройках устройства. Изучив структуру системных папок я заметил, что существует несколько файлов build.prop, которые располагаются в папках: system, system_ext, vendor и product. Эмпирическим методом я скачивал, редактировал и пушил обратно каждый из этих файлов. В конце концов ключевым оказался файл в папке product. Отредактировав его я наконец-то смог изменить название модели эмулятора устройства!

Подводим итоги

Наконец-то я смогу запустить приложение и воспроизвести баг. Подумал я

Теперь я уперся в то, что запускаю приложение якобы с рутованого девайса (ну да есть такой грешок). И дело даже не в команде adb root, ведь команда adb unroot не помогла. Что ж, опускать руки уже поздно, придется что-то придумать.

О том, как я обходил проверку на рутованность устройства я расскажу в следующей своей статье. Немного реверс инжиниринга и даже такая популярная библиотека как RootBeer не проблема.

Данной статьей я стремился собрать как можно больше проблем по этому вопросу и изложить все в форме step-by-step. Спасибо за ваше внимание и очень надеюсь, что статья оказалась полезной!

Подробнее..

Как обойти проверку на Рутинг устройства обхитрив библиотеку RootBeer?

25.01.2021 14:08:49 | Автор: admin

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

Дисклеймер

Сразу предупрежу, что люблю писать подобные статьи довольно подробно, не ради объема и многобукав, а ради максимального погружения в проблему и способ ее решения. Обратите внимание, что я работаю на macOS, поэтому все команды в терминале будут ориентированы под данную ОС.

Как до этого дошло?

Мне выслали .apk файл приложения. Где-то внутри приложения есть баг, который мне нужно воспроизвести. Но пройти вглубь приложения у меня не получается. Мое устройство не проходит проверку на рутованность.

Экран, который меня не пропускаетЭкран, который меня не пропускает

Так как я уже потратил немало усилий, чтобы все же запустить это приложение (о каких именно усилиях идет речь можно узнать в прошлой статье), то и здесь я решил не сдаваться и попробовать обойти проверку на рутованность устройства.

Что будем делать?

Первое, что пришло мне в голову, так это попробовать выполнить декомпиляцию и поправить кое-где код, а потом собрать все обратно. Основное сомнение по поводу такого подхода вызывало то что, у меня не нативное android-приложение, а flutter-приложение. То есть как такового основного кода приложения в виде байт-кода в .apk найти не получится. Или получится? И нужен ли мне код самого приложения?

Небольшое отступление о том, как во флаттере запускается нативный код, то есть родной код для Android или iOS платформы. Например, перед flutter-разработчиком стоит задача: не давать возможность работать с приложением на рутованном устройстве. Аналогом андроид root-устройства является jailbreak для iOS. Для проверки на рутованность или jailbreak необходимо воспользоваться нативными средствами обеих платформ. Для этого разработчик пишет плагин, который вызывает соответствующие нативные методы в зависимости от платформы на которой запущено приложение.

Таким образом, я сделал вывод, что в имеющемся .apk файле есть как минимум 2 интересующих меня места в виде байт-кода. Первое место - это нативная часть приложения, которая слушает команды из flutter части приложения, чтобы вызвать соответствующие нативные методы. И второе место - это собственно и есть эти самые нативные методы, а в данном случае - библиотека для проверки на рутованность устройства.

Я решил, что буду менять байт-код во втором месте. Честно говоря, сначала я работал с первым местом, то есть с плагином. Все потому, что кода там намного меньше и запутаться было сложнее. Всего лишь метод, который вызывает другой метод - это пара строк кода. Но в таком случае статья была бы еще сильнее завязана под конкретный .apk, и не было б такой абстрактности. Поэтому будем работать напрямую с кодом библиотеки.

Смотрим байт-код .apk

Итак, посмотрим на внутренности .apk. Для этого можно воспользоваться инструментом, предоставляемый Android Studio. В меню выбираем Build -> Analyze APK В окне выбора файла находим интересующий нас .apk.

Весь скомпилированный байт-код хранится в файле classes.dex. Выберем его и взглянем на его содержимое. В первую очередь нас интересуют не файлы java или androidx, а именно файлы приложения. Поэтому выбираем первый package в структуре файлов android проекта, в моем случае это папка com. Из любопытства к содержимому каждой из папок я затригерился на слово rootbeer. Погуглив в гугле оказалось, что это весьма популярная библиотека для проверки устройства на предмет рутованности.

Исследовав документацию и исходники библиотеки стало ясно о том, как пользоваться библиотекой и где располагается ключевой метод isRooted().

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

Судя по исходникам библиотеки, нужный мне файл должен находится рядом с классом RootBeerNative, и как мы видим тут таких, два a и b. Эмпирическим методом я понял, что это файл b. Правый клик по файлу b и в выпадающем меню выбираем Show Bytecode.

К сожалению, имена всех методов обфусцированы. Снова обращаясь к исходному файлу на github становится ясно, что метод isRooted() находится на строке 42. Побегав по файлу с байт-кодом мне удалось найти этот метод. Только теперь он называется a() и почему-то начинает работу с .line 43. Вот этот метод я и буду редактировать. Но не так быстро, К сожалению здесь только Read-only доступ.

Редактируем содержимое classes.dex

Для этого придется декомпилировать весь .apk при помощи популярного инструмента apktool. Работать с ним довольно просто. После его установки нам понадобятся всего 2 команды:

apktool d appname.apk, которая декомпилирует указанный .apk и apktool b directory_with_app, которая соберет .apk обратно (в указанной directory_with_app должен располагаться файл apktool.yml).

Итак, выполняю декомпиляцию при помощи команды в терминале: apktool d app.apk

После выполнения команды появляется папка с файлами приложения. Нас интересует папка smali. Smali - это язык которым описан байт-код (вот классная статья по основам smali). Именно эта папка и есть содержимое файла classes.dex. К только что выполненной команде можно добавить параметр --skip-sources или просто -s тогда вместо папки smali мы увидим тот самый файл classes.dex.

Далее, в папке smali находим интересующий и уже известный нам файл b.smali:

Открываем его любым текстовым редактором и переходим к месту, где располагается метод isRooted():

Содержимое файла b.smali
.method public a()Z    .locals 1    .line 43    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->c()Z    move-result v0    if-nez v0, :cond_1    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->d()Z    move-result v0    if-nez v0, :cond_1    const-string v0, "su"    invoke-virtual {p0, v0}, Lcom/scottyab/rootbeer/b;->a(Ljava/lang/String;)Z    move-result v0    if-nez v0, :cond_1    const-string v0, "busybox"    .line 44    invoke-virtual {p0, v0}, Lcom/scottyab/rootbeer/b;->a(Ljava/lang/String;)Z    move-result v0    if-nez v0, :cond_1    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->f()Z    move-result v0    if-nez v0, :cond_1    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->g()Z    move-result v0    if-nez v0, :cond_1    .line 45    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->b()Z    move-result v0    if-nez v0, :cond_1    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->h()Z    move-result v0    if-nez v0, :cond_1    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->j()Z    move-result v0    if-nez v0, :cond_1    invoke-virtual {p0}, Lcom/scottyab/rootbeer/b;->e()Z    move-result v0    if-eqz v0, :cond_0    goto :goto_0    :cond_0    const/4 v0, 0x0    goto :goto_1    :cond_1    :goto_0    const/4 v0, 0x1    :goto_1    return v0.end method

Можем сравнить его с неповторимым оригиналом:

Очень похожи. Итак, нас интересует return, то есть самый конец метод. Видим, что метод возвращает некоторое значение константы v0, значение которой определяется на основе выполнивших в методе условий. Нам это не подходит. Нам всегда нужно возвращать false или же как это будет в smali 0x0. Для этого добавим свою констант v1 со значением 0x0. Сделаем это прямо над return:

:goto_1const/4 v1, 0x0return v1

И конечно же заменим в return v0 на v1. Поднимемся в самое начало метода и изменим значение .locals с 1 на 2 потому, что так надо. Сохраняем изменения в файле и закрываем редактор.

Собираем .apk обратно

Для этого воспользуемся командой apktool b app, где app - папка с приложением, в котором мы редактировали smali файл. После завершения команды, в папке app появиться директория dist. Здесь и расположен наш заново собранный .apk. Однако при попытке установить его мы получим следующую ошибку:

The APK failed to install.Error: INSTALLPARSEFAILEDNOCERTIFICATES: Failed collecting certificates for /data/app/vmdl164530405.tmp/base.apk: Failed to collect certificates from /data/app/vmdl164530405.tmp/base.apk: Attempt to get length of null array

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

keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

Подписать ключом приложение можно при помощи одного из двух инструментов: apksigner или jarsigner.

Я выбрал jarsigner используя следующую команду:

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore keystore app.apk cp_key

В этой команде мы указываем путь к keystore, путь к .apk, который хотим подписать и имя ключа (alias) из указанного keystore. После, вводим пароль от keystore и приложение успешно подписано.

Однако и это еще не все, теперь при попытке установить .apk мы будем получать другую ошибку:

The APK failed to install.Error: INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2

Это потому, что после подписи приложения нужно выполнить оптимизацию .apk файла при помощи инструмента zipalign.

Для выполнения оптимизации нужно ввести следующую команду: ~/Library/Android/sdk/build-tools/30.0.3/zipalign -v -f -p 4 app.apk rdy.apk

30.0.3 - я выбрал самую последнюю версию на момент написания статьи. После завершения команды на выходе получаем файл rdy.apk, который можно успешно установить! Проверим, получилось ли обойти проверку на рутованность устройства:

И да, это успех!

Заключение

Вызов принят - вот, что я подумал получив этот .apk. И считаю это маленькой победой. Данной статьей я стремился описать не просто инструкцию о том, как расковырять приложение или свои способности по типу "смотрите как могу". Этой статьей я хочу сказать (и напомнить тем, кто стал забывать) что большинство проблем решаемы, нужно только копать, копать и еще раз копать, не опускать руки и результат обязательно будет удовлетворительным. Даже если, в конце концов, баг я так и не обнаружил, я очень рад что расширил свой кругозор и в дальнейшем смогу взяться за более сложные задачи! Спасибо за внимание, обязательно буду писать еще про подобные танцы с бубном!

Подробнее..

Установка Midnight Commander на Mac OS X Catalina (2020)

15.11.2020 20:17:49 | Автор: admin
Государственный флаг СССРГосударственный флаг СССР

Причем здесь флаг СССР? Статья затрагивает программы из далеких 80-х годов, когда был Советский Союз, поэтому и наш красивый флаг из тех времен. Кто помнит те времена и на больших предприятиях в некоторых кабинетах были даже программисты на перфокартах, это отдельная тема.

ПерфокартаПерфокарта

Так вот, вернемся к установки MC на Mac OS. Уверен, те кто давно работает за компьютером, помнит времена Norton Commander и Volkov Commander (Российская версия) и прочих файловых менеджеров, которые помогали работать на компьютере. До того как появился Windows 3.11 и вообще полноценный Windows, основным интерфейсом был MS-DOS. А для UNIX систем был создан Midnight Commander.

Сегодня я решил установить MC на Mac OS Catalina. Зачем? Иногда нужен доступ к папкам и всем каталогам, а их нет, Apple все пытается спрятать. Через терминал - это отдельный танец с бубном, не очень удобно.

Установка не в 2 клика, все оказалось не так просто, как хотелось бы.

Решил поделиться опытом, вдруг кто-то о подобном задумался и не знает как.

Процесс установки

1. Требуется установить Xcode

Берем бесплатную версию Xcode с App Store и устанавливаем.

После установки Xcode выполнить команду в строке терминала:

 xcode-select --install

Если при запуске получили ответ: xcode-select: error: command line tools are already installed, use "Software Update" to install updates. Значит у вас уже установлен Xcode, тогда пропускайте пункт 1 установки Xcode.

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

Если этого не сделать то в последующей Homebrew будет выдавать предупреждение.

2. Установка Homebrew

Чтобы скачать и установить Homebrew, запустим сценарий установки в командной строке который приведен ниже и ждем когда скрипт сделает свое дело:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Далее идет примерно такая установка.

3. Установка MC

Теперь можно установить Midnight Commander. В командной строке набираем:

brew install mc

После установки в командной строке терминала набираем:

mc
Окно MC в Mac OS (из Терминала)Окно MC в Mac OS (из Терминала)

Источники, которые использовались при написании статьи:
Homebrew менеджер пакетов для OS X Mavericks 10.9 (04.02.2014)
Midnight Commander на Mac OS X установка и настройка (09.09.2016)
Midnight Commander на Mac OS X установка и настройка (12.02.2014)

Подробнее..

Из песочницы Ты еще не используешь tmux наполную! (Наверное)

25.08.2020 12:13:42 | Автор: admin
Привет, Хабр! Представляю вашему вниманию перевод статьи "(tmux".

Содержание


  • Что такое tmux
  • Запуск и начало новой сессии
  • Открытие нового окна
  • Переходы между окнами
  • Разделение окон и создание панелей
  • Передвижение между панелями
  • Передвижение между сессиями
  • [Практическое использование] Переадресация отображаемого содержания в tmux
  • [Практическое использование] Отображение названия ветки Git в информационном поле
  • [Практическое использование] Отображение пути текущей операции
  • [Практическое использование] Вызов сниппета
  • Ссылка на настройки .tmux.conf
  • Совместимость версий tmux

Что такое tmux


tmux терминальный мультиплексор. Когда работаешь на машине, использующую SSH, исполняешь увесистую программу, но хочешь без прекращения исполнения перейти к другой задаче и т.д., то tmux может очень пригодиться.

Но возможности tmux на этом на этом не заканчиваются. Есть различные удобные варианты использования tmux, что я и хочу продемонстрировать на примерах ниже.

Базовая идея похожа на моды в Vim. С помощью prefixa (зарезервированные key bindings или привязка клавиш) можно изменить мод, по умолчанию используется привязка ctrl + b.

Запуск и начало новой сессии


Если ваша ОС Ubuntu или Debian, вы можете установить tmux командой `sudo apt-get install tmux`. На MacOS brew install tmux.

Команда для запуска:

$ tmux

Если хотите запустить tmux и сразу дать название новой сессии, используйте эту команду:
$ tmux new -s { Название сессии }

image

Открытие нового окна


Создав сессию в tmux, вы также можете создавать новые окна. Стандартная связка ctrl +b + c. Если вы сохранили свой prefix, можете использовать связку prefix + c. Скорее всего, значение c create, отсюда и такая связка.

image

Переходы между окнами


Можно также свободно переключаться между созданными окнами. Стандартные связки для этого prefix + p (p previous) и prefix + n (n next).

Использовать prefix не всегда удобно, поэтому я для себя кастомизировал связки клавиш для перехода между окнами: shift + rightKey для следующего окна и shift + leftKey для предыдущего.

image

Разделение окон и создание панелей


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

Без привязки клавиш, команды для разделения окна prefix + split-window -h, prefix + split-window -v.

Так как прописывать это каждый раз не особо хочется, я сделал для себя хоткеи в виде prefix + "-", prefix + "|".

image

Передвижение между панелями


Стандартные команды для передвижения между панелями сложноваты, не очень удобны в обращении, поэтому я и в этом случае назначил свои хоткеи: ctrl + shift + upKey, ctrl + shift + downKey, ctrl + shift + rightKey, ctrl + shift + leftKey.

image

Передвижение между сессиями


С помощью связки клавиш ctrl + t можно вызвать список сессий, а клавишами выбрать нужную сессию.

image

[Практическое использование] Переадресация отображаемого содержания в tmux


По сути, tmux является своего рода виртуальным терминалом, содержащимся в директории /dev/pts/{fooBar}. Для каждой панели создается такая же директория.

Другими словами, если мы определим {fooBar} каждой панели, мы сможем передавать содержимое панели X, разделив, например, на stderr и stdout, на панели Y и Z.

Таким образом можно выводить на разные панели stderr и stdout программы, которые вы пишите, а также использовать терминал как лог операций.

image

[Практическое использование] Отображение названия ветки Git в статус баре


Это лайфхак, который использует возможность чтения Shellscript и Python script из .tmux.conf файла конфигурации tmux.

Статус бар можно настроить следующей командой:

set-option -g status-right '#{host} #(tmux run-shell "tmux_hook --default true --git-path #{pane_current_path}")'

#{host} это, очевидно, имя хоста, а tmux run-shell запускает настраиваемый скрипт, который возвращает value в настройки статус бар.

tmux_hook это файл, который я создал для отображения времени и текущей ветки Git, но он, по сути, может вернуть любую текстовую информацию. Например, если правильно настроить, можно в статус баре отображать даже таймлайн своего твиттера.

image

[Практическое использование] Отображение пути текущей операции


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

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

setw -g pane-border-format '#{pane_tty} | #{pane_current_path}'

image

[Практическое использование] Вызов сниппета


Несмотря на то, что tmux является менеджером сессий с функцией разделения терминала, он может выполнять некоторые функции IDE (круто, не правда ли?). Вы можете забиндить свои хоткеи на специальную настройку send-keys и вызвать их в терминале.

Например, если настроить send-keys как на моем примере ниже, можно просто нажать prefix + 1 и вывести команды import, необходимые для работы с python.

bind -T prefix -n 1 send-keys "import os\nimport sys\n"

image

Ссылка на настройки .tmux.conf


Вот тут

Совместимость версий tmux


Иногда случается, что некоторые настройки tmux не работают в этом случае, его версия может быть либо слишком новой, либо слишком старой.

Все вышеописанное и конфиг, на который я оставил ссылку, для tmux версии 2.8 и выше. Если у вас что либо не работает, проверьте, подходит ли вам данная версия.

Если вы соберетесь самостоятельно что-то отлаживать, то прежде всего стоит обратиться к man tmux самой надежной документации по tmux на данный момент.

Ссылка на оригинал данной статьи тут

Мы будем очень рады, если вы расскажете нам, понравилась ли вам данная статья, понятен ли перевод, была ли она вам полезна?
Подробнее..
Категории: Терминал , Оболочки , Vim , Tmux

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru