<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Доктор Лексиум</title>
	<atom:link href="https://www.lexium.ru/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.lexium.ru</link>
	<description>Разработка сайтов и веб-приложений</description>
	<lastBuildDate>Thu, 22 Oct 2026 07:57:14 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.lexium.ru/images/2020/11/cropped-favicon-lex-512-32x32.png</url>
	<title>Доктор Лексиум</title>
	<link>https://www.lexium.ru</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Термопринтер LX-D02 без приложения: печать с ПК и из Home Assistant</title>
		<link>https://www.lexium.ru/2026/10/termoprinter-lx-d02-pechat-s-pk-i-home-assistant/</link>
					<comments>https://www.lexium.ru/2026/10/termoprinter-lx-d02-pechat-s-pk-i-home-assistant/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 07:57:14 +0000</pubDate>
				<category><![CDATA[Скрипты и серверы]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=10365</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2026/10/th_2026-10-22_10-53-24-200x200.png" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" /><p>Китайский BLE-термопринтер, который «работает только с Funny Print», печатает с компьютера одной командой и сообщения из семейного чата через Home Assistant. Протокол, код на Python, очередь печати и пять граблей.</p>
The post <a href="https://www.lexium.ru/2026/10/termoprinter-lx-d02-pechat-s-pk-i-home-assistant/">Термопринтер LX-D02 без приложения: печать с ПК и из Home Assistant</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>Года уже полтора примерно на моей полке пылился маленький термопринтер LX-D02. Их продают на маркетплейсах под десятками названий: котик или пингвинчик, встроенный аккумулятор, рулончик чековой ленты шириной 57 мм. Покупал я его с целью экспериментов: чтобы бирки печатать или фоточки в стиле &#171;почти полароид&#187; но на чековой ленте. Ну и конечно хотелось сделать так, чтобы компьютер или умный дом могли там выдавать что-нибудь короткое. Напоминание, список покупок, сообщение из чата.</p>
<p>Но как выяснилось, такое производитель заблокировал. Принтер дружит только с приложением Funny Print на смартфоне. USB-порт у него только для зарядки, Windows его как бы видит, но и только. Bluetooth типа есть, но BLE (Bluetooth Low Energy), и никакого «последовательного порта» для ПК. Весной я убил на него ни один вечер, и нейронка, с которой я советовался, после всех мучений выдала гениальное: «Займитесь другим проектом. Или купите принтер с нормальным RS232/TTL».</p>
<p><a href="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-22-35.jpg" data-rel="lightbox-image-0" data-rl_title="" data-rl_caption="" title=""><img fetchpriority="high" decoding="async" class="size-large wp-image-10374 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-22-35-800x611.jpg" alt="" width="800" height="611"></a></p>
<p>Вот и кукует теперь этот пластиковый зверёк, пылью покрывается. Но за несколько месяцев нейросети поумнели и набрались опыта. Так что&#8230;</p>
<p>Однажды, листопадным осенним вечером я вспомнил про сие чудовище китайской электроники, и&#8230; теперь принтер печатает с ПК одной командой, а из Home Assistant печатает сообщения из семейного чата. Ниже о том как это было сделано: с кодом и граблями, на которых я с увлечением отплясывал.</p>
<p><span id="more-10365"></span></p>
<div class="tip-box"><strong>Кому пригодится:</strong> владельцам LX-D02 и похожих принтеров с приложением Funny Print (Xiqi, DOLEWA и другие бренды). Скорее всего, подойдёт для любого принтера, который в списке Bluetooth виден как <code>LX-D02</code> и у которого есть сервис <code>FFE6</code>.</div>
<p><!-- ФОТО: принтер с лентой, на которой напечатано сообщение из чата --></p>
<h2>Протокол: спасибо тем, кто был раньше</h2>
<p>Сниффать Bluetooth мне не пришлось. Протокол уже разобрали ValdikSS в <a href="https://github.com/ValdikSS/printer-driver-funnyprint" target="_blank" rel="noopener">printer-driver-funnyprint</a> и klimromanyuk в <a href="https://github.com/klimromanyuk/funnyprint" target="_blank" rel="noopener">funnyprint</a>. Я сверил их реализации между собой и собрал минимальную версию на Python.</p>
<p>Коротко, как это устроено:</p>
<ul>
<li>Принтер рекламирует себя как <code>LX-D02</code>. Команды пишутся в характеристику <code>FFE1</code>, ответы приходят уведомлениями из <code>FFE2</code>.</li>
<li>Ширина печати 384 точки, то есть 48 байт на строку. За раз отправляется пакет из двух строк, 96 байт.</li>
<li>Перед печатью нужно «рукопожатие»: принтер присылает вызов, а в ответ ждёт байт, посчитанный по CRC16 от его MAC-адреса. Без этого он молча игнорирует данные. Видимо, это защита от «чужих» приложений.</li>
<li>Дальше задаётся плотность (0..7), количество пакетов, и пакеты идут потоком. Когда лента допечатана, принтер отвечает <code>5a06</code>.</li>
</ul>
<p>Текст принтер не понимает, только картинку. Поэтому текст сначала рисуется в чёрно-белое изображение шириной 384 точки через Pillow, а потом режется на пакеты.</p>
<h2>Весь протокол в одном файле</h2>
<p>Вот он целиком, это 143 строки. В конце самопроверка: <code>python printer.py</code> должен напечатать в консоль <code>ok</code>.</p>
<pre><code>"""LX-D02 (FunnyPrint) protocol. No Home Assistant imports: also used by ../../lxd02.py.

Protocol from github.com/ValdikSS/printer-driver-funnyprint.
"""
import asyncio
from pathlib import Path

from PIL import Image, ImageDraw, ImageFont

WRITE = "0000ffe1-0000-1000-8000-00805f9b34fb"
NOTIFY = "0000ffe2-0000-1000-8000-00805f9b34fb"
WIDTH = 384  # dots, 48 bytes per row
FONT = Path(__file__).with_name("DejaVuSans.ttf")


def crc16(data):
    crc = 0
    for b in data:
        for i in range(8):
            if ((crc &gt;&gt; 15) &amp; 1) ^ ((b &gt;&gt; (7 - i)) &amp; 1):
                crc = ((crc &lt;&lt; 1) &amp; 0xFFFF) ^ 0x1021
            else:
                crc = (crc &lt;&lt; 1) &amp; 0xFFFF
    return crc


def handshake_reply(mac):
    r = crc16(b"\x00" + bytes.fromhex(mac.replace(":", ""))) &gt;&gt; 8
    return b"\x5a\x0b" + bytes([r]) * 10


def wrap(text, font, width):
    out = []
    for para in text.split("\n"):
        line = ""
        for word in para.split(" "):
            cand = f"{line} {word}" if line else word
            if line and font.getlength(cand) &gt; width:
                out.append(line)
                line = word
            else:
                line = cand
        out.append(line)
    return out


def render(text, size=28, separator=False):
    font = ImageFont.truetype(str(FONT), size)
    lines = wrap(text, font, WIDTH - 8)
    text_h = (size + 6) * len(lines) + 4
    h = text_h + (16 if separator else 0)
    img = Image.new("1", (WIDTH, h + h % 2), 1)
    d = ImageDraw.Draw(img)
    for i, line in enumerate(lines):
        d.text((4, 2 + i * (size + 6)), line, font=font, fill=0)
    if separator:
        d.rectangle((0, text_h + 6, WIDTH - 1, text_h + 9), fill=0)
    return img


def to_payloads(img):
    """1-bit image, WIDTH wide -&gt; 96-byte payloads, two rows each, 1 = black."""
    if img.height % 2:
        img = img.crop((0, 0, WIDTH, img.height + 1))  # pads with 0 = black
        img.paste(1, (0, img.height - 1, WIDTH, img.height))
    raw = bytes(b ^ 0xFF for b in img.tobytes())
    rows = [raw[i:i + 48] for i in range(0, len(raw), 48)]
    return [rows[i] + rows[i + 1] for i in range(0, len(rows), 2)]


async def print_payloads(client, mac, payloads, density=3, feed=40):
    """Handshake and print on an already connected BleakClient."""
    payloads = payloads + [bytes(96)] * feed
    events = asyncio.Queue()

    def w(data):
        return client.write_gatt_char(WRITE, data, response=False)

    async def wait_for(prefix, timeout=5):
        while True:
            data = await asyncio.wait_for(events.get(), timeout)
            if data[:2] == prefix:
                return data

    await client.start_notify(NOTIFY, lambda _, data: events.put_nowait(bytes(data)))
    await w(b"\x5a\x01" + bytes(10))  # device info
    await asyncio.sleep(0.5)
    await w(b"\x5a\x0a" + bytes(10))  # challenge
    await wait_for(b"\x5a\x0a")
    await w(handshake_reply(mac))
    if (await wait_for(b"\x5a\x0b"))[2] != 1:
        raise RuntimeError("LX-D02 handshake failed")

    await w(b"\x5a\x0c" + bytes([max(0, min(7, density))]))
    await asyncio.sleep(0.3)
    n = len(payloads)
    await w(b"\x5a\x04" + n.to_bytes(2, "big") + b"\x00\x00")
    await asyncio.sleep(0.1)

    # Flow control as in klimromanyuk/funnyprint: the printer's buffer is small.
    # 5a08 = "pause, buffer full"; 5a05 + row number = "lost rows, resend from here";
    # 5a06 = "done". Without this, long prints (pictures) come out cut short.
    cur, paused, rests = 0, False, 0
    try:
        while True:
            if paused or cur &gt;= n:
                data = await asyncio.wait_for(events.get(), 90 if paused else max(60, n * 0.5))
            elif not events.empty():
                data = events.get_nowait()
            else:
                await w(b"\x55" + cur.to_bytes(2, "big") + payloads[cur] + b"\x00")
                cur += 1
                await asyncio.sleep(0.025)
                continue
            kind = data[:2]
            if kind == b"\x5a\x06":
                return
            if kind == b"\x5a\x08":
                paused = True
            elif kind == b"\x5a\x05":
                lost = int.from_bytes(data[2:4], "big")
                if paused:  # let the printer print out its buffer, then resend
                    rests += 1
                    await asyncio.sleep(min(8.0, 2.0 + rests * 0.5))
                    while not events.empty():
                        more = events.get_nowait()
                        if more[:2] == b"\x5a\x06":
                            return
                        if more[:2] == b"\x5a\x05":
                            lost = int.from_bytes(more[2:4], "big")
                    paused = False
                cur = lost
    finally:
        await w(b"\x5a\x04" + n.to_bytes(2, "big") + b"\x01\x00")


if __name__ == "__main__":
    assert handshake_reply("00:00:00:00:00:00") == b"\x5a\x0b" + bytes(10)
    assert to_payloads(Image.new("1", (WIDTH, 2), 0)) == [b"\xff" * 96]
    assert to_payloads(Image.new("1", (WIDTH, 1), 0)) == [b"\xff" * 48 + bytes(48)]
    assert render("x", separator=True).height == render("x").height + 16
    assert len(wrap("a " * 200, ImageFont.truetype(str(FONT), 28), WIDTH)) &gt; 1
    print("ok")</code></pre>
<p>Шрифт <code>DejaVuSans.ttf</code> лежит рядом с файлом. Это не прихоть: системного шрифта с кириллицей в контейнере Home Assistant нет, и вместо русского текста печатаются квадратики.</p>
<h2>Печать с компьютера</h2>
<p>Скрипт для ПК, <code>lxd02.py</code>, лежит в <a href="https://git.08h.ru/alex/lx-d02" target="_blank" rel="noopener">репозитории</a> рядом с <code>printer.py</code>. Он сам находит принтер по имени, подключается и печатает. Ставим зависимости и печатаем:</p>
<pre><code>pip install "bleak&lt;1.0" pillow
python lxd02.py "Привет" "Вторая строка"
python lxd02.py фото.jpg</code></pre>
<p>Картинки он растягивает на ширину ленты, альбомные поворачивает вдоль неё.</p>
<div class="warning-box"><strong>Грабли №1: версия bleak.</strong> На моём Python 3.9 свежий bleak 1.x падает прямо при импорте. Версия 0.22.3 (<code>bleak&lt;1.0</code>) работает. На Python поновее, возможно, пойдёт и 1.x.</div>
<div class="warning-box"><strong>Грабли №2: принтер однолюб.</strong> LX-D02 держит только одно BLE-соединение. Если телефон с открытым Funny Print подключён к принтеру, тот перестаёт рекламировать себя, и ни ПК, ни Home Assistant его не находят. Долго ловил «принтер пропал» именно из-за этого. Перед экспериментами закрывайте приложение.</div>
<h2>Интеграция в Home Assistant</h2>
<p>У меня Home Assistant Supervised крутится в Docker на ТВ-приставке с rk3318, и встроенный в неё Bluetooth доступен через BlueZ. Поверх <code>printer.py</code> я написал небольшую интеграцию <code>lxd02</code>: папку <code>custom_components/lxd02</code> копируем в <code>/config/custom_components/</code>, в <code>configuration.yaml</code> добавляем MAC принтера и перезапускаем HA.</p>
<pre><code>lxd02:
  mac: AA:BB:CC:DD:EE:FF</code></pre>
<p>После этого появляется действие <code>lxd02.print_text</code>:</p>
<pre><code>action: lxd02.print_text
data:
  text: "Привет из Home Assistant"
  size: 28         # размер шрифта, 10..120
  density: 3       # плотность, 0..7
  feed: 40         # прогон ленты после текста
  separator: true  # линия под текстом</code></pre>
<p>Самое ценное в интеграции — <strong>очередь</strong>. Принтер может быть выключен, лежать в другой комнате или быть занят телефоном. Поэтому каждое задание сначала попадает в очередь на диске (<code>/config/.storage/lxd02</code>), и перезапуск HA её не теряет. Как только HA снова видит принтер, очередь печатается по порядку. Если задание оборвалось на середине, оно остаётся первым и печатается заново целиком.</p>
<div class="warning-box"><strong>Грабли №3: HA не повторяет попытку сам.</strong> Сначала я сделал печать по событию «принтер появился в эфире». Первая неудачная попытка, и дальше тишина. Оказалось, Home Assistant пропускает рекламные пакеты, данные в которых не изменились, поэтому повторного события просто не бывает. Пришлось добавить повтор каждые 60 секунд, пока очередь не пуста.</div>
<h2>Зачем всё это: семейный чат на чековой ленте</h2>
<p>У нас дома есть нода <a href="https://meshcore.co.uk/" target="_blank" rel="noopener">MeshCore</a>, это текстовая радиосеть без интернета и без операторов. Интеграция MeshCore для Home Assistant генерирует событие на каждое входящее сообщение. Осталось связать два конца:</p>
<pre><code>triggers:
- trigger: event
  event_type: meshcore_message
  event_data:
    message_type: channel
conditions:
- condition: template
  value_template: "{{ trigger.event.data.channel | lower == 'family' and not trigger.event.data.outgoing | default(false) }}"
actions:
- action: lxd02.print_text
  continue_on_error: true
  data:
    size: 24
    separator: true
    text: "{{ trigger.event.data.sender_name }} · {{ now().strftime('%d.%m %H:%M') }}\n{{ trigger.event.data.message }}"
mode: queued
max: 20</code></pre>
<p>Теперь каждое сообщение из канала <code>Family</code> печатается на ленте: в первой строке отправитель и время, ниже текст, под ним черта. Свои исходящие сообщения я отфильтровал: интеграция MeshCore присылает событие для них заново на каждое обновление статуса доставки, и без фильтра одно и то же сообщение печаталось по несколько раз.</p>
<p>Если принтер в этот момент недоступен, сообщение ждёт в очереди и печатается позже, но с исходным временем получения в заголовке.</p>
<p><!-- ФОТО: кусок ленты с несколькими сообщениями --></p>
<h2>Грабли №4: Bluetooth, который засыпает навсегда</h2>
<p>Время от времени принтер «отваливался», и приходилось переподключать его руками. Я грешил на принтер: мол, не рассчитан быть наготове 24/7. Одну причину я уже описал выше, это повторы в очереди. Вторая оказалась интереснее, и принтер в ней вообще ни при чём. Зависал Bluetooth-чип самой приставки: в <code>dmesg</code> появлялось <code>hci0: Opcode 0x0c03 failed: -110</code>, адаптер уходил в DOWN, а HA показывал <code>NotReady</code>. Помогал только перезапуск драйвера.</p>
<p>Раз помогает перезапуск, пусть его делает машина. Скрипт-сторож раз в минуту проверяет адаптер, и если тот лежит, перепривязывает чип к драйверу:</p>
<pre><code>#!/bin/sh
# Revive hung built-in Bluetooth (BCM4334 on UART, hci_uart_bcm).
# Symptom: hci0 DOWN, dmesg "hci0: Opcode 0x0c03 failed: -110", HA "NotReady".
# Run by bt-watchdog.timer every minute.
D=/sys/bus/serial/drivers/hci_uart_bcm

up() { hciconfig hci0 2&gt;/dev/null | grep -q "UP RUNNING"; }

up &amp;&amp; exit 0
sleep 20  # HA/BlueZ may be resetting the adapter itself
up &amp;&amp; exit 0

logger -t bt-watchdog "hci0 down, rebinding serial0-0"
echo serial0-0 &gt; $D/unbind 2&gt;/dev/null
sleep 2
echo serial0-0 &gt; $D/bind
sleep 8
timeout 5 bluetoothctl power on &gt;/dev/null 2&gt;&amp;1
if up; then
    logger -t bt-watchdog "hci0 back up"
else
    logger -t bt-watchdog "hci0 still down after rebind"
fi</code></pre>
<p>Запускается он systemd-таймером:</p>
<pre><code>[Unit]
Description=Check Bluetooth chip every minute

[Timer]
OnBootSec=3min
OnUnitActiveSec=1min

[Install]
WantedBy=timers.target</code></pre>
<p>Имя драйвера (<code>hci_uart_bcm</code>) и устройства (<code>serial0-0</code>) у вас может быть другим, смотрите в <code>/sys/bus/serial/drivers/</code>. Если Bluetooth у вас USB-свисток, то и перезапускать нужно по-другому.</p>
<h2>Грабли №5: длинная печать рвётся</h2>
<p>В первой версии код слал пакеты с фиксированной паузой и не слушал принтер. Короткие сообщения печатались отлично, а длинная картинка обрывалась на середине. Принтер на самом деле сообщает «подожди, буфер полон» (<code>5a08</code>) и «потерял строки, дошли с такой-то» (<code>5a05</code>). В коде выше это уже учтено, по образцу <a href="https://github.com/klimromanyuk/funnyprint" target="_blank" rel="noopener">klimromanyuk/funnyprint</a>. Подробности — в <a href="https://www.lexium.ru/?p=10366">посте про принтер для Windows</a>.</p>
<h2>Итог</h2>
<p>Устройство, которое «работает только с приложением», оказалось вполне обычным BLE-гаджетом. Чтобы с ним договориться, хватило полутора сотен строк на Python, очереди и одного сторожевого скрипта. Вещь, которая полтора года лежала на полке, теперь каждый день печатает сообщения из семейного чата.</p>
<p>Весь код открыт: <a href="https://git.08h.ru/alex/lx-d02" target="_blank" rel="noopener">git.08h.ru/alex/lx-d02</a>. А в <a href="https://www.lexium.ru/?p=10366">следующем посте</a> принтер становится обычным принтером Windows, на который можно печатать из Блокнота и браузера.</p>
<p>Следующий шаг напрашивается сам: печатать по утрам погоду и задачи на день, а по вечерам список покупок. Если у вас такой же принтер и что-то не заводится, пишите в комментариях, разберёмся.</p>
<p>Историю о том, как это всё рождалось, с отчаянием и счастливым концом, я по ходу дела записывал в <a href="https://www.alexcube.ru/blog/2026/04/01-04-2026-sreda/" target="_blank" rel="noopener">личном дневнике</a>.</p>
<div></div>The post <a href="https://www.lexium.ru/2026/10/termoprinter-lx-d02-pechat-s-pk-i-home-assistant/">Термопринтер LX-D02 без приложения: печать с ПК и из Home Assistant</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2026/10/termoprinter-lx-d02-pechat-s-pk-i-home-assistant/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Термопринтер LX-D02 как обычный принтер Windows: три драйвера и ESC/POS</title>
		<link>https://www.lexium.ru/2026/10/termoprinter-lx-d02-printer-windows/</link>
					<comments>https://www.lexium.ru/2026/10/termoprinter-lx-d02-printer-windows/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 07:51:34 +0000</pubDate>
				<category><![CDATA[Скрипты и серверы]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=10366</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2026/10/th_2026-10-22_10-53-24-200x200.png" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" /><p>Как сделать из BLE-термопринтера LX-D02 обычный принтер Windows: почему не подошли Print to PDF и IPP Class Driver, как помог драйвер POS-58 и разбор ESC/POS, и почему длинная картинка печаталась обрезанной.</p>
The post <a href="https://www.lexium.ru/2026/10/termoprinter-lx-d02-printer-windows/">Термопринтер LX-D02 как обычный принтер Windows: три драйвера и ESC/POS</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>В <a href="https://www.lexium.ru/?p=10365">прошлый раз</a> я научил китайский термопринтер LX-D02 печатать с компьютера командой <code>python lxd02.py "текст"</code> и из Home Assistant.</p>
<p><a href="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-22-35.jpg" data-rel="lightbox-image-0" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class=" wp-image-10374 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-22-35-800x611.jpg" alt="" width="501" height="383"></a></p>
<p>Удобно, но это всё ещё печать «на программерском». А хотелось, чтобы принтер стоял в списке рядом с обычным, и на него можно было отправить что угодно: заметку из Блокнота, страницу из браузера, картинку.</p>
<p>Своего драйвера у LX-D02 нет, колхозить самописный для Windows с нуля — удовольствие на любителя. Поэтому план был простой: пусть Windows печатает на какой-нибудь готовый драйвер, а уже тот отдаёт результат не в сам принтер, а в порт на этом же компьютере. Там его ловит небольшой сервер на Python, превращает в картинку шириной 384 точки и отправляет по Bluetooth.</p>
<p>Звучит как вечерок работы. Однако, по и тогу, вышло три драйвера, один самописный IPP-принтер и одна вовремя найденная находка из прошлого.</p>
<p><span id="more-10366"></span></p>
<div class="tip-box"><strong>Результат</strong> лежит в открытом репозитории <a href="https://git.08h.ru/alex/lx-d02" target="_blank" rel="noopener">git.08h.ru/alex/lx-d02</a>: принтер для Windows, печать картинок правым кликом, командная строка и интеграция для Home Assistant. Установка — один скрипт.</div>
<p><!-- ФОТО: распечатка из Блокнота и картинка с часами на ленте --></p>
<h2>Попытка 1: Microsoft Print to PDF</h2>
<p>Самым очевидным кандидатом стал драйвер «Microsoft Print to PDF» (есть в любой Windows начиная с). Порт ему можно назначить любой, в том числе сетевой <code>127.0.0.1:9100</code>. Тогда вместо сохранения файла, PDF уходит прямиком в мой сервер, а тот рисует его библиотекой <code>pypdfium2</code>.</p>
<p>Заработало сразу. Тестовая лента вышла, я довольный пошёл печатать из Блокнота и получил… буквы размером с маковое зёрнышко.</p>
<p><a href="https://www.lexium.ru/images/2026/10/2026-10-22_10-31-52.png" data-rel="lightbox-image-1" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-10376 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/2026-10-22_10-31-52.png" alt="" width="122" height="177"></a></p>
<p>Причина банальна. PDF-драйвер знает только офисные форматы: A4, Letter, A3 и подобные. Блокнот честно раскладывает текст на лист шириной 210 мм, а сервер потом ужимает этот лист до 48 мм ширины печатной ленты. В четыре с лишним раза. В логе так и было: страница целиком, 555 точек в длину.</p>
<p>Значит, Windows должна с самого начала знать, что бумага у принтера шириной 58 мм. А PDF-драйвер этого не умеет.</p>
<h2>Попытка 2: притворяемся сетевым принтером (IPP)</h2>
<p>В Windows есть ещё один встроенный драйвер — <strong>Microsoft IPP Class Driver</strong>. Он для современных сетевых принтеров, которые сами рассказывают о себе по протоколу IPP: какие у них форматы бумаги, разрешение, цветность.</p>
<div class="comment">Красота: значит, достаточно написать сервер, который представится принтером с рулоном 58 мм, и Windows сама предложит этот размер всем программам.</div>
<p>IPP — бинарный протокол поверх HTTP: группы атрибутов, теги типов, вложенные коллекции. Минимальный сервер, который отвечает на «Какие у тебя возможности?», принимает задания и сообщает их статус, занял около 270 строк. Windows подключилась, задала свои вопросы (в логе было видно, что она спрашивает <code>media-supported</code>, <code>media-col-database</code> и ещё полсотни атрибутов)… и показала в списке бумаги только Letter и A4.</p>
<p>Дальше пошли эксперименты. Плюс в том, что Windows перечитывает возможности принтера при каждом запросе, так что переустанавливать ничего не нужно: поменял список, перезапустил сервер, посмотрел, что она выбрала.</p>
<ul>
<li>Самоописывающие названия по стандарту PWG <code>om_..._58x200mm</code> и <code>custom_58x200mm</code> — выброшены.</li>
<li>Визитка, A7, A8, карточка 3×5 дюйма — выброшены.</li>
<li>A6 для проверки — принят.</li>
<li>A5, которому я подсунул размеры 58×200 мм, — принят, но с честными размерами A5. Мои цифры Windows проигнорировала и взяла размер по названию.</li>
<li>Диапазон «ширина 58 мм, длина любая» для своего размера бумаги — проигнорирован.</li>
</ul>
<p><strong>Вывод:</strong> IPP-драйвер Windows понимает только знакомые ему названия бумаги, и самое узкое из них — A6, 105 мм. Это лучше, чем A4, но всё равно вдвое мельче нужного. 270 строк отправились в корзину.</p>
<p>Была ещё идея из серии: «А может его как факс добавить?». Увы: факс-драйвер тоже живёт в мире A4 и Letter и выдаёт TIFF для факсимильного аппарата, то есть те же грабли.</p>
<h2>Попытка 3: находка из прошлого</h2>
<p>Пока я перебирал драйверы командой <code>Get-PrinterDriver</code>, в списке мелькнуло <strong>POS-58 11.2.0.0</strong>. Это стандартный драйвер для китайских 58-мм чековых принтеров. Я сам поставил его весной, когда первый раз пытался подружить LX-D02 с компьютером, ничего не добился и забыл.</p>
<p>А ведь это ровно то, что нужно. Драйвер — обычный Unidrv, то есть текстовый файл описания <code>POS58.GPD</code> плюс встроенный в Windows движок.</p>
<p>Внутри:</p>
<ul>
<li>разрешение 203×203 точки на дюйм, как у LX-D02;</li>
<li>бумага шириной 58 мм, длиной 210, 297 или 3276 мм, плюс свой размер;</li>
<li>печатная ширина 1151 единица при 609 единицах на дюйм — это ровно 384 точки. Совпадение до точки.</li>
</ul>
<p>Выдаёт он команды ESC/POS — язык, на котором говорят почти все чековые принтеры. Я поставил принтер на этот драйвер с портом <code>127.0.0.1:9100</code>, напечатал строчку из Блокнота и посмотрел, что пришло:</p>
<pre><code>1b 70 00 40 50        ESC p  — открыть денежный ящик (спасибо, не надо)
1b 40                 ESC @  — сброс
1b 42 04 01           ESC B  — пискнуть
1d 76 30 00 30 00 18 00 + 1152 байта   GS v 0 — картинка 48×24 байта
1b 4a 15              ESC J  — прогнать ленту
...и так 99 раз</code></pre>
<p>Драйвер режет страницу на полосы по 24 строки и отправляет каждую командой <code>GS v 0</code>: ширина 48 байт (384 точки), высота 24 строки, дальше сами точки, единица — чёрный. Между полосами идёт прогон <code>ESC J</code>, и он сдвигает бумагу ровно на высоту полосы, так что полосы можно просто сложить друг под другом. Весь разбор:</p>
<pre><code>rows, pos = [], 0
while True:
    pos = data.find(b"\x1dv0", pos)
    if pos &lt; 0 or pos + 8 &gt; len(data):
        break
    w = data[pos + 4] | data[pos + 5] &lt;&lt; 8
    h = data[pos + 6] | data[pos + 7] &lt;&lt; 8
    band = data[pos + 8:pos + 8 + w * h]
    rows += [band[r * w:(r + 1) * w] for r in range(h)]
    pos += 8 + w * h</code></pre>
<p>Блокнот напечатал текст нормального размера.</p>
<p><a href="https://www.lexium.ru/images/2026/10/2026-10-22_10-36-06.png" data-rel="lightbox-image-2" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-10377 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/2026-10-22_10-36-06.png" alt="" width="129" height="151"></a></p>
<p>С третьей попытки.</p>
<h2>Доводка: рулон, поля и картинки</h2>
<p><strong>Рулон бумаги.</strong> По умолчанию у POS-58 выбрана лента длиной 3276 мм, и браузер честно показывает в превью трёхметровую полоску с картинкой посередине. Колонтитул «Страница 1» уезжает в самый низ листа. Чтобы не тратить рулон, сервер срезает белое сверху и снизу и ужимает любой пустой промежуток длиннее 6 мм до 6 мм. Трёхметровая страница из Блокнота превратилась в 2 см ленты.</p>
<p><strong>Левое поле.</strong> Программы держат свои поля страницы, и текст начинался с отступом в треть ленты. Сервер находит, где начинаются чернила, и сдвигает всё содержимое к левому краю. Сдвиг общий для всей страницы, так что выравнивание по центру или вправо не ломается.</p>
<p><strong>Правый край.</strong> А вот здесь ничего не поделаешь: у драйвера печатная полоса 48 мм начинается от левого края листа 58 мм. Браузер с обычными полями сдвигает картинку к центру, и правые миллиметры драйвер срезает ещё до моего сервера. Лечится настройкой: поля «Минимальные». Тогда браузер берёт их у драйвера, и всё помещается.</p>
<p><strong>Картинки.</strong> Из «Фотографий» и браузера картинки выходили то мелкими, то обрезанными: они раскладывают картинку по листу, как им удобно.</p>
<p><a href="https://www.lexium.ru/images/2026/10/2026-10-22_10-37-24.png" data-rel="lightbox-image-3" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-10378 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/2026-10-22_10-37-24.png" alt="" width="349" height="218"></a></p>
<p>Поэтому для картинок я сделал обходной путь без драйвера. Правый клик по файлу → «Печать на LX-D02», и картинка растягивается ровно на ширину ленты. Альбомная поворачивается вдоль ленты, чтобы выйти крупнее, полутона передаются растром, как в газете. Это пункт в реестре <code>HKCU\Software\Classes\SystemFileAssociations\image\shell</code>, права администратора не нужны.</p>
<h2>И последние грабли: длинная печать</h2>
<p>Скриншот с часами вышел почти целым по ширине и обрезанным по длине. Первая версия кода слала пакеты с фиксированной паузой и не слушала принтер. А принтеру есть что сказать:</p>
<ul>
<li><code>5a08</code> — «подожди, буфер полон»;</li>
<li><code>5a05</code> + номер строки — «я потерял строки, дошли с этой»;</li>
<li><code>5a06</code> — «готово».</li>
</ul>
<p>Вот так выглядело вертикальное фото.</p>
<p><a href="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-38-27.jpg" data-rel="lightbox-image-4" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-large wp-image-10379 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-38-27-800x481.jpg" alt="" width="800" height="481"></a></p>
<p>Доходило примерно до середины, потом принтер думал, а затем спохватывался и заканчивал печать.</p>
<p>Потому, что короткие тексты проскакивали, а длинная картинка переполняла буфер. Код ждал ответа «готово» 30 секунд и потом сам закрывал задание, обрывая печать на середине.</p>
<p>Доработал. Теперь код по образцу <a href="https://github.com/klimromanyuk/funnyprint" target="_blank" rel="noopener">klimromanyuk/funnyprint</a> на паузе ждёт, пока принтер допечатает буфер, досылает потерянные строки и закрывает задание только по «готово»..&nbsp; Время ожидания растёт вместе с длиной задания. Картинка напечаталась целиком.</p>
<p><a href="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-41-12.jpg" data-rel="lightbox-image-5" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-large wp-image-10380 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/photo_2026-10-22_10-41-12-679x800.jpg" alt="" width="679" height="800"></a></p>
<p>Заодно лечится ещё одна мелочь: Windows иногда не может подключиться к уснувшему принтеру с первого раза и пишет <code>Unreachable</code>. Теперь подключение пробуется три раза.</p>
<h2>А почему не свой драйвер?</h2>
<p>Вопрос напрашивается: раз уж всё равно разбирался, почему бы не написать для LX-D02 настоящий драйвер?</p>
<p>Вариантов два, и оба проигрывают.</p>
<ul>
<li><strong>Свой файл описания для встроенного движка Windows</strong> (те же <code>.gpd</code> и <code>.inf</code>, что у POS-58). Написать можно за вечер, но <strong>64-битная Windows не ставит неподписанные драйверы</strong>. Для себя можно подписать своим сертификатом и добавить его в доверенные на каждом компьютере. Для других нужна подпись Microsoft, а это платный сертификат и их проверка. И даже после всего этого получится ровно то же, что уже даёт POS-58, только с другим названием в списке.</li>
<li><strong>Драйвер, который сам ходит в Bluetooth</strong> (монитор порта на C/C++ внутри службы печати). Тогда не будет нужен сервер на Python. И это плюс. Но зато и ошибка в таком модуле роняет печать во всей системе, отлаживать его тяжело, а подписывать всё-равно придётся. И это уже минус, при том размером с копьё.</li>
</ul>
<p>У <strong>готового</strong> драйвера и маленького <strong>сервера</strong> свои преимущества.</p>
<p>Драйвер POS-58 уже подписан и потому без проблем ставится везде.</p>
<p>Вся логика сервера живёт в паре сотен строк на Python: упал — перезапустился, не печатает — смотрю журнал и сохранённое задание, поправил — перезапустил, без перезагрузки и без переустановки драйвера. И тот же код печатает из командной строки и из Home Assistant.</p>
<p>Единственный минус — драйвер POS-58 придётся найти, но он обычно идёт с любым дешёвым 58-мм чековым принтером. Но если нашёл даже я, то это не должно стать проблемой.</p>
<h2>Как поставить у себя</h2>
<p>Нужны Python, Bluetooth и драйвер POS-58. Он обычно идёт с любым дешёвым 58-мм чековым принтером (либо ищем на просторах интернета). Дальше в PowerShell от имени администратора:</p>
<pre><code>git clone https://git.08h.ru/alex/lx-d02.git
cd lx-d02
pip install -r requirements.txt
Set-ExecutionPolicy -Scope Process Bypass
.\windows\install.ps1</code></pre>
<p>Скрипт добавит принтер LX-D02, сервер в автозапуск через Планировщик задач и пункт для картинок в контекстное меню. Удаление — <code>install.ps1 -Uninstall</code>.</p>
<h2>Итог</h2>
<p>Чековый принтер за копейки, который «работает только с приложением», теперь стоит в Windows рядом с офисным. Текст печатает из любой программы, а картинки — правым кликом (через &#171;Отправить&#187;), длинные задания не рвёт.</p>
<p><a href="https://www.lexium.ru/images/2026/10/2026-10-22_10-49-12.png" data-rel="lightbox-image-6" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-10381 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2026/10/2026-10-22_10-49-12.png" alt="" width="730" height="303"></a></p>
<p>Самый полезный урок этого вечера даже не про принтеры. Решение нашлось не в коде, а в списке того, что уже стоит на машине. Весенняя неудачная попытка оставила после себя драйвер, без которого осенью ничего бы не вышло. Так что не спешите удалять «бесполезное» после неудачных экспериментов.</p>
<p>Если у вас похожий принтер и что-то не заводится, пишите в комментариях или открывайте задачу в репозитории.</p>
<div></div>The post <a href="https://www.lexium.ru/2026/10/termoprinter-lx-d02-printer-windows/">Термопринтер LX-D02 как обычный принтер Windows: три драйвера и ESC/POS</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2026/10/termoprinter-lx-d02-printer-windows/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Как автоматизировать рутину: гид по пользовательским кнопкам в LaserGRBL</title>
		<link>https://www.lexium.ru/2026/06/magiya-peremennykh-g-kod-kotoryjj-podstraivaetsya-sam/</link>
					<comments>https://www.lexium.ru/2026/06/magiya-peremennykh-g-kod-kotoryjj-podstraivaetsya-sam/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Tue, 16 Jun 2026 12:29:38 +0000</pubDate>
				<category><![CDATA[Блог]]></category>
		<category><![CDATA[Лазер и ЧПУ]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9919</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2026/06/image-11-200x200.jpeg" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" srcset="https://www.lexium.ru/images/2026/06/image-11-200x200.jpeg 200w, https://www.lexium.ru/images/2026/06/image-11-410x410.jpeg 410w, https://www.lexium.ru/images/2026/06/image-11-800x800.jpeg 800w, https://www.lexium.ru/images/2026/06/image-11-768x768.jpeg 768w, https://www.lexium.ru/images/2026/06/image-11.jpeg 1024w" sizes="auto, (max-width: 200px) 100vw, 200px" /><p>Работа с лазерным станком часто включает повторение одних и тех же действий: подвод каретки, включение лазера для фокусировки, очерчивание границ заготовки. Постоянно прописывать G-код вручную или искать нужные команды в истории — пустая трата времени. Разработчики LaserGRBL предусмотрели элегантное решение — пользовательские кнопки (Custom Buttons). Это инструмент, который позволяет упаковать сложный набор команд в один клик мыши. Давайте разберем, как с ними работать и как с помощью встроенных переменных вывести...</p>
The post <a href="https://www.lexium.ru/2026/06/magiya-peremennykh-g-kod-kotoryjj-podstraivaetsya-sam/">Как автоматизировать рутину: гид по пользовательским кнопкам в LaserGRBL</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p><!-- Вступление --></p>
<p>Работа с лазерным станком часто включает повторение одних и тех же действий: подвод каретки, включение лазера для фокусировки, очерчивание границ заготовки. Постоянно прописывать G-код вручную или искать нужные команды в истории — пустая трата времени.</p>
<p>Разработчики LaserGRBL предусмотрели элегантное решение — <strong>пользовательские кнопки (Custom Buttons)</strong>. Это инструмент, который позволяет упаковать сложный набор команд в один клик мыши. Давайте разберем, как с ними работать и как с помощью встроенных переменных вывести автоматизацию на новый уровень.</p>
<div class="warning-box"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Состояние на Июнь 2026:</strong> Интерфейс LaserGRBL остается стабильным. Все приведенные скриншоты и пути актуальны для версии 3.8.2 и выше. Убедитесь, что ваша версия обновлена, чтобы использовать переменные <code>[$num]</code>.</div>
<p><!-- Блок 1: Что это --></p>
<h2>Что такое пользовательские кнопки?</h2>
<p>По сути, это программируемые макросы. Вы создаете графическую кнопку прямо на панели управления LaserGRBL и привязываете к ней блок команд G-кода. При нажатии станок выполняет всё, что вы прописали: от простого перемещения до запуска сложных циклов.</p>
<p>Это незаменимо, когда нужно:</p>
<ul>
<li>Быстро обрисовать «габаритный прямоугольник» будущей гравировки, чтобы убедиться, что заготовка лежит правильно.</li>
<li>Переместить инструмент в точку смены материала.</li>
<li>Реализовать сложную логику, например, включение лазера на минимальной мощности для прицеливания.</li>
</ul>
<p><!-- Блок 2: Создание --></p>
<h2>Где их найти и как создать?</h2>
<p>В LaserGRBL нет отдельного меню «Настройки макросов». Всё интуитивно спрятано в контекстном меню:</p>
<ol>
<li>Запустите программу и посмотрите на верхнюю панель, где расположены стрелки перемещения, кнопка «Домой» и т.д.</li>
<li>Кликните <strong>правой кнопкой мыши</strong> по любому пустому месту в этой области (или даже по существующей кнопке).</li>
<li>В выпадающем списке выберите <code>Add new</code> (Добавить новую), чтобы начать с чистого листа, или <code>Import</code> (Импортировать), если хотите загрузить готовый файл-образец.</li>
</ol>
<p><!-- Блок 3: Типы кнопок --></p>
<h2>Три типа кнопок: выбираем под задачу</h2>
<p>Перед написанием кода вы столкнетесь с выбором типа кнопки. От этого зависит, как она будет реагировать на ваши действия мышкой.</p>
<h3>1. Обычная кнопка (Button)</h3>
<p>Самый простой и популярный тип. Одно нажатие — один блок кода.</p>
<ul>
<li><strong>Когда использовать:</strong> Для абсолютного большинства задач. Запуск подготовительных процедур, установка нуля координат, выполнение конкретной G-команды.</li>
<li><strong>Пример:</strong> Рисуем рамку вокруг загруженной картинки.</li>
</ul>
<h3>2. Кнопка-переключатель (TwoStateButton)</h3>
<p>У нее два визуальных состояния (Вкл/Выкл) и два разных блока кода. Первое нажатие выполняет действие и «залипает», второе — выполняет альтернативный код и отлипает.</p>
<ul>
<li><strong>Когда использовать:</strong> Для опций, требующих фиксации. Идеальный пример — тестовое включение лазера.</li>
<li><strong>Сценарий:</strong> Нажали кнопку — лазер зажегся на минимальной мощности (помогает поймать фокус в середине линзы). Отпустили — лазер не гаснет. Нажали еще раз — лазер погас.</li>
</ul>
<h3>3. Кнопка с удержанием (PushButton)</h3>
<p>Выполняет код, только пока вы держите ее нажатой. Отпустили — срабатывает второй блок кода (обычно стоп или отмена).</p>
<ul>
<li><strong>Когда использовать:</strong> Для ручных перемещений. Это аналог джойстика. Пока держите — ось едет. Бросили — остановка.</li>
<li><strong>Важно:</strong> Требует особой осторожности в настройке, чтобы не сломать механику.</li>
</ul>
<p><!-- Блок 4: Переменные --></p>
<h2>Магия переменных: G-код, который подстраивается сам</h2>
<p>Главная сила кастомных кнопок — использование переменных. Вам не нужно вручную переписывать координаты каждый раз, когда меняется размер изображения. Переменные берут актуальные данные из интерфейса LaserGRBL. Они заключаются в квадратные скобки <code>[ ]</code>, и внутри них можно проводить вычисления.</p>
<p>Вот список самых необходимых переменных (валидны для LaserGRBL 2026):</p>
<table>
<thead>
<tr>
<th>Переменная</th>
<th>Что подставляется</th>
<th>Практический пример</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="3"><strong>Границы изображения</strong></td>
</tr>
<tr>
<td><code>[left]</code></td>
<td>Координата X левого края</td>
<td><code>G0 X[left] Y[top]</code></td>
</tr>
<tr>
<td><code>[right]</code></td>
<td>Координата X правого края</td>
<td><code>G0 X[right-5]</code></td>
</tr>
<tr>
<td><code>[top]</code></td>
<td>Координата Y верхнего края</td>
<td><code>G0 X[left] Y[top]</code></td>
</tr>
<tr>
<td><code>[bottom]</code></td>
<td>Координата Y нижнего края</td>
<td><code>G0 Y[bottom]</code></td>
</tr>
<tr>
<td><code>[width]</code></td>
<td>Ширина изображения</td>
<td><code>[width]/2</code></td>
</tr>
<tr>
<td><code>[height]</code></td>
<td>Высота изображения</td>
<td><code>G0 X[left+[width]/2]</code></td>
</tr>
<tr>
<td colspan="3"><strong>Интерфейс и перемещения</strong></td>
</tr>
<tr>
<td><code>[jogstep]</code></td>
<td>Текущий шаг перемещения (Jog Step)</td>
<td><code>G91 X[jogstep]</code></td>
</tr>
<tr>
<td><code>[jogspeed]</code></td>
<td>Текущая скорость подачи (Jog Speed)</td>
<td><code>G0 F[jogspeed]</code></td>
</tr>
<tr>
<td colspan="3"><strong>Координаты положения</strong></td>
</tr>
<tr>
<td><code>[WCO.X]</code></td>
<td>Смещение нуля (Work Offset) по осям</td>
<td><code>[WCO.Z]</code></td>
</tr>
<tr>
<td><code>[MPos.X]</code></td>
<td>Машинная позиция</td>
<td><code>G92 X[MPos.X+10]</code></td>
</tr>
<tr>
<td><code>[WPos.X]</code></td>
<td>Рабочая позиция</td>
<td><code>G0 X[WPos.X-5]</code></td>
</tr>
<tr>
<td colspan="3"><strong>Системные параметры GRBL</strong></td>
</tr>
<tr>
<td><code>[$num]</code></td>
<td>Значение настроек из прошивки</td>
<td><code>[$30]</code></td>
</tr>
</tbody>
</table>
<div class="tip-box"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Лайфхак:</strong> Внутри скобок работают простые формулы. Запись <code>[left+5]</code> сработает корректно и сдвинет каретку на 5 мм правее границы картинки. По состоянию на июнь 2026 года эта функция критически важна для точной обводки контура (Overscan).</div>
<p><!-- Блок 5: Готовые решения --></p>
<h2>Готовые решения: стартуем без программирования</h2>
<p>Если вы пока не готовы писать макросы самостоятельно, создатели LaserGRBL выложили в открытый доступ пакеты предустановленных кнопок. Это отличная база для обучения.</p>
<p><strong>Что нужно сделать:</strong></p>
<ol>
<li>Скачайте официальный файл с готовыми кнопками (обычно он идет в формате <code>.zip</code> или рядом с дистрибутивом программы).</li>
<li>Кликните правой кнопкой мыши по панели инструментов в LaserGRBL.</li>
<li>Выберите <strong>«Import»</strong>, укажите путь к файлу и загрузите его.</li>
</ol>
<p>Сразу после импорта вы получите рабочие кнопки для обводки контура, включения/выключения лазера и перемещений. Изучив их код (правый клик -&gt; Edit), вы быстро поймете логику и создадите свои.</p>
<p><!-- FAQ (микроразметка) --></p>
<section class="faq-section">
<h2>Часто задаваемые вопросы (FAQ)</h2>
<div class="faq-item">
<div class="faq-question">В: Можно ли переместить кнопки на панели?</div>
<div>
<p>Да. Зажмите клавишу <code>Alt</code>, захватите кнопку мышью и перетащите в нужное место. Там же в контекстном меню можно добавить разделители для группировки.</p>
</div>
</div>
<div class="faq-item">
<div class="faq-question">В: Почему кнопка не нажимается или не работает в 2026 версии?</div>
<div>
<p>Проверьте, подключен ли COM-порт (статус должен быть <code>Idle</code> или <code>Run</code>). Если в коде есть ошибка в синтаксисе G-кода, LaserGRBL подсветит строку красным в логе при попытке выполнения. Убедитесь, что у вас стоит версия не ниже 3.8.2.</p>
</div>
</div>
<div class="faq-item">
<div class="faq-question">В: Я указал [width/2], но станок поехал не в центр. Почему?</div>
<div>
<p>Вероятно, вы забыли указать абсолютную систему координат. Код должен выглядеть так: <code>G90</code> (абсолютные координаты) и затем <code>G0 X[left+[width]/2]</code>.</p>
</div>
</div>
</section>
<p><!-- Заключение --></p>
<h2>Заключение</h2>
<p>Пользовательские кнопки — это «секретное оружие» опытных операторов LaserGRBL. Потратив 15 минут на их настройку, вы навсегда избавитесь от рутины и ускорите позиционирование в разы. Начните с импорта готового шаблона, а затем адаптируйте его под специфику вашего станка.</p>
<p>Данное руководство проверено и обновлено в <strong>июне 2026 года</strong>. Все упомянутые функции и переменные полностью работоспособны на актуальных сборках ПО.</p>
<div></div>The post <a href="https://www.lexium.ru/2026/06/magiya-peremennykh-g-kod-kotoryjj-podstraivaetsya-sam/">Как автоматизировать рутину: гид по пользовательским кнопкам в LaserGRBL</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2026/06/magiya-peremennykh-g-kod-kotoryjj-podstraivaetsya-sam/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Как отключить автозапуск FortiClient в Windows 10</title>
		<link>https://www.lexium.ru/2024/04/kak-otklyuchit-avtozapusk-forticlient-v-windows-10/</link>
					<comments>https://www.lexium.ru/2024/04/kak-otklyuchit-avtozapusk-forticlient-v-windows-10/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Mon, 08 Apr 2024 08:33:56 +0000</pubDate>
				<category><![CDATA[Блог]]></category>
		<category><![CDATA[Скрипты и серверы]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9849</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2024/04/photo_2024-04-08_11-33-19-200x200.jpg" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" srcset="https://www.lexium.ru/images/2024/04/photo_2024-04-08_11-33-19-200x200.jpg 200w, https://www.lexium.ru/images/2024/04/photo_2024-04-08_11-33-19-410x410.jpg 410w, https://www.lexium.ru/images/2024/04/photo_2024-04-08_11-33-19-800x800.jpg 800w, https://www.lexium.ru/images/2024/04/photo_2024-04-08_11-33-19-768x768.jpg 768w, https://www.lexium.ru/images/2024/04/photo_2024-04-08_11-33-19.jpg 1280w" sizes="auto, (max-width: 200px) 100vw, 200px" /><p>Некоторые компании, из соображений безопасности, закрывают корпоративную сеть на внешку, а потому войти туда можно только через корпоративный VPN. В качестве VPN-клиента, некоторые из них, используют FortiClient. Одной из особенностей FortiClient является его автозапуск при старте системы, который никак не отключить. Зачем вообще отключать автозапуск FortiClient? Не проще удалить приложение совсем? Проще. Но, допустим, вас перевели в другой отдел, а там используют совсем другой VPN-клиент. Однако, удалять FortiClient вы не...</p>
The post <a href="https://www.lexium.ru/2024/04/kak-otklyuchit-avtozapusk-forticlient-v-windows-10/">Как отключить автозапуск FortiClient в Windows 10</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>Некоторые компании, из соображений безопасности, закрывают корпоративную сеть на внешку, а потому войти туда можно только через корпоративный VPN. В качестве VPN-клиента, некоторые из них, используют FortiClient.</p>
<p>Одной из особенностей FortiClient является его автозапуск при старте системы, который никак не отключить.</p>
<p>Зачем вообще отключать автозапуск FortiClient? Не проще удалить приложение совсем?</p>
<p>Проще. Но, допустим, вас перевели в другой отдел, а там используют совсем другой VPN-клиент. Однако, удалять FortiClient вы не желаете, поскольку вас запросто могут перевести обратно, и вам очень не хочется заново проходить довольно непростую настройку FortiClient.</p>
<p>Чтобы всякий раз не выключать FortiClient вручную (от имени администратора), <strong>нужно всего-лишь отключить автозапуск</strong>.</p>
<div class="z">Вот только разработчики этого программного продукта не предусмотрели подобное действие. Т.е. в настройках FortiClient нет такой возможности, а в стандартном приложении Windows 10 &#8212; &#171;Автозагрузка&#187;, где можно легко выключать автостарт программ, строчка с FortiClient загадочно отсутствует.</div>
<p>Значит, придётся идти другим путём, и мы не побоимся его пройти.</p>
<div class="z"><strong>Из минусов:</strong> После отключения автозапуска, вы уже не сможете запустить FortiClient. Т.е. это, по сути, такая альтернатива удалению FortiClient, чтобы не терять доступы. Хотя, в конце поста я расскажу как реанимировать FortiClient, если он снова понадобился.</div>
<h2>Способ отключения автозапуска FortiClient, во всей красе и всего из пяти пунктов</h2>
<p><strong>Шаг 1.</strong> Щелкните правой кнопкой мыши значок FortiClient на панели задач и выберите Shutdown FortiClient (т.е. отключите его).&nbsp;</p>
<p><strong>Шаг 2.</strong> Перейдите в командную строку (под администратором), введите: net stop fortishield и прожмите ENTER.</p>
<pre class="pre"><code class="dl-code">net stop fortishield</code></pre>
<p><strong>Шаг 3.</strong> Прожмите горячие клавиши Win-R (запустится приложение &#171;Выполнить&#187;), введите в текстовое поле msconfig, прожмите ОК.</p>
<p><a href="https://www.lexium.ru/images/2024/04/2024-04-08_11-10-18.png" data-rel="lightbox-image-0" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9851 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2024/04/2024-04-08_11-10-18.png" alt="" width="424" height="205"></a></p>
<p>Откроется приложение &#171;Конфигурация системы&#187;. В ней нужно перейти во вкладку Службы (Services), снять флажок на FortiClient Service Scheduler и прожать кнопку &#171;Применить&#187;.</p>
<p><a href="https://www.lexium.ru/images/2024/04/2024-04-08_11-11-24.png" data-rel="lightbox-image-1" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9850 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2024/04/2024-04-08_11-11-24.png" alt="" width="567" height="382"></a></p>
<div class="w">В этом месте компьютер перезагружать не нужно!</div>
<p><strong>Шаг 4.</strong> Перейдите в Пуск и напишите там &#171;Службы&#187; (имеется в виду поиск). В результатах поиска вижу вот это.</p>
<p><a href="https://www.lexium.ru/images/2024/04/2024-04-08_11-15-11.png" data-rel="lightbox-image-2" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9853 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2024/04/2024-04-08_11-15-11.png" alt="" width="368" height="157"></a></p>
<p>Кликаю и открываю приложение &#171;Службы&#187;.</p>
<p><a href="https://www.lexium.ru/images/2024/04/2024-04-08_11-17-06.png" data-rel="lightbox-image-3" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-large wp-image-9852 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2024/04/2024-04-08_11-17-06-800x235.png" alt="" width="800" height="235"></a></p>
<p>В приложении найдите строку FortiClient Service Scheduler. Щелкните правой кнопкой мыши по данной строке, выберите пункт &#171;Свойства&#187;, измените тип запуска на: &#171;Ручной&#187;.</p>
<p><strong>Шаг 5.</strong> Перезагрузите компьютер.</p>
<p>Всё. FortiClient перестал стартовать вместе с системой.</p>
<div class="donate_tea"><a class="donate_tea_button" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Помогло? Зашли админу на чай с печеньками</a></p>
<div class="top10_wrapper">
<div class="track">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB</div>
</div>
<p><a class="donate_tea_button thanckyou_w" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Большое спасибо!</a></div>
<p>Как и говорилось выше, при попытке старта FortiClient вручную, он будет ругаться вот таким окном.</p>
<p><a href="https://www.lexium.ru/images/2024/04/2024-04-08_11-22-48.png" data-rel="lightbox-image-4" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9854 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2024/04/2024-04-08_11-22-48.png" alt="" width="352" height="144"></a></p>
<div class="comment">При этом, совершенно не важно запускаете ли вы его от имени администратора или нет.</div>
<p>Если всё-таки <strong>нужно стартовать</strong> то вам достаточно <strong>повторить</strong> шаги 2 и 3.</p>
<p>Только <strong>в шаге 2</strong> нужно использовать вот такую команду. Она запустит отключенную службу.</p>
<pre class="pre"><code class="dl-code">net start fortishield</code></pre>
<p>А <strong>в шаге 3</strong> не снимать флажок, а наоборот, <strong>проставить его обратно</strong>. И прожать &#171;Применить&#187;.</p>
<p>Перезагрузка системы, в моём случае не потребовалась. FortiClient запустился без проблем.&nbsp;Вроде ничего сложного.</p>
<p style="text-align: right;"><em><strong>А с вами был Доктор Лексиум.</strong></em><br />
<em><strong>До новых постов.</strong></em></p>
<div></div>The post <a href="https://www.lexium.ru/2024/04/kak-otklyuchit-avtozapusk-forticlient-v-windows-10/">Как отключить автозапуск FortiClient в Windows 10</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2024/04/kak-otklyuchit-avtozapusk-forticlient-v-windows-10/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Как поставить паузу в дебагере ГуглХрома?</title>
		<link>https://www.lexium.ru/2023/10/kak-postavit-pauzu-v-debagere-guglkhroma/</link>
					<comments>https://www.lexium.ru/2023/10/kak-postavit-pauzu-v-debagere-guglkhroma/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Sun, 15 Oct 2023 12:06:26 +0000</pubDate>
				<category><![CDATA[Автотесты]]></category>
		<category><![CDATA[Блог]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9829</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2023/10/c974d875e0004aa98cd0bfb5908bec24_fuse_4439945_0-200x200.jpg" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" srcset="https://www.lexium.ru/images/2023/10/c974d875e0004aa98cd0bfb5908bec24_fuse_4439945_0-200x200.jpg 200w, https://www.lexium.ru/images/2023/10/c974d875e0004aa98cd0bfb5908bec24_fuse_4439945_0-410x410.jpg 410w, https://www.lexium.ru/images/2023/10/c974d875e0004aa98cd0bfb5908bec24_fuse_4439945_0-800x800.jpg 800w, https://www.lexium.ru/images/2023/10/c974d875e0004aa98cd0bfb5908bec24_fuse_4439945_0-768x768.jpg 768w, https://www.lexium.ru/images/2023/10/c974d875e0004aa98cd0bfb5908bec24_fuse_4439945_0.jpg 1024w" sizes="auto, (max-width: 200px) 100vw, 200px" /><p>Зачем нужно делать паузу в панели отладки браузера Гугл Хром или Яндекс? В ходе написания автотеста мне время от времени нужно добывать селекторы из кода веб-страницы. Отличным инструментом для этого является дебагер (DevTools). Она-же &#8212; инструменты разработчика. Это на редкость удобный инструмент, необходимый для веб-разработчика, но не только. Однажды я столкнулся с сайтом, у которого, при нажатии на поле селектора появлялось модальное окно, где можно было выбрать нужный вариант. И...</p>
The post <a href="https://www.lexium.ru/2023/10/kak-postavit-pauzu-v-debagere-guglkhroma/">Как поставить паузу в дебагере ГуглХрома?</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<h2><strong>Зачем нужно делать паузу в панели отладки браузера Гугл Хром или Яндекс?</strong></h2>
<p>В ходе написания автотеста мне время от времени нужно добывать селекторы из кода веб-страницы. Отличным инструментом для этого является дебагер (DevTools). Она-же &#8212; инструменты разработчика.</p>
<div class="comment">Тот самый DevTools, который вызывается нажатием клавиши F12.</div>
<p>Это на редкость удобный инструмент, необходимый для веб-разработчика, но не только.</p>
<p>Однажды я столкнулся с сайтом, у которого, при нажатии на поле селектора появлялось модальное окно, где можно было выбрать нужный вариант. И всё-бы ничего, но с этим возникла проблема.</p>
<p>Дело в том, что если на выбранном варианте нажать левую кнопку мыши (ЛКМ), то нужный пункт выбирается, как и задумано авторами. Однако, при нажатии на правую кнопку (или на любое другое действие) модальное окно просто исчезало.</p>
<div class="comment">И ладно-бы только это! Оно исчезало из DOM&#8217;а! Полностью! Навсегда! Пока снова не ткнёшь в поле.</div>
<p>Таким образом, чтобы понять из каких селекторов состояло это модальное окно, нужно было запаузить содержимое страницы в тот момент, когда оно появилось.</p>
<h2>Как это сделать?</h2>
<p>В интернете описано множество способов, но я для себя написал вот этот короткий скрипт.</p>
<pre class="pre"><code class="dl-code">document.addEventListener('keyup',function(event){if(event.key=='F9'){setTimeout(()=&gt;{debugger;},3000);}});</code></pre>
<p>Чтобы им воспользоваться, достаточно скопировать, перейти на нужный сайт, запустить панель отладки (F12), выбрать в ней вкладку Консоль.</p>
<p><a href="https://www.lexium.ru/images/2023/10/2023-10-15_14-51-20.png" data-rel="lightbox-image-0" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9834 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2023/10/2023-10-15_14-51-20.png" alt="" width="538" height="141"></a>&nbsp;</p>
<p>В консоль вписать фразу &#171;allow pasting&#187; (естественно, без кавычек) и прожать Enter.</p>
<pre class="pre"><code class="dl-code">allow pasting</code></pre>
<p><em>Иначе консоль ГуглоХрома откажется принимать вставку скрипта.</em></p>
<p><a href="https://www.lexium.ru/images/2023/10/2024-02-09_13-00-29.png" data-rel="lightbox-image-1" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9842 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2023/10/2024-02-09_13-00-29.png" alt="" width="511" height="87"></a></p>
<p>После этого вставьте код скрипта в консоль и прожмите Enter.</p>
<p><a href="https://www.lexium.ru/images/2023/10/2023-10-15_14-51-40.png" data-rel="lightbox-image-2" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9833 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2023/10/2023-10-15_14-51-40.png" alt="" width="543" height="132"></a></p>
<div class="comment">Всё! Главное дело сделано.</div>
<p>Теперь, будучи на странице сайта, прожимаем F9 и, в течение трёх секунд (пока на сработала пауза), нажимаем на тот элемент, который вызывает нужное модальное окно.</p>
<p><a href="https://www.lexium.ru/images/2023/10/2023-10-15_14-52-52.png" data-rel="lightbox-image-3" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9831 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2023/10/2023-10-15_14-52-52.png" alt="" width="609" height="646"></a></p>
<p>Там появится характерная плашка, через которую паузу можно будет снять.</p>
<p>Из минусов: страница становится недоступной для того, чтобы прямо на ней выделить нужный элемент и посмотреть его в дебагере. Однако, можно перейти во вкладку Elements и искать нужное прямо там.</p>
<p><a href="https://www.lexium.ru/images/2023/10/2023-10-15_15-02-06.png" data-rel="lightbox-image-4" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-large wp-image-9835 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2023/10/2023-10-15_15-02-06-800x290.png" alt="" width="800" height="290"></a></p>
<p>Это не очень удобно, но вполне реально.</p>
<p>Ну а после снятия с паузы можно снова прожать F9, ткнуть уже в другой элемент (вызывающий очередную &#171;исчезающую модалку&#187;), снова дождаться паузы и найти искомые элементы.</p>
<p><a href="https://www.lexium.ru/images/2023/10/2023-10-15_15-04-20.png" data-rel="lightbox-image-5" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9836 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2023/10/2023-10-15_15-04-20.png" alt="" width="508" height="377"></a></p>
<p>Я проверил, у меня работает. Во всяком случае пока.</p>
<div class="donate_tea"><a class="donate_tea_button" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Помогло? Зашли админу на чай с печеньками</a></p>
<div class="top10_wrapper">
<div class="track">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB</div>
</div>
<p><a class="donate_tea_button thanckyou_w" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Большое спасибо!</a></div>
<p>Если тебе был полезен этот пост, пожалуйста поддержи автора.</p>
<p style="text-align: right;"><em><strong>Ну а с вами был Доктор Лексиум.</strong></em><br />
<em><strong>До новых постов.</strong></em></p>
<div></div>The post <a href="https://www.lexium.ru/2023/10/kak-postavit-pauzu-v-debagere-guglkhroma/">Как поставить паузу в дебагере ГуглХрома?</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2023/10/kak-postavit-pauzu-v-debagere-guglkhroma/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Как запустить в Windows несколько экземпляров автотеста одновременно?</title>
		<link>https://www.lexium.ru/2023/06/kak-zapustit-v-windows-neskolko-ehkzemplyarov-avtotesta-odnovremenno/</link>
					<comments>https://www.lexium.ru/2023/06/kak-zapustit-v-windows-neskolko-ehkzemplyarov-avtotesta-odnovremenno/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Mon, 26 Jun 2023 10:12:11 +0000</pubDate>
				<category><![CDATA[Автотесты]]></category>
		<category><![CDATA[Блог]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9785</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2023/06/photo_2023-06-26_13-10-16-200x200.jpg" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" srcset="https://www.lexium.ru/images/2023/06/photo_2023-06-26_13-10-16-200x200.jpg 200w, https://www.lexium.ru/images/2023/06/photo_2023-06-26_13-10-16-410x410.jpg 410w, https://www.lexium.ru/images/2023/06/photo_2023-06-26_13-10-16-800x800.jpg 800w, https://www.lexium.ru/images/2023/06/photo_2023-06-26_13-10-16-768x768.jpg 768w, https://www.lexium.ru/images/2023/06/photo_2023-06-26_13-10-16.jpg 1280w" sizes="auto, (max-width: 200px) 100vw, 200px" /><p>Возникла гипотеза о том, что один из багов на моём стенде возникает из за одновременных попыток авторизации сразу нескольких автотестов. Как проверить? Можно открыть несколько вкладок браузера в режиме инкогнито, открыть в каждом по сайту и попытаться одновременно залогиниться. Но у такого подхода есть два минуса. Во-первых, настройки теста меняют поведение браузера. Так что ручной запуск может быть неинформативным (хотя с этого я и начал). Во-вторых, ну сколько вкладок можно...</p>
The post <a href="https://www.lexium.ru/2023/06/kak-zapustit-v-windows-neskolko-ehkzemplyarov-avtotesta-odnovremenno/">Как запустить в Windows несколько экземпляров автотеста одновременно?</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>Возникла гипотеза о том, что один из багов на моём стенде возникает из за одновременных попыток авторизации сразу нескольких автотестов.</p>
<p><strong>Как проверить?</strong></p>
<p>Можно открыть несколько вкладок браузера в режиме инкогнито, открыть в каждом по сайту и попытаться одновременно залогиниться. Но у такого подхода есть два минуса.</p>
<ul>
<li>Во-первых, настройки теста меняют поведение браузера. Так что ручной запуск может быть неинформативным (хотя с этого я и начал).</li>
<li>Во-вторых, ну сколько вкладок можно запустить таким образом. Две? Три? А если хочу сразу 10?</li>
</ul>
<p>Я работаю из под Windows 10, а потому следующим этапом стало создание двух cmd-файлов.</p>
<p><a name="cross1"></a><accontent index="1">Первый &#8212; запускает один автотест. Вот его примерный текст.</p>
<p><strong>starter.cmd</strong></p>
<pre class="pre"><code class="dl-code">cd C:\pyproject\
venv\Scripts\pytest.exe \tests\test_auth.py
pause</code></pre>
<ul>
<li>Первая строка переходит в папку проекта.</li>
<li>Вторая &#8212; запускает нужный мне автотест.</li>
<li>Третья &#8212; ставит паузу, чтобы окно не захлопнулось сразу после окончания теста. Это на всякий случай.</li>
</ul>
<p>Второй файл &#8212; запускает заданное количество экземпляров первого файла.</p>
<p><strong>multistarter.cmd</strong></p>
<pre class="pre"><code class="dl-code">cd C:\pyproject\
set x=0
:A
set /a x=%x%+1
start starter.cmd
if not %x%==10 goto :A</code></pre>
<p>В первой строке мы переходим в папку проекта (где лежит starter.cmd). В последней &#8212; задано количество одновременно запущенных экземпляров starter.cmd</p>
<p>Всё. Теперь запускаю <strong>multistarter.cmd</strong> и наслаждаюсь процессом.</accontent></p>
<div class="donate_tea"><a class="donate_tea_button" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Помогло? Зашли админу на чай с печеньками</a></p>
<div class="top10_wrapper">
<div class="track">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB</div>
</div>
<p><a class="donate_tea_button thanckyou_w" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Большое спасибо!</a></div>
<p>Вместо C:\pyproject\ можно указать путь к папке, где лежат оба ваши cmd-файла.<br />
Вместо venv\Scripts\pytest.exe \tests\crowd_mos_ru\ideas\test_proverka_predlozhit_ideju.py &#8212; любую другую программу, которую нужно запустить в нескольких экземплярах.</p>
<p>Все экземпляры автотеста авторизовались и отработали без ошибок. Баг не подтвердился.<br />
А что если один из автотестов использует логаут? Пошёл копать код в поисках подобной неприятности.</p>
<p style="text-align: right;"><strong><em>А с вами был Доктор Лексиум. До новых постов.</em></strong></p>
<div></div>The post <a href="https://www.lexium.ru/2023/06/kak-zapustit-v-windows-neskolko-ehkzemplyarov-avtotesta-odnovremenno/">Как запустить в Windows несколько экземпляров автотеста одновременно?</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2023/06/kak-zapustit-v-windows-neskolko-ehkzemplyarov-avtotesta-odnovremenno/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Открыть xls файл в соседней вкладке, передав туда данные методом post</title>
		<link>https://www.lexium.ru/2023/01/otkryt-fajjl-v-sosednejj-vkladke-peredav-tuda-dannye-metodom-post/</link>
					<comments>https://www.lexium.ru/2023/01/otkryt-fajjl-v-sosednejj-vkladke-peredav-tuda-dannye-metodom-post/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Tue, 31 Jan 2023 19:43:51 +0000</pubDate>
				<category><![CDATA[Блог]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9769</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2023/01/2023-01-31_23-37-40-200x200.png" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" /><p>Имеется задача. Нужно получить выборку товаров на сайте (это просто), отметить галочкой нужные, а затем по нажатию кнопки скачать прайс-лист с выбранными товарами в формате xls. Превратить php-скрипт в xls легко. По сути php файл прикинется файлом xls. Осталось только передать ему ID нужных товаров. И вот в этом получается затык. Есть ajax. С его помощью можно передать данные серверному скрипту и получить от него ответ. Однако с его помощью...</p>
The post <a href="https://www.lexium.ru/2023/01/otkryt-fajjl-v-sosednejj-vkladke-peredav-tuda-dannye-metodom-post/">Открыть xls файл в соседней вкладке, передав туда данные методом post</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>Имеется задача. Нужно получить выборку товаров на сайте (это просто), отметить галочкой нужные, а затем по нажатию кнопки скачать прайс-лист с выбранными товарами в формате xls.</p>
<p>Превратить php-скрипт в xls легко.</p>
<pre class="pre"><code class="dl-code">&lt;? //Генерация xls-файла
header ( &quot;Expires: Mon, 1 Apr 1974 05:00:00 GMT&quot; );
header ( &quot;Last-Modified: &quot; . gmdate(&quot;D,d M YH:i:s&quot;) . &quot; GMT&quot; );
header ( &quot;Cache-Control: no-cache, must-revalidate&quot; );
header ( &quot;Pragma: no-cache&quot; );
header ( &quot;Content-type: application/vnd.ms-excel;charset=UTF-8;&quot; );
header ( &quot;Content-Disposition: attachment; filename=items_export.xls&quot; );
?&gt;&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//RU&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;ru&quot; lang=&quot;ru&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;meta name=&quot;author&quot; content=&quot;none&quot; /&gt;
&lt;title&gt;Demo&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table&gt;&lt;tr&gt;&lt;th&gt;Заголовок&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Содержимое&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>По сути php файл прикинется файлом xls.</p>
<p>Осталось только передать ему ID нужных товаров. И вот в этом получается затык.</p>
<p>Есть ajax. С его помощью можно передать данные серверному скрипту и получить от него ответ. Однако с его помощью нельзя получить файл и открыть его в соседней вкладке. И тогда на помощь приходит костыль.</p>
<p>Создаём скрытую форму со скрытым текстовым полем. Прописываем в тэге form путь к php-скрипту и его открытие в соседней вкладке.</p>
<pre class="pre"><code class="dl-code">&lt;form id=&quot;item_ids_form&quot; method=&quot;POST&quot; target=&quot;_blank&quot; action=&quot;/php_scripts/xls/&quot;&gt;
&lt;textarea style=&quot;display:none;&quot; id=&quot;item_ids_container&quot; name=&quot;item_ids&quot;&gt;&lt;/textarea&gt;
&lt;/form&gt;</code></pre>
<p>Делаем js-скрипт, который при работе с выборкой (при снятии/простановке галочек) будет добавлять ID в textarea нашей скрытой формы (через запятую).</p>
<div class="comment">Код js-скрипта приводить не буду, поскольку в каждой конкретной ситуации он будет отличаться.</div>
<p>Создаём кнопку получения прайс-листа, по которой эта форма будет отправляться.</p>
<pre class="pre"><code class="dl-code">&lt;p&gt;&lt;button id=&quot;button_price&quot;&gt;Получить прайс&lt;/button&gt;&lt;/p&gt;</code></pre>
<p>Раз кнопка вне формы (поскольку форма скрыта), то пропишем для неё обработчик на js.</p>
<pre class="pre"><code class="dl-code">$(&#039;#button_price&#039;).on(&#039;click&#039;, function(e){
e.preventDefault();
$(&quot;#item_ids_form&quot;).submit();
return false;
});</code></pre>
<div class="z">Впрочем, обработчик делать не обязательно, ведь скрыть можно не всю форму, а только поле (textarea). Тогда кнопку размещаем непосредственно в форме и отправка данных произойдёт по клику, без дополнительного js. Кнопка должна быть тэгом button, или input (с параметром type=&#8217;submit&#8217;)</div>
<p>Получается, в html-форма умеет отправить данные на страницу, которая откроется в соседнюю вкладке.</p>
<div class="donate_tea"><a class="donate_tea_button" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Помогло? Зашли админу на чай с печеньками</a></p>
<div class="top10_wrapper">
<div class="track">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB</div>
</div>
<p><a class="donate_tea_button thanckyou_w" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Большое спасибо!</a></div>
<p>Почему было не сделать такую возможность для ajax, для меня загадка. Всего-то пару параметров добавить. Видимо не настолько часто приходится реализовывать подобное, чтобы ради этого драконить ajax.</p>
<div></div>The post <a href="https://www.lexium.ru/2023/01/otkryt-fajjl-v-sosednejj-vkladke-peredav-tuda-dannye-metodom-post/">Открыть xls файл в соседней вкладке, передав туда данные методом post</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2023/01/otkryt-fajjl-v-sosednejj-vkladke-peredav-tuda-dannye-metodom-post/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PyTest: Решение проблемы с кириллицей в отчётах</title>
		<link>https://www.lexium.ru/2022/10/pytest-reshenie-problemy-s-kirillicejj-v-otchjotakh/</link>
					<comments>https://www.lexium.ru/2022/10/pytest-reshenie-problemy-s-kirillicejj-v-otchjotakh/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Fri, 21 Oct 2022 09:32:25 +0000</pubDate>
				<category><![CDATA[Автотесты]]></category>
		<category><![CDATA[Блог]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9752</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2022/10/2022-10-21_12-30-35-200x200.png" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" /><p>Уже который день меня выбешивает одна проблема. Суть вот в чём. Имеется автотест на PyTest, для проверки сайдбара на одном сайте. Алгоритм прост: Открываю сайт, Авторизуюсь, Перехожу на первую попавшуюся страницу, В сайдбаре страницы открываю вертикальное выпадающее меню и кликаю на один из пунктов (берётся из массива), На открывшихся страницах проверяю сайдбар на наличие меню, на возможность свернуть-развернуть, на всплывающие подсказки, на ширину и прочее-прочее. И всё вроде было нормально,...</p>
The post <a href="https://www.lexium.ru/2022/10/pytest-reshenie-problemy-s-kirillicejj-v-otchjotakh/">PyTest: Решение проблемы с кириллицей в отчётах</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>Уже который день меня выбешивает одна проблема. Суть вот в чём. Имеется автотест на PyTest, для проверки сайдбара на одном сайте.</p>
<p>Алгоритм прост:</p>
<ol>
<li>Открываю сайт,</li>
<li>Авторизуюсь,</li>
<li>Перехожу на первую попавшуюся страницу,</li>
<li>В сайдбаре страницы открываю вертикальное выпадающее меню и кликаю на один из пунктов (берётся из массива),</li>
<li>На открывшихся страницах проверяю сайдбар на наличие меню, на возможность свернуть-развернуть, на всплывающие подсказки, на ширину и прочее-прочее.</li>
</ol>
<p>И всё вроде было нормально, когда эти действия шли в обычном цикле for. Однако, у цикла был жирный минус, который всё портил.</p>
<p>Представь, что один из пунктов меню пропал. Или на одной из страниц сайдбар оказался битый. В этом месте цикла тест падал и остальные пункты меню уже не проверялись.</p>
<p>Было найдено более корректное решение &#8212; параметризованный тест. Массив такому тесту передаётся в виде параметра и тест запускается до тех пор, пока не пройдёт массив до конца.</p>
<p>Т.е. по сути это тот же цикл, но каждая итерация в нём &#8212; отдельный тест, с отдельным результатом выполнения. Таким образом я вижу в каких разделах сайта не всё в порядке с сайдбаром.</p>
<p>Вот кусок кода с примером.</p>
<pre class="pre"><code class="dl-code">items_text = [&quot;текст 1&quot;, &quot;текст 2&quot;, &quot;текст 3&quot;]
@allure.feature(&#039;Функциональное тестирование&#039;)
@pytest.mark.parametrize(&quot;item_text&quot;, items_text)
@allure.story(&quot;Общие функции сайдбара в разделе&quot;)
def test_sidebar_in(pages, item_text):
    page = SidebarElements(pages.browser)
    with allure_step(f&quot;Шаг 5: Проверка сайдбара в разделе &#039;{item_text}&#039;&quot;):
        print(f&quot; Раздел: &#039;{item_text}&#039;&quot;)
        ................</code></pre>
<p>Вот тут и появилась новая проблема. Дело в том, что параметры из массива PyTest отображает в отчёте. А поскольку пункты меню на русском, он заменяет кириллицу на эскейп-последовательности. Получаются совершенно неинформативные строки. И это раздражает всякий раз.</p>
<p><a href="https://www.lexium.ru/images/2022/10/2022-10-21_11-54-59.png" data-rel="lightbox-image-0" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9753 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/10/2022-10-21_11-54-59.png" alt="" width="368" height="129"></a></p>
<p>Слышал, что в PyTest 2.9 такой проблемы не было, но начиная с 3.0 &#8212; появилась.</p>
<p>Я кучу времени угрохал на то, чтобы найти решение. Баг известный, и достаточно давно, но в сети не попадалось ничего кроме стенаний пользователей. Решение нашёл мой коллега.</p>
<p>Устранить проблему PyTest с отображением кириллицы в отчётах оказалось достаточно легко, если знать как.</p>
<h2>Как исправить отображение кириллицы в отчётах PyTest?</h2>
<ul>
<li>В корень проекта кладём файлик pytest.ini</li>
<li>В фале пишем вот такой текст:</li>
</ul>
<pre class="pre"><code class="dl-code">[pytest]
disable_test_id_escaping_and_forfeit_all_rights_to_community_support = true</code></pre>
<p><a href="https://www.lexium.ru/images/2022/10/2022-10-21_12-03-09.png" data-rel="lightbox-image-1" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-large wp-image-9754 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/10/2022-10-21_12-03-09-800x365.png" alt="" width="800" height="365"></a></p>
<div class="w">Внимание, на скрине выше пропущен символ &#171;_&#187; в &#171;_all_rights_&#187;.</div>
<ul>
<li>Сохраняем.</li>
<li>??????</li>
<li>PROFIT!</li>
</ul>
<p>Вот так отчёт выглядит теперь.</p>
<p><a href="https://www.lexium.ru/images/2022/10/2022-10-21_12-17-10.png" data-rel="lightbox-image-2" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9758 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/10/2022-10-21_12-17-10.png" alt="" width="399" height="169"></a></p>
<p>Совсем другое дело. И в ходе выполнения теста текущие шаги тоже корректно отображают кириллицу.</p>
<div class="donate_tea"><a class="donate_tea_button" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Помогло? Зашли админу на чай с печеньками</a></p>
<div class="top10_wrapper">
<div class="track">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB</div>
</div>
<p><a class="donate_tea_button thanckyou_w" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Большое спасибо!</a></div>
<p>Флаг &#171;disable_test_id_escaping_and_forfeit_all_rights_to_community_support&#187; экспериментальный, но работает уже несколько месяцев. Т.е. типа временный, но прижился вроде-как.</p>
<p style="text-align: right;"><strong><em>А с вами был Доктор Лексиум.</em></strong><br />
<strong><em>До новых постов.))</em></strong></p>
<div></div>The post <a href="https://www.lexium.ru/2022/10/pytest-reshenie-problemy-s-kirillicejj-v-otchjotakh/">PyTest: Решение проблемы с кириллицей в отчётах</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2022/10/pytest-reshenie-problemy-s-kirillicejj-v-otchjotakh/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Как выделить текст на странице с помощью Python Selenium</title>
		<link>https://www.lexium.ru/2022/05/kak-vydelit-tekst-na-stranice-s-pomoshhyu-python-selenium/</link>
					<comments>https://www.lexium.ru/2022/05/kak-vydelit-tekst-na-stranice-s-pomoshhyu-python-selenium/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Thu, 26 May 2022 15:16:43 +0000</pubDate>
				<category><![CDATA[Автотесты]]></category>
		<category><![CDATA[Блог]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9746</guid>

					<description><![CDATA[<img width="200" height="200" src="https://www.lexium.ru/images/2022/05/wp-16535781798859147832351016779712-200x200.jpg" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" srcset="https://www.lexium.ru/images/2022/05/wp-16535781798859147832351016779712-200x200.jpg 200w, https://www.lexium.ru/images/2022/05/wp-16535781798859147832351016779712-410x410.jpg 410w, https://www.lexium.ru/images/2022/05/wp-16535781798859147832351016779712-800x800.jpg 800w, https://www.lexium.ru/images/2022/05/wp-16535781798859147832351016779712-768x768.jpg 768w, https://www.lexium.ru/images/2022/05/wp-16535781798859147832351016779712.jpg 1000w" sizes="auto, (max-width: 200px) 100vw, 200px" /><p>Автоматизирую тест-кейс с помощью Python Selenium. Дохожу до очередного шага, а там написано &#171;Проверка копирования названия отчетов&#187; и скриншот, где виден выделенный заголовок. Т.е. кто-то навёл мышку на начало заголовка, зажал правую кнопку, дотянул до конца заголовка, и отпустил. А теперь, нужно это дело повторить, чтобы убедиться, что текст можно выделить. Я потратил несколько часов, чтобы реализовать данный шаг. Чего только не делал. В итоге, получилась вот такая функция, на...</p>
The post <a href="https://www.lexium.ru/2022/05/kak-vydelit-tekst-na-stranice-s-pomoshhyu-python-selenium/">Как выделить текст на странице с помощью Python Selenium</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>Автоматизирую тест-кейс с помощью Python Selenium. Дохожу до очередного шага, а там написано &#171;Проверка копирования названия отчетов&#187; и скриншот, где виден выделенный заголовок.</p>
<p>Т.е. кто-то навёл мышку на начало заголовка, зажал правую кнопку, дотянул до конца заголовка, и отпустил. А теперь, нужно это дело повторить, чтобы убедиться, что текст можно выделить.</p>
<p>Я потратил несколько часов, чтобы реализовать данный шаг. Чего только не делал. В итоге, получилась вот такая функция, на базе запуска js.</p>
<pre class="pre"><code class="dl-code">def select_string_by_css(self, css_selector):
    script1 = f&quot;var rttt = document.createRange();&quot; \
              f&quot;rttt.selectNode(document.querySelector(&#039;{css_selector}&#039;));&quot; \
              f&quot;document.getSelection().removeAllRanges();&quot; \
              f&quot;document.getSelection().addRange(rttt);&quot;
    script2 = f&quot;return document.getSelection().toString();&quot;
    self.browser.driver.execute_script(script1)
    return str(self.browser.driver.execute_script(script2)).split(&quot;\n&quot;)[0]</code></pre>
<p>Функция принимает на вход css-селектор элемента, где находится заголовок, а возвращает содержимое выделения.</p>
<p>В ходе тестов выяснилось, что на выход иногда попадают переносы строк и даже какие-то фрагменты текста из соседних областей. Пришлось обрезать по значку переноса строк.</p>
<p>Код выкладываю как есть. Поскольку функция является методом класса, там присутствует self.<br />
self.browser.driver &#8212; это объект Webdriver.</p>
<p>А вот и сам js. Вытащил его с какого-то сайта и добавил чуть-чуть отсебятины.</p>
<pre class="pre"><code class="dl-code">var rttt = document.createRange();
var css_selector = &quot;h1&quot;;
rttt.selectNode(document.querySelector(&#039;{css_selector}&#039;));
document.getSelection().removeAllRanges();
document.getSelection().addRange(rttt);
var result = document.getSelection().toString();</code></pre>
<p>Таким образом, селектор будет в переменной css_selector, а результат (в нашем случае &#8212; выделенный текст) &#8212; в переменной result.</p>
<div class="donate_tea"><a class="donate_tea_button" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Помогло? Зашли админу на чай с печеньками</a></p>
<div class="top10_wrapper">
<div class="track">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB</div>
</div>
<p><a class="donate_tea_button thanckyou_w" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Большое спасибо!</a></div>
<p>Оставляю здесь, чтобы снова не искать долго-долго-долго.</p>
<p style="text-align: right;"><em><strong>С вами был Доктор Лексиум.</strong></em><br />
<em><strong>Всего доброго.</strong></em></p>
<div></div>The post <a href="https://www.lexium.ru/2022/05/kak-vydelit-tekst-na-stranice-s-pomoshhyu-python-selenium/">Как выделить текст на странице с помощью Python Selenium</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2022/05/kak-vydelit-tekst-na-stranice-s-pomoshhyu-python-selenium/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Как одновременно открыть несколько браузеров Яндекс с разными профилями под Windows?</title>
		<link>https://www.lexium.ru/2022/04/kak-odnovremenno-otkryt-neskolko-brauzerov-yandeks-s-raznymi-profilyami-pod-windows/</link>
					<comments>https://www.lexium.ru/2022/04/kak-odnovremenno-otkryt-neskolko-brauzerov-yandeks-s-raznymi-profilyami-pod-windows/#respond</comments>
		
		<dc:creator><![CDATA[Doctor Lexium]]></dc:creator>
		<pubDate>Thu, 07 Apr 2022 11:25:30 +0000</pubDate>
				<category><![CDATA[Блог]]></category>
		<category><![CDATA[Скрипты и серверы]]></category>
		<guid isPermaLink="false">https://www.lexium.ru/?p=9730</guid>

					<description><![CDATA[<img width="199" height="200" src="https://www.lexium.ru/images/2022/04/2022-04-07_14-25-04.png" class="attachment-thumbnail size-thumbnail wp-post-image" alt="" style="float:left; margin:0 10px 10px 0;" decoding="async" loading="lazy" /><p>Для начала вопрос: Зачем вообще нужно одновременно открывать несколько браузеров Яндекс с разными профилями под Windows? Если ты рядовой пользователь, который ходит в интернет что-нибудь почитать или посмотреть, то тебе это не нужно от слова &#171;почти совсем&#187;. Однако, ситуации бывают разные. Например, ты хочешь разделить работу и отдых. Т.е. в одном браузере у тебя открыт Гугл, где ты авторизован под неким логином. Там у тебя открыты определённые вкладки и стоят...</p>
The post <a href="https://www.lexium.ru/2022/04/kak-odnovremenno-otkryt-neskolko-brauzerov-yandeks-s-raznymi-profilyami-pod-windows/">Как одновременно открыть несколько браузеров Яндекс с разными профилями под Windows?</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></description>
										<content:encoded><![CDATA[<p>Для начала вопрос: <strong>Зачем вообще нужно одновременно открывать несколько браузеров Яндекс с разными профилями под Windows?</strong></p>
<p>Если ты рядовой пользователь, который ходит в интернет что-нибудь почитать или посмотреть, то тебе это не нужно от слова &#171;почти совсем&#187;. Однако, ситуации бывают разные. Например, ты хочешь разделить работу и отдых.</p>
<p>Т.е. в одном браузере у тебя открыт Гугл, где ты авторизован под неким логином. Там у тебя открыты определённые вкладки и стоят какие-то плагины.</p>
<p>А теперь, ты хочешь открыть в соседнем окне другой браузер, где в Гугле ты авторизован под другим пользователем, там другие вкладки, другие плагины и т.д.</p>
<div class="comment">Согласись, что в подобном случае удобно иметь на рабочем столе два ярлыка: Работа и Отдых, соответственно.</div>
<p>Теперь давай рассмотрим, Как одновременно открыть несколько браузеров Яндекс с разными профилями под Windows?</p>
<p><strong>1. Для начала, понадобится скачать и установить Яндекс.Браузер. </strong></p>
<p>Для этого нужно открыть yandex.ru и написать там &#171;яндекс браузер скачать&#187;, перейти по полученной ссылке и.. Ну ты понимаешь.</p>
<div class="comment">Это элементарный шаг, а потому не буду останавливаться на нём подробно.</div>
<p><a href="https://www.lexium.ru/images/2022/04/2022-04-07_14-06-31.png" data-rel="lightbox-image-0" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9731 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/04/2022-04-07_14-06-31.png" alt="" width="117" height="99"></a></p>
<p>Итак, браузер установлен. На рабочем столе даже появился характерный ярлык.</p>
<p><strong>2. Создаём папки для профилей. Их будет два: job и rest.</strong></p>
<p>Тут тоже всё просто. Переходим на диск <strong>C:</strong> и создаём там папку <strong>Browsers</strong>. Открываем её и уже в ней создаём папки <strong>job</strong> и <strong>rest</strong>.</p>
<p><strong>3. Делаем копию ярлыка Yandex на рабочем столе.</strong></p>
<p>Для этого клацаем по нему правой кнопкой мыши. В контекстном меню (которое выпало при клике) выбираем <strong>&#171;Копировать&#187;</strong>.</p>
<p>Потом, клацаем правой кнопкой мыши на пустом месте рабочего стола и в контекстном меню жмём <strong>&#171;Вставить&#187;</strong>.</p>
<p><a href="https://www.lexium.ru/images/2022/04/2022-04-07_14-09-48.png" data-rel="lightbox-image-1" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9732 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/04/2022-04-07_14-09-48.png" alt="" width="103" height="105"></a></p>
<p>Если всё сделано правильно, у нас появится копия этого ярлыка. Переименуйте его в <strong>Job</strong>. Повторите процедуру и новую копию переименуйте в <strong>Rest</strong>.</p>
<div class="comment">Копий можно сделать столько, сколько профилей вам нужно. Названия, соответственно, тоже можно делать любые.</div>
<p><strong>4. Вносим изменения в ярлык.</strong></p>
<p>Кликаем правой кнопкой мыши по ярлыку Job и в выпадающем меню выбираем <strong>&#171;Свойства&#187;</strong>.</p>
<p><a href="https://www.lexium.ru/images/2022/04/2022-04-07_14-12-04.png" data-rel="lightbox-image-2" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-medium wp-image-9733 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/04/2022-04-07_14-12-04-410x173.png" alt="" width="410" height="173"></a></p>
<p>В появившемся окне нас интересует поле <strong>&#171;Объект&#187;</strong>.&nbsp;</p>
<p><a href="https://www.lexium.ru/images/2022/04/2022-04-07_14-14-23.png" data-rel="lightbox-image-3" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-medium wp-image-9734 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/04/2022-04-07_14-14-23-410x522.png" alt="" width="410" height="522"></a></p>
<p>Кликаем по полю, переходим в конец строки и (через пробел) добавляем туда вот это:</p>
<pre class="pre"><code class="dl-code">--user-data-dir=&quot;C:\Browsers\job&quot;</code></pre>
<p>Жмём кнопку &#171;Применить&#187;. Ярлык готов.</p>
<p>Кликаем по нему, выполняем требования браузера и вот рабочая версия готова.</p>
<p>Ту же процедуру проводим для отдыхательной версии. Только указываем другую папку для хранения профиля и прочих данных.</p>
<pre class="pre"><code class="dl-code">--user-data-dir=&quot;C:\Browsers\rest&quot;</code></pre>
<p>В нашем случае, это папка <strong>rest</strong> (которую мы создали в шаге 2).</p>
<p>Ничего сложного. Теперь, кликнув сначала на один ярлык, а затем на другой мы одновременно открываем несколько браузеров Яндекс с разными профилями.</p>
<div class="comment">По крайней мере на Windows 10 это работает. У меня.</div>
<p>А на этом всё.</p>
<p><strong>(UPDATE 04.05.2022):</strong> Как выяснилось немного позднее, яндекс-браузер умеет переписывать ярлыки.<em> Не спрашивай зачем.</em> Поэтому, перед тем как сохранить ярлык (или открыв его свойства), следует проставить галочку в чекбоксе &#171;Только чтение&#187; во вкладке &#171;Общие&#187;.</p>
<p><a href="https://www.lexium.ru/images/2022/04/2022-05-04_13-10-58.png" data-rel="lightbox-image-4" data-rl_title="" data-rl_caption="" title=""><img loading="lazy" decoding="async" class="size-full wp-image-9741 aligncenter" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" sleepsrc="https://www.lexium.ru/images/2022/04/2022-05-04_13-10-58.png" alt="" width="369" height="38"></a></p>
<p>Это должно помочь.</p>
<div class="donate_tea"><a class="donate_tea_button" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Помогло? Зашли админу на чай с печеньками</a></p>
<div class="top10_wrapper">
<div class="track">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Евгений С &#8212; 1 300 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stand Alone &#8212; 500 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Вадим Ворон &#8212; 216 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vyazik &#8212; 50 RUB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vitor &#8212; 50 RUB</div>
</div>
<p><a class="donate_tea_button thanckyou_w" href="https://www.donationalerts.com/r/alexcube" rel="nofollow" target="_blank" title="Зашли админу на чай с печеньками">Большое спасибо!</a></div>
<p>Если этот пост был полезен, буду рад вашему пожертвованию на печеньки к чаю.</p>
<p style="text-align: right;"><em><strong>А с вами был Доктор Лексиум.</strong></em><br />
<em><strong>Всего доброго.</strong></em></p>
<div></div>The post <a href="https://www.lexium.ru/2022/04/kak-odnovremenno-otkryt-neskolko-brauzerov-yandeks-s-raznymi-profilyami-pod-windows/">Как одновременно открыть несколько браузеров Яндекс с разными профилями под Windows?</a> first appeared on <a href="https://www.lexium.ru">Доктор Лексиум</a>.]]></content:encoded>
					
					<wfw:commentRss>https://www.lexium.ru/2022/04/kak-odnovremenno-otkryt-neskolko-brauzerov-yandeks-s-raznymi-profilyami-pod-windows/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
