
Спасибо Леше, который заморочился и нагенерил CSV по данным из Википедии.
Кстати, началась весна, а я случайно обнаружил О-о-очень древнюю запись. Эмо-панк группа с характерным названием «Выхода нет». Трэк «Весна в Гонконге». Доложили, что тема петрозаводская. Не гуглил, не проверял, с авторами не связывался
Слушайте. Текст — охуенный.
Расшифровка полей данных SYNOP и METAR в формате CSV
Взято с RP5.RU, и собственно, для работы с архивами погоды оттуда и предназначается. Описание полей выдирал L.S. из кода страничек.
Кстати, не сочтите за рекламу, но, ИМХО, это самый классный погодный сайт во всем интернете, не только в рунете, а во всем вообще! Потому что единственный, где можно взять наблюдения непосредственно с нужной метеостанции. Обычно показывают ближайшую к выбранному населенному пункту, но можно, немного изъебнувшись, найти нужную по WMO ID (кто не знает, это такой уникальный типа «айпишник» конкретной станции). Единственный минус — какая-то автоматизация получения данных, только за бабки, запросами выдрать не получается, сайт заскриптован наглухо, но за бабки дают XML, который можно крутить-вертеть, как хочешь.

Возобновляем мысленный проект Димы
Итак, что такое N-ART, это типа арт-журнал, где типа эксперты выбирают типа произведения искусства для одной цели — опубликовать их на нашем сайте. Критериев отбора всего 2:
1. Нам понравилось
2. Произведение нигде не было опубликовано.
Политика участия. Можно присылать свои работы каким угодно образом, лучше всего по почте или лично, тогда мы их отсканируем (сфотографируем) и отдадим оригинал обратно (вышлем письмом).
Политика редакции. Мы не получаем с публикации денег. Если кто-то из авторов хочет деньги, то он может приписать, что ему нужен донат. Весь донат для автора будет отправлен автору. Мы не берем процентов.
На остальные заебы похуй, весь цифровой контент, попавший к нам распространяется по лицензии Хекса
Сегодня у нас произведение Длиннопанка из города К.

В первой части я показал, как просто обнаружить ошибки HTTP при работе с curl. Но на самом деле, подход, использованный в скрипте, немного неправильный:
Клиент может не знать все коды состояния, но он обязан отреагировать в соответствии с классом кода. В настоящее время выделено пять классов кодов состояния.
Т.е. объясняя по рабоче-крестьянски, не только код 200 может свидетельствовать об успешном завершении запроса, а другие коды, кроме явных клиентских или серверных ошибок, могут требовать от нас каких-либо действий.
Вообще, коды ответа HTTP разделены на 5 классов:
1xx — информационные
2xx — успешное завершение
3xx — требуется переопределение
4xx — ошибка, допущенная со стороны клиента
5xx — ошибка, допущенная со стороны сервера
Вот и модифицируем наш скрипт в соответствии со стандартом.
В общем, надо из кода ответа HTTP извлечь первую цифру, и, соответственно прореагировать. Привожу часть скрипта, ответственного за более подробную реакцию на код ответа HTTP:
curl -o $SAVEFILE $1 -D $HEADERDUMP >/dev/null 2>/dev/null
EXITCODE=$?
if [ $EXITCODE -ne 0 ]; then
echo "CURL error $EXITCODE"
else
HTTPSTATUS=`cat $HEADERDUMP|head -1|awk '{print $2}'` #get HTTP status code
HTTPSTATUSMESS=`cat $HEADERDUMP|head -1|cut -d ' ' -f 3-
HTTPSTATUSID=`echo $HTTPSTATUS|cut -c 1` #get first char status code
case "$HTTPSTATUSID" in
1 ) echo -n "Informational: ";;
2 ) echo -n "Success: ";;
3 ) echo -n "Redirection: ";;
4 ) echo -n "Client Error: ";;
5 ) echo -n "Server Error: ";;
* ) echo -n "Unknow status: ";;
esac
echo "$HTTPSTATUS $HTTPSTATUSMESS"
fi
Жирным шрифтом выделена строка, в которой мы получаем этот самый класс кода возврата.
Курсивом — строка, где мы получаем пояснения текстовые пояснения к коду ответа.
Используемая в процессе анализа утилита cut, в первом случае, позволяет нам вывести в переменную все символы после с третьего пробела.
Перед первым у нас версия протокола http, потом код ошибки, а потом пояснение, которое может содержать несколько пробелов, поэтому awk тут не подходит.
cut так же может работать с текстовыми данными, в которых есть разделители, например пробелы, или же с отдельными символами, как в той строке кода, что выделена жирным — так мы можем извлечь первую цифру из кода ответа.
Дальнейший анализ осуществляется с помощью оператора case

Расширенный анализ кодов состояния HTTP:
На Pastebin
На Github
PHP скрипт для проверки:
На Pastebin
На Github
Краткий справочник по командам curl и wget Копия
Утилита cut
Коды статуса HTTP
Оператор case
Итак, возникла следующая задача — определить, когда curl получил вменяемые данные от http-сервера, а когда нет. В общем, и самом распространенном случае, задача сводится к тому, чтобы определить, отдал ли нам сервер запрашиваемый файл, или отобразил «страница не найдена».
Впрочем, это работает и для других возможных кодов ответа.
Ясно, что сервер, на наш запрос GET может ответить, как возвратив нам запрашиваемую страницу, так и отправив код, например, 404 (не найдено), и возвратив страницу-заглушку для этого случая. Так вот, на уровне скрипта bash или скрипта php необходимо проанализировать ответ сервера, чтобы не выдать пользователю вместо ожидаемых данных, всяческую лабуду. Далее я рассматриваю исключительно консольную Linux-утилиту curl. Для php, синтаксис, по-моему, отличается.
Есть страница, которую мы хотим получить: http://example.org/page.html, сохранить ее в файл page.html и есть curl, команда будет такая:
curl -o "page.html" http://example.org/page.html
Если страница на месте, то мы получим ее, и ничего анализировать не требуется.
Если же нет, то от большинства web-серверов мы получим страницу-заглушку, например такую, но никакой ошибки при этом.
Как же быть:
Проверяем код ошибки самого curl, если нет связи с сетью, URL неправильный, или задан неподдерживаемый curl протокол, если так, то мы получим соответствующий код возврата, наподобие:
curl: (1) Protocol htt not supported or disabled in libcurl
А вот если адрес правильный, и никакой ошибки в адресе или соединении нет, то код возврата не сработает, нам самим придется думать дальше.
Надо получить код ответа HTTP!
Сделать это можно, если получить отдельно заголовки ответа сервера, и после их проанализировать. Благо, для этого никакого страшного колдунства не требуется, достаточно указать утилите curl опцию -D (т.е. dump) и файл, куда выгружать заголовки.
Покажу это на примере конкретного скрипта:
#!/bin/bash
HEADERDUMP="/tmp/headerdump.txt"
SAVEFILE="/tmp/httpfile"
HTTPSTATUS=""
curl -o $SAVEFILE $1 -D $HEADERDUMP >/dev/null 2>/dev/null
EXITCODE=$?
if [ $EXITCODE -ne 0 ]; then
echo "CURL error $EXITCODE"
else
HTTPSTATUS=`cat $HEADERDUMP|head -1|awk '{print $2}'`
if [ "$HTTPSTATUS" == "200" ];then
echo "OK"
else
echo "HTTP error $HTTPSTATUS"
fi
fi
заводим 3 переменные
HEADERDUMP="/tmp/headerdump.txt" — файл, в который будем получать заголовки
SAVEFILE="/tmp/httpfile" — файл с сервера, который мы хотим получить
HTTPSTATUS="" — переменная для статуса (состояния) HTTP
curl -o $SAVEFILE $1 -D $HEADERDUM
пытаемся скачать нужный файл (получить страницу):
-o «имя_файла» — куда сохранять результат
$1 — внутренняя переменная, первый параметр скрипта, при вызове его с командной строки. В своем скрипте надо заменить на свой случай.
можно добавить >/dev/null 2>/dev/null — для красоты, чтоб не вылезали сообщения о процессе и ошибках.
-D <файл> — файл, куда будем копировать заголовки
Файл headerdump.txt выглядит примерно так:
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Fri, 30 Mar 2018 00:17:23 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.6.33
Link:
Set-Cookie: quick_chat_alias=Anon_240883; path=/
Upgrade: h2,h2c
Vary: Accept-Encoding,User-Agent
В первой строке — интересующая нас информация. Версия протокола (не интересно), код ответа (вот он) и информационное сообщение (не особо надо).
Вычленяем код:
HTTPSTATUS=`cat $HEADERDUMP|head -1|awk '{print $2}'`
1. Берем первую строчку (head -1)
2. Сохраняем в переменную 2-е значение после пробела (разделитель пробел): awk '{print $2}'
Дальше можно анализировать:
if [ "$HTTPSTATUS" == "200" ];then
echo "OK"
else
echo "HTTP error $HTTPSTATUS"
fi

Также, впрочем, можно поступить и для анализа запросов POST, вот тестовый скрипт php для отладки подобных возможностей и скрипт bash

Пример с запросом GET
Пример с запросом GET на Гитхаб
Пример с запросом POST
Пример с запросом POST на Гитхаб
Точнее про то, что копирайт и копирасты это говно, а копирование — не воровство.
Имеются:
— главный герой, получивший от нас (ваших товарищей из параллельного измерения) Хаопринтер, с возможностью 3D-печати и кучей дополнительных опций. Впрочем, он неплохо работает и с дефолтными настройками.
— злобный и жадный копираст, у которого бомбануло
— судья-взяточник, который, естественно, на стороне копираста
В общем, смотрите 🙂
Абсолютный размер в пикселях
По размеру DIV’а
Пример
Киберфорум
Кот из примера
Еще какие-то
L.S.
Чтобы создать путь со всеми вложенными подкаталогами, достаточно выполнить команду mkdir с ключом -p. Например:
mkdir -p ./the/test/path
создаст в текущем каталоге путь the/test/path

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

Очередное студенческое задание, да. Причем опять, то ли препод не совсем адекватный, то ли студент, то ли мы дебилы и не видим чего-то лежащего на поверхности. Потому что «совсем для всех» кодировок, поддерживаемых .NET оно не получается.
Для начала, пришлось задачу все-таки глобально поделить на 3 больших части:
— кодировки однобайтовые (Windows 1251, DOS 866 и т.д.)
— кодировка Unicode
— кодировки многобайтовые, но не Unicode (всякие там японские, китайские и прочие).
С ними проще всего. Достаточно перебрать все символы от 0 до 255, перекодировать их последовательно в UTF-16 стандартной функцией класса Encoding и вывести на экран.
Encoding enc = Encoding.GetEncoding(CP);
for (int i = 0; i < 256; i++)
{
string sChr = enc.GetString(new byte[] { (byte)i });
//...
}
Отделить их от остальных тоже просто, у объекта Encoding есть свойство IsSingleByte
С этим тоже особой сложности нет, весь стандарт открытый, можно взять список диапазонов Юникода прямо с официального сайта. Разобрать, залить в ComboBox и отображать кусками, для больших кусков сделать постраничное листание.
Главная проблема была побороть глюк с отображением символа с кодом > FFFFh Копия, из-за чего пришлось использовать RichTextBox и периодически пересчитывать ему размер в зависимости от используемого шрифта и символа, а также в нужных местах перерисовывать таблицу, чтоб та не расползалась.

Вторая проблема - изобрести какое-то подобие "композитных" шрифтов в BabelMap, т.е. подгружать разные шрифты для разных диапазонов Unicode, поскольку шрифта, абсолютно поддерживающего все символы Unicode нет, он бы получился чудовищно большим. И те, которые есть-то, не маленькие, из нескольких файлов, и весят под сотню мегабайт.
Чтоб ради задания не загадить систему шрифтами, пришлось предусмотреть возможность грузить их из файлов, а тут поджидал уже другой глюк, на этот раз Framework'а Копия.
В общем, процентов 90 кода (да и процессорного времени) уходит на возню со шрифтами и отрисовку таблицы.
Отделить варианты кодирования Unicode от других кодовых страниц тоже несложно, благо всего этих вариантов не так много (UTF16 LE/BE, UTF32 LE/BE, UTF8 и UTF7).
public static bool IsUnicode(int CodePage)
{
if (CodePage == 65001 ||
CodePage == 65000 ||
CodePage == 1201 ||
CodePage == 1200 ||
CodePage == 12000 ||
CodePage == 12001)
return true;
else return false;
}
А получить конкретный символ можно вот таким способом:
if ((num >= 0x00d800) && (num <= 0x00dfff))
{
st = Convert.ToString((char)num);
}
else
{
st = char.ConvertFromUtf32(num);
}
if ((num >= 0x00d800) && (num <= 0x00dfff)) - это чтобы не попасть в диапазоны суррогатов, но все-таки на их месте что-то отображать (в шрифтах там обычно пустые символы или знаки ?), а char.ConvertFromUtf32() при попадании в диапазон суррогатов свалится с ошибкой.
А вот тут уже так легко не получится, все-таки единственный вменяемый способ, это искать спецификации на каждую. Поэтому, в рамках задания, эта часть задачи была признана некорректной и не решаемой.
Нет, был, конечно, вариант простого перебора всех возможных вариантов. Максимальное количество байт, необходимых для кодирования символа в указанной кодировке можно получить с помощью Encoding.GetEncoding(cp).GetMaxByteCount(1), но перебрать все возможные значения, например, для массива размером уже в 4 байта, перебирая его, например, так, да еще и фильтруя все лишнее, непомерно долго.
В общем, вроде бы того, что сделали, оказалось достаточно.
Пришлось студенту писать пояснительную записку с источниками 🙂
Исходник примера на GitHub
Скачать
Leha S, NKT
Понадобилось грузить TTF-шрифты из файлов, что делается с помощью PrivateFontCollection.AddFontFile(FileName). И, внезапно, стал проявляться плавающий глюк, возникающий, если периодически пересоздавать объект PrivateFontCollection. Например, при попытке сделать MeasureString(Text, LoadedFont).ToSize(), программа стала вываливаться с ошибкой "Попытка чтения или записи в защищенную память".
Пишут, что это глюк Framework’а и толковое решение только одно, создавать PrivateFontCollection один раз при запуске программы, например, в каком-нибудь статическом классе, и больше ее не трогать. Т.е. подгружать новые шрифты можно, а пересоздавать коллекцию не надо.
Минус решения — можно загадить память подгружаемыми шрифтами, если подгрузить много файлов. Но лучше пока ничего не нашел.
В принципе, можно создать вот такой статический класс, который будет подгружать шрифт в коллекцию, и хранить в Dictionary сопоставление между именем файла и шрифтом в коллекции. Если файл еще не был загружен — подгружать, если был, возвращать позицию в коллекции.
Ну и чтоб два раза не вставать, класс FileFont, который заодно меняет параметры шрифта (размер и начертание).
На Cyberforum’е тоже пока ничего более дельного не предложили.
Известно, что внутренний формат строк в .NET — UTF16, что значит, что символы из основной многоязыковой плоскости (BMP) Unicode, т.е. с кодом меньше FFFF кодируются одним машинным словом, а остальные символы — двумя, одно из которых т.н. суррогат.
Так вот, как оказалось, с отображением суррогатных пар может возникнуть проблема. Контролы Windows Forms могут воспринимать символ с кодом >FFFF не как один символ, как должно быть, а как два. Для примера пробуем отобразить анатолийский иероглиф

с кодом 0x14476

Как видно, TextBox и Label воспринимают символ, как два символа, и, соответственно, его не отображают, а RichTextBox видит, что это один символ, но не отображает его, даже при правильно заданном шрифте.
MessageBox также отображает символ не как один, а как два:

Для устранения проблемы с RichTextBox достаточно задать нужный шрифт перед тем, как присвоить свойству Text нужные символы.
int Code = 0x14476; //анатолийский иероглиф
Font AnFont = new Font("Anatolian", 24, FontStyle.Regular,
GraphicsUnit.Pixel, 1);
private void Form1_Load(object sender, EventArgs e)
{
string strSP = char.ConvertFromUtf32(Code);
lblTest.Font = AnFont;
txtTest.Font = AnFont;
lblFont.Text = AnFont.FontFamily.Name;
rtbTest.Font = AnFont;
lblTest.Text = strSP;
txtTest.Text = strSP;
rtbTest.Text = strSP;
}

PictureBox также отрисовывает нужный символ без проблем:

А корень проблемы кроется не в C#, .NET и компонентах Windows Forms, а в самой Windows. Пакет обновления SP1 для Windows 7 решает проблему полностью.
Наиболее универсальным решением является использование RichTextBox для работы с такими символами, во всяком случае, это работает даже для Windows XP, для которой ждать патчей, понятное дело, не приходится.
Главное, не забывать про то, что шрифт надо задавать до вставки/присвоения символа.
Или, во всяком случае, большинство символов.
TWBh: шрифт, поддерживающий большинство символов Unicode
Дополнительно:
Композитный шрифт для BabelMap (TWBhBabelCompositeFont.xml)
Композитный шрифт для WPF (TWBh.CompositeFont)
Композитный шрифт для примера простой Charmap для Unicode и однобайтных кодировок (babel.cf)
Universalia самый распространенный максимально поддерживающий Unicode набор шрифтов Ссылка Magnet
Набор шрифтов с почти полной поддержкой Unicode, собранный неизвестным пользователем интернета Что и как поддердживает каждый файл шрифта, есть описание в тектовом файле. Плюс есть композитный шрифт для тестовой программы.
Программа BabelMap Копия
Самый совершенный Charmap для Unicode, поддерживает композитные шрифты и все диапазоны Unicode

Или будни редакции.
Главред все переживал, не выглядит ли он на «свои почти 40 лет» и не сильно ли у него «насекомная (рептильная) мордочка», несмотря на все-таки серьезность акции и вполне ответственное, как наше всехное, так и его личное отношение. Не смог побороть глупую улыбку в камеру, как мы его просили.
«Ну не могу я, когда фоткают, не улыбаться, даже на загран 7 раз фотографировали», сказал редактор.
-А как ты, сишарпер хренов, по скайпу выступаешь.
-У меня камера хреновая, там хрен чо хрен разглядишь. И сишарп вообще не гадание на Таро, там лицо видеть не обязательно.
Ктулху с ним, как получилось, так и ладно.
Нашли еще две темы. По-моему круто! Хотя мечтаю познакомить вас с их первым альбомом, на котором вполне себе панковский гражданско-оборонно-гаражный звук. Надеюсь, архивы Леши не оскудели, и в ближайшее время, таки да.