Немного смущает, что даются ссылки на платную программу WinRar (она ведь еще платная, не?), но это мелочи. Самый прикол в приложении к письму: размер приложения 536Kb, внутри платежка размером 127Kb и спам картинка на 410kb. Потратить 75% размера на рекламу — это гениально, я считаю. К тексту письма претензий нет, приведу его здесь целиком:
Уважаемый абонент!
Петербургский филиал ОАО «Ростелеком» высылает счет/комплект платежных документов по E-mail за апрель 2013 года.
Рекомендации:
1. Если полученный файл (Attachments.zip) не удается открыть при просмотре почтового ящика, сохраните его на компьютер и затем откройте.
2. Если при выводе на печать из программы Adobe Reader (http://get.adobe.com/reader/) документ невозможно прочитать (символы вместо букв), то необходимо воспользоваться альтернативной программой просмотра PDF-файлов Foxit Reader (http://www.foxitsoftware.com/downloads/).
3. Для открытия архива и просмотра документов рекомендуем использовать следующие программы:
— для распаковки архива программу WinRar версия 3.30 и выше или аналоги (например 7-zip).
— для просмотра документов Adobe Reader версия 8.0 и выше или Foxit Reader4. Необходимые программы можно скачать по адресам:
Win Rar — http://www.win-rar.ru/download/winrar/
7-zip — http://7-zip.org.ua/ru/
Adobe Reader — http://get.adobe.com/reader/
Foxit Reader http://www.foxitsoftware.com/downloads/Если Вы не получите наше письмо в 1-ой декаде месяца, проверьте папку Нежелательная почта (СПАМ).
Мы рады сотрудничеству с Вами!
Данное письмо сформировано программным модулем и не требует ответа.
Если указанные выше рекомендации не позволили Вам открыть вложение, обращайтесь по тел. 8-118-88.
В целом, остался доволен. Наконец-то наступил XXI век в отдельно взятом гос. учреждении..
Совет сотрудникам, которые добавляют рекламу в платежку — если сохранять такую картинку сразу в PNG формат, то размер будет меньше.
UPD: прислали новую платежку за сентябрь. Сложно сказать есть ли прогресс: платежка теперь в формате PDF (это плюс), реклама теперь с разрешением 2482×3508 и размером 950Kb (это минус).
Допустим, есть задача: создать поток, который скачивает что-то из интернета, а из основного потока ему валятся задания. Стандартный путь реализации такой:
class DownloadThread extends Thread { public interface Listener { void onImageLoaded(Image image); } private String reqUrl_ = null; private final Listener listener_; private boolean isFinished_ = false; DownloadThread(Listener listener) { listener_ = listener; } public void imageRequest(String url) { synchronized (this) { // Запрос на загрузку изображения reqUrl_ = url; } } @Override public void run() { while (!isFinished_) String url = null; synchronized (this) { // Проверка: есть ли запрос? if (null != reqUrl_) { url = reqUrl_; reqUrl_ = null; } } if (null != url) { // Запрос есть, загружаем изображение Image image = download(url); listener_.onImageLoaded(image); } try { // Поспим одну милисекунду, чтоб не грузить CPU sleep(1); } catch (InterruptedException e) { isFinished_ = true; break; } } } public void stopThread() { isFinished_ = true; } } |
Почему этот плохой, негодный пример? Потому что, когда заданий много, между ними одна миллисекунда бездействия минимум — это во-первых. Во-вторых, если задач для потока нет, то он работает без всякой пользы, создавая лишнюю нагрузку процессору.
Рассмотрим пример номер два:
class DownloadThread extends Thread { public interface Listener { void onImageLoaded(Image image); } private String reqUrl_ = null; private final Listener listener_; private boolean isFinished_ = false; DownloadThread(Listener listener) { listener_ = listener; } public void imageRequest(String url) { synchronized (this) { // Запрос на загрузку изображения reqUrl_ = url; // Уведомляем поток, что есть задание notify(); } } @Override public void run() { while (!isFinished_) String url = null; synchronized (this) { if (isFinished_) { break; } // Проверка: есть ли запрос? if (null != reqUrl_) { url = reqUrl_; reqUrl_ = null; } else { try { // Ждем вызова notify wait(); } catch (InterruptedException e) { isFinished_ = true; break; } } } if (null != url) { // Запрос есть, загружаем изображение Image image = download(url); listener_.onImageLoaded(image); } } } public void stopThread() { synchronized (this) { isFinished_ = true; notify(); } } } |
Почему этот пример лучше первого? Во-первых, когда заданий нет, поток находится в режиме ожидания без вызовов sleep()
. Во-вторых, когда задание приходит, поток реагирует моментально просыпаясь.
Обратите внимание, что метод stopThread()
слегка изменился. Ввиду того, что поток не выйдет из состояния wait()
без вызова notify()
.
UPD: По совету друзей исправил метод run()
для корректного завершения потока.
В обоих примерах не учитывается, что изображения нам нужны пачкой сразу, то есть очередь запросов выкинута для упрощения кода.
P.S. Кстати, в C/C++ для тех же целей можно использовать pthread_cond_wait()
и pthread_cond_signal()
В продолжение темы кватерниона…
Итак, есть матрица 4×4, где три оси ортогональны друг другу (по-нашенски, по-деревенски — это означает, что три оси перпендикулярны каждая с каждой, представьте оси прямоугольной системы координат, так вот это оно и есть).
Выглядит матрица вот так:
В ней, как я уже рассказывал, «живут» три вектора ABC (ось X), EFG (ось Y), IJK (ось Z). Также есть три смещения вдоль XYZ — это M, N и O соответственно.
Для того, чтобы извлечь вектор и угол из этой матрицы я использую вот такую конструкцию (псевдокод):
def getAngleAxis(m): xx = m[A] yy = m[F] zz = m[K] # Сумма элементов главной диагонали traceR = xx + yy + zz # Угол поворота theta = acos((traceR - 1) * 0.5) # Упростим вычисление каждого элемента вектора omegaPreCalc = 1.0 / (2 * sin(theta)) # Вычисляем вектор w.x = omegaPreCalc * (m[J] - m[G]) w.y = omegaPreCalc * (m[C] - m[I]) w.z = omegaPreCalc * (m[E] - m[B]) # Получаем угол поворота и ось, # относительно которой был поворот return (theta, w) |
Мне довелось применять этот метод на матрице, где вектора ABC, EFG и IJK нормализованы. Масштаб хранится отдельно. Если вы храните масштаб внутри матрицы, то перед применением формулы надо нормализовать вектора ABC, EFG и IJK).