четверг, 6 декабря 2018 г.

Google-таблицы: вставка изображения в ячейку

Оказывается, в Google-таблицах есть такая прикольная функция, как =IMAGE(url).
Она позволяет внутрь ячейки внедрить изображение, причём это изображение может масштабироваться по мере изменения размера ячейки. Единственная проблема: как запихнуть туда изображение не из интернета, а, скажем, с рабочего стола.

Оказывается, есть способ. Нужно:

а) Положить изображение на Google-диск.

б) Дать этому изображению доступ всем пользователям по ссылке. При этом получится некий урл примерно такого вида:
https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvw/view?usp=sharing
в нем ценность представляет ключ 1234567890abcdefghijklmnopqrstuvw.

в) Этот ключ вставить в новый урл:
http://drive.google.com/uc?id=1234567890abcdefghijklmnopqrstuvw

г) И уже этот урл скормить функции IMAGE:
=IMAGE("http://drive.google.com/uc?id=1234567890abcdefghijklmnopqrstuvw")

Литература:

Insert an image from Drive in a cell on google sheets - How To

суббота, 18 августа 2018 г.

Debian: ошибка в работе жесткого диска Seagate

Посыпался WD Caviar Green 1.5Tb. Не такой уж старый - девять лет всего - а вот поди ж ты. Ну, посыпался - и бог с ним, говорят, это у них часто бывает. Пришлось купить на замену Seagate 2Tb IronWolf. Пять месяцев отработал без нареканий, а потом началось. Бывает, смотришь, а точка монтирования пустая - диск отвалился. В логах (по команде dmesg) высыпается такой набор:
[549201.794807] Buffer I/O error on device sdd1, logical block 225329999
[549201.794811] EXT4-fs warning (device sdd1): ext4_end_bio:250: I/O error -5 writing to inode 37618358 (offset 45134135296 size 49152 starting block 225330256)
[549201.801653] EXT4-fs error (device sdd1): ext4_journal_start_sb:327: Detected aborted journal
[549201.801659] EXT4-fs (sdd1): Remounting filesystem read-only
[549201.801662] EXT4-fs (sdd1): previous I/O error to superblock detected
[549201.801673] EXT4-fs (sdd1): ext4_da_writepages: jbd2_start: 9223372036854775807 pages, ino 37618358; err -30
[549201.805986] sd 5:0:0:0: [sdd] Synchronizing SCSI cache
[549202.047724] ata6: SATA link down (SStatus 0 SControl 310)
[549202.047732] ata6.00: link offline, clearing class 1 to NONE
[549202.047740] ata6: EH complete
[549202.047782] sd 5:0:0:0: [sdd]  Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
[549202.047786] sd 5:0:0:0: [sdd] Stopping disk
[549202.047794] sd 5:0:0:0: [sdd] START_STOP FAILED
[549202.047796] sd 5:0:0:0: [sdd]  Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
[549202.066818] ata6: exception Emask 0x10 SAct 0x0 SErr 0x4040000 action 0xe frozen
[549202.066823] ata6: irq_stat 0x00000040, connection status changed
[549202.066826] ata6: SError: { CommWake DevExch }
[549202.066836] ata6: limiting SATA link speed to 1.5 Gbps
[549202.066840] ata6: hard resetting link
[549202.843166] ata6: SATA link down (SStatus 0 SControl 310)
[549202.843174] ata6.00: link offline, clearing class 1 to NONE
[549202.843182] ata6: EH complete
[549202.865848] ata6: exception Emask 0x10 SAct 0x0 SErr 0x4040000 action 0xe frozen
[549202.865853] ata6: irq_stat 0x00000040, connection status changed
[549202.865857] ata6: SError: { CommWake DevExch }
[549202.865866] ata6: limiting SATA link speed to 1.5 Gbps
[549202.865869] ata6: hard resetting link
[549203.642603] ata6: SATA link down (SStatus 0 SControl 310)
[549203.642611] ata6.00: link offline, clearing class 1 to NONE
[549203.642619] ata6: EH complete
Что к чему - непонятно. Диск вроде живой, перемонтируешь его или комп перезагрузишь - и опять работает. Наконец, ошибки стали появляться слишком часто, поэтому полез гуглить.

Знающие люди говорят, что, возможно, это потому что диск - sata3, а материнская плата - sata. Т.е., у сигейта такие хитрые настройки или таймауты, что линукс считает, что диск отвалился, и выдает ошибку. Понятных мне варианта решения два: заменить диск или прописать в /etc/default/grub такую опцию:
GRUB_CMDLINE_LINUX="libata.force=1.5Gbps"
и выполнить команду update-grub.

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

UPD 2018-08-28: Не помогло. Следующий вариант - отключить кэширование записи на диск:
hdparm -W0 /dev/sdd
Куда деваться, попробую его. Попутно узнал команды lspci (показывает контроллеры) и hdparm -I /dev/sdd (показывает много всякой интересной информации о диске).

UPD 2019-07-24: Как-то этот костыль худо-бедно работал, а сегодня пришлось отключить компьютер на пару часов, и... И обратно система не поднялась - завалила экран ошибками диска на этапе загрузки. С испугу купил новый диск, и тут выяснилось, что новый, хоть и другая модель, но ведёт себя точно так же. Помогло перетыкание питания - просто один пучок проводков, идущий от БП, заменил на другой. Так что, возможно, все эти ошибки - результат того, что что-то неладно с питанием. Похоже, не диски надо было мучить, а элементарно поставить новый блок питания.

Литература

Disk IO errors on all sata disks, disks dropped out
Ubuntu Freeze Issue After SSD Upgrade
[ubuntu] Problems with the new Seagate 1.5TB hard drives

понедельник, 13 августа 2018 г.

Отключить HSTS

Оказывается, есть на свете такой механизм: HSTS (HTTP Strict Transport Security). Эта штука препятствует работе с сервером, сертификат которого не удовлетворяет определенным требованиям безопасности, однако, иногда такая забота мешает жить.

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

Чтобы браузер забыл настройки HSTS для сайта, нужно:

а) в Google Chrome перейти по ссылке chrome://net-internals/#hsts, в разделе Delete domain ввести адрес сайта и нажать кнопку Delete.

б) в Mozilla FireFox зайти в журнал просмотренных страниц, на нужном адресе правым кликом мыши вызвать контекстное меню, в котором выбрать последний пункт "Забыть об этом сайте".

Литература
Here’s how to disable HSTS settings in Chrome & Firefox

понедельник, 6 августа 2018 г.

Для взлома шифра Цезаря

S = "Кгылчусеюегм ефб лрчсупгщлб"

S = S.upper()

chars = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"
for i in range(0, len(chars)):
    print(i, "".join(chars[(chars.find(s) + i)%len(chars)] if chars.find(s) >= 0 else s for s in S))

можно было, конечно, и так:
for i in range(0, 33):
    print("".join(chr(ord('А')+(ord(s)-ord('А')+i)%(ord('Я')-ord('А')+1)) if ord(s) in range(ord('А'),ord('Я')+1) else s for s in S))
но вдруг набор символов слегка отличается от привычного?

пятница, 3 августа 2018 г.

Windows 7: повторно подключить к домену

Одна рабочая станция под управлением Windows 7 начала при попытке авторизоваться выдавать следующее: "База данных диспетчера учетных записей на сервере не содержит записи для регистрации компьютера через доверительные отношения с этой рабочей станцией". Оказалось, что какой-то злодей снёс учетную запись компьютера в Active Directory. Ситуация осложнилась тем, что доменными политиками отключена учетная запись локального администратора.

К счастью, удалось прицепиться под доменной админской учетной записью (один из админов когда-то входил в этот компьютер за какой-то своей надобностью, и локальный профиль сохранился). Дальше поступили как в случае с Windows XP. Единственная тонкость: команду netdom remove пришлось выполнить с ключом /Force, чтобы рабочая станция осознала, что она уже не в домене.
netdom remove myWS /Domain:myDOMAIN /UserD:myDOMAIN\Admin /PasswordD:*** /Force
netdom join myWS /Domain:myDOMAIN /UserD:myDOMAIN\Admin /PasswordD:***

среда, 30 мая 2018 г.

C# и CLI

Задался вопросом: как компилировать программы на C# не имея установленных средств разработки типа Visual Studio или там Sharp Develop. Ну просто и компьютер слабоват, и вообще... Выяснилось, что можно - соответствующие компиляторы и утилиты штатно поставляются вместе с .NET Framework - но, конечно, не так комфортно, как во всех этих WYSIWYG редакторах.

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

Кроме того, есть существенная особенность - всё происходит под Windows XP с установленным на ней .NET Framework v3.5. Итак, приступим.

1. Простейшее консольное приложение
Файл Program.cs
using System;  

class HelloWorld  
{  
    static void Main()  
    {  
        Console.WriteLine("Привет, мир!");  
    }  
}  
как оказалось, без проблем компилируется командой:
C:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe  Program.cs
Причем компилятор каким-то чудесным образом корректно обрабатывает русские буквы, при этом автоматически определяя кодировку исходного файла.

2. Если приложение посложнее, то знающие люди советуют не пользоваться компилятором напрямую ввиду обилия разнообразных опций, которые потребуется выставить, а использовать утилиту MS Build. Утилита берёт настройки из файла *.csproj, так что проект дополняется ещё одним файлом:
Файл project.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project  DefaultTargets="Rebuild"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">  

 <PropertyGroup>

  <!-- имя сборки -->
  <AssemblyName>main</AssemblyName>  

  <!-- в какую папку будет компилироваться сборка -->
  <OutputPath>bin\</OutputPath>  

 </PropertyGroup>  


 <ItemGroup>  
  <Compile Include="Program.cs" />  
 </ItemGroup>  


 <Target Name="Clean">  
  <Delete Files="$(OutputPath)$(AssemblyName).exe" Condition="Exists('$(OutputPath)')" />  
 </Target>  

 <Target Name="Build">  

  <!-- если папка, в которую будет компилироваться проект, не существует, создаём её -->
  <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />  

  <!-- компилируем сборку -->
  <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />

 </Target>

 <Target Name="Rebuild" DependsOnTargets="Clean;Build" /> 

</Project>
и собирается следующей командой:
C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe  project.csproj
Тут уже можно задавать некую структуру проекта, например, создавать отдельную папку для результата компиляции. Кстати, если присмотреться, секции <Target> идеологически сильно напоминают правила линуксовой утилиты make.

3. Но пришло время перейти к оконным приложениям. Поскольку за кулисами оконного интерфейса скрывается экземпляр класса System.Windows.Forms.Application, то изменяем файл Program.cs - теперь там этот самый экземпляр будет создаваться и вводиться в работу:
Файл Program.cs
using System;
using System.Windows.Forms;

namespace myProject
{
 static class Program
 {
  /// <summary>
  /// Точка входа в программу
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   Application.Run(new MainForm());
  }
 }
}
Кроме того, теперь требуется описать окно нашего приложения. В Visual Studio его описание разбито на несколько файлов, и нужно согласиться, что это достаточно удобно - вся рутина, посвященная созданию окна и расположенных на нем компонентов, вынесена в отдельный файл *.Designer.cs. Мы последуем этому примеру и создадим наши два файла для описания главного окна:
Файл MainForm.cs
using System;
using System.Windows.Forms;

namespace myProject
{
 public partial class MainForm : Form
 {
  public MainForm()
  {
   InitializeComponent();
  }
 }
}
Файл MainForm.Designer.cs
namespace myProject
{
 partial class MainForm
 {
  private void InitializeComponent()
  {
   System.Windows.Forms.Button button1 = new System.Windows.Forms.Button();

   button1.Location = new System.Drawing.Point(8, 8);
   button1.Name = "button1";
   button1.Size = new System.Drawing.Size(75, 23);
   button1.TabIndex = 0;
   button1.Text = "Кнопка";

   this.Controls.Add(button1);
  }
 }
}
Кроме того, изменения, очевидно, коснутся файла проекта - теперь он будет выглядеть так:
Файл project.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project  DefaultTargets="Rebuild"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">  

 <PropertyGroup>

  <!-- имя сборки -->
  <AssemblyName>main</AssemblyName>  

  <!-- в какую папку будет компилироваться сборка -->
  <OutputPath>bin\</OutputPath>  

 </PropertyGroup>  


 <ItemGroup>  

  <Compile Include="Program.cs" />

  <!-- главное окно программы -->
  <Compile Include="MainForm.Designer.cs" />
  <Compile Include="MainForm.cs" />

 </ItemGroup>


 <Target Name="Clean">  
  <Delete Files="$(OutputPath)$(AssemblyName).exe" Condition="Exists('$(OutputPath)')" />  
 </Target>  

 <Target Name="Build">  

  <!-- если папка, в которую будет компилироваться проект, не существует, создаём её -->
  <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />  

  <!-- компилируем сборку -->
  <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />

 </Target>

 <Target Name="Rebuild" DependsOnTargets="Clean;Build" /> 

</Project>

4. Как видим, всё хорошо, но описать форму можно удобнее. Воспользуемся таким инструментом, как XAML. Для этого заменяем файл Program.cs на его эквивалент:
Файл Program.xaml
<?xml version="1.0" encoding="utf-8"?>
<Application x:Class="myProject.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml">
</Application>
и заменяем файлы с описанием главного окна программы (MainForm.Designer.cs и MainForm.cs) на вот такие:
Файл MainWindow.xaml
<?xml version="1.0" encoding="utf-8"?>
<Window x:Class="myProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Тестовое окно"
 Height="300"
 Width="400"
 >
    <Grid>
        <Button Height="35" Margin="8,8,8,8" Name="button1" VerticalAlignment="Top">Test</Button>
    </Grid>
</Window>
Файл MainWindow.xaml.cs
using System;
using System.Windows;

namespace myProject
{
 /// <summary>
 /// Логика работы окна MainWindow.xaml
 /// </summary>
 public partial class MainWindow : Window
 {
  public MainWindow()
  {
   InitializeComponent();
  }
 }
}
Эти изменения, разумеется, найдут своё отражение в файле проекта:
Файл project.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project  xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">  

 <PropertyGroup>

  <!-- имя сборки -->
  <AssemblyName>main</AssemblyName>  

  <!-- в какую папку будет компилироваться сборка -->
  <OutputPath>bin\</OutputPath> 

  <OutputType>winexe</OutputType>
  <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

 </PropertyGroup>  


 <ItemGroup>

  <Reference Include="System"/>
  <Reference Include="WindowsBase"/>
  <Reference Include="PresentationCore"/>
  <Reference Include="PresentationFramework"/>

  <ApplicationDefinition Include="Program.xaml"/>

  <Page Include="MainWindow.xaml"/>
  <Compile Include="MainWindow.xaml.cs"/>

 </ItemGroup>  


 <!-- вся магия на самом деле скрыта тут -->
 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

</Project>

Таким образом, можно вполне создавать оконные приложения .NET имея под рукой только блокнот. Не скажу, что этот вариант хоть в чем-то выигрывает по сравнению с IDE, но само наличие такой возможности не может не радовать.

Литература
Walkthrough: Creating an MSBuild Project File from Scratch
MSBuild

воскресенье, 27 мая 2018 г.

Ubuntu: отключить автомонтирование

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

К счастью, говорят, это можно отключить. В редакторе настроек (вызывается командой dconf-editor) нужно найти и снять соответствующие галочки в разделе /org/gnome/desktop/media-handling. Нашел. Снял. Посмотрю, поможет ли.

Литература
Mount/USB (Ubuntu documentation, Community Help Wiki)
Tip: Using UUID for mounting disks, the convenient way

суббота, 27 января 2018 г.

Ubuntu: подключаем bluetooth-колонку

В общем, обзавёлся я bluetooth-колонкой. Ну захотелось засыпать под приятную музыку с ютуба, а компьютер стоит в другой комнате. Не дырявить же из-за такого пустяка стены! Поэтому выбор пал на bluetooth. В DNS-е прикупил Sven PS-170BL и принялся её настраивать.

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

Итак, настройка. После предыдущих экспериментов в системе остались какие-то установленные пакеты (bluez, pulseaudio-module-bluetooth), так что доустанавливать ничего не пришлось. Запустил апплет blueman-applet, включил поиск устройств, тот нашел колонку, находящуюся в режиме bluetooth, и успешно подключился. Руководство пользователя к колонке предупреждало, что, возможно, потребуется ввести пароль 0000, но это не понадобилось. Кстати, пароль тут, похоже, неизменяемый, так что надо быть готовым к тому, что какой-нибудь шутник-сосед за стеной подключится и начнет транслировать всякие непристойности.

На этом настройка не закончилась. Командой pavucontrol вызвал регулятор громкости. В нём есть вкладка "Конфигурация". В этой вкладке отображаются всякие аудиоустройства. Надо найти свой пункт "Sven PS-170BL" и выбрать профиль "Воспроизведение высокого качества (приемник A2DP)" (откуда он там взялся - это, конечно, интересный вопрос). Во вкладке "Устройства вывода" эту колонку можно сделать устройством вывода звука по умолчанию, но моя задача заключалась не в этом.
Задача у меня стояла сделать так, чтобы часть приложений пищала через интегрированную на материнку звуковую карту, а другая часть - через колонку. Сделать это оказалось просто. При запуске приложения, пытающегося вывести звук (например, firefox или mpg123), это приложение появляется в списке во вкладке "Проигрывание", и для него можно выбрать требуемое устройство вывода.

Кроме того, для mpg123 можно вообще обойтись CLI. Команда
pacmd list-sinks
выдаёт некий список примерно такого вида:
2 sink(s) available.
  * index: 0
        name: <alsa_output.pci-0000_00_07.0.analog-stereo>
        driver: <module-alsa-card.c>
        ....
        ....
    index: 7
        name: <bluez_sink.30_41_30_FA_95_57>
        driver: <module-bluez5-device.c>
        ....
        ....
        module: 33
        properties:
                bluetooth.protocol = "a2dp_sink"
                device.description = "SVEN PS-170BL"
                device.string = "30:41:30:FA:95:57"
                device.api = "bluez"
                device.class = "sound"
                device.bus = "bluetooth"
                device.form_factor = "hands-free"
                bluez.path = "/org/bluez/hci0/dev_30_41_30_FA_95_57"
                bluez.class = "0x240408"
                bluez.alias = "SVEN PS-170BL"
                device.icon_name = "audio-handsfree-bluetooth"
                device.intended_roles = "phone"
        ports:
                handsfree-output: Хендс-фри (priority 0, latency offset 0 usec, available: yes)
                        properties:
    
        active port: 
В нём нас интересует одна строка: "name: <bluez_sink.30_41_30_FA_95_57>". В домашнем каталоге создаём файл ~/.asoundrc с таким содержимым:
pcm.bluetooth {
        type pulse
        device "bluez_sink.30_41_30_FA_95_57"
}
Теперь можно вызывать mpg123 такой командой:
mpg123 -o alsa -a bluetooth мой_файл.mp3
и звук пойдёт через колонку.

Литература
https://wiki.archlinux.org/index.php/Bluetooth_headset_(Русский)
https://wiki.archlinux.org/index.php/PulseAudio_(Русский)
https://askubuntu.com/questions/609292/different-applications-different-sound-output-devices
https://askubuntu.com/questions/14077/how-can-i-change-the-default-audio-device-from-command-line
https://wiki.debian.org/Bluetooth/Alsa

вторник, 9 января 2018 г.

Windows: полезный список CLSID

А может, и бесполезный. Но пусть будет:

::{d20ea4e1-3957-11d2-a40b-0c5020524153} Administrative Tools  
::{85bbd920-42a0-1069-a2e4-08002b30309d} Briefcase  
::{21ec2020-3aea-1069-a2dd-08002b30309d} Control Panel  
::{d20ea4e1-3957-11d2-a40b-0c5020524152} Fonts  
::{ff393560-c2a7-11cf-bff4-444553540000} History  
::{00020d75-0000-0000-c000-000000000046} Inbox  
::{00028b00-0000-0000-c000-000000000046} Microsoft Network  
::{20d04fe0-3aea-1069-a2d8-08002b30309d} My Computer 
::{450d8fba-ad25-11d0-98a8-0800361b1103} My Documents 
::{208d2c60-3aea-1069-a2d7-08002b30309d} My Network Places 
::{1f4de370-d627-11d1-ba4f-00a0c91eedba} Network Computers 
::{7007acc7-3202-11d1-aad2-00805fc1270e} Network Connections 
::{2227a280-3aea-1069-a2de-08002b30309d} Printers and Faxes 
::{7be9d83c-a729-4d97-b5a7-1b7313c39e0a} Programs Folder  
::{645ff040-5081-101b-9f08-00aa002f954e} Recycle Bin 
::{e211b736-43fd-11d1-9efb-0000f8757fcd} Scanners and Cameras  
::{d6277990-4c6a-11cf-8d87-00aa0060f5bf} Scheduled Tasks 
::{48e7caab-b918-4e58-a94d-505519c795dc} Start Menu Folder  
::{7bd29e00-76c1-11cf-9dd0-00a0c9034933} Temporary Internet Files  
::{bdeadf00-c265-11d0-bced-00a0c90ab50f} Web Folders

подсмотрел тут.