программирование
Запуск сайтов из Spotlight
Занялся потихоньку автоматизацией своих задач на «Маке».
Очень хотелось сделать так, чтобы по короткому имени, набираемому в Spotlight, открывались
Я знаю, что тут много ребят сидят на Windows, поэтому поясню. Spotlight (его аналог) есть на Windows 7 — это поисковая строка, куда можно вбить начальные буквы
В Mac OS X удобно, что это поисковое поле появляется по кнопке Ctrl+Пробел.
Написать плагин к Spotlight мне пока слабо́, а вот набросать на AppleScript программу, открывающую одноимённый сайт — пожалуйста.
Идея такова: кладу на диск одну и ту же программу в нескольких копиях, с разными именами — «wiki», «jira», «calendar» и так далее. Теперь их можно запускать откуда угодно, включая Spotlight. После запуска программа смотрит какое у неё имя, прибавляет к нему префикс/суффикс и проверяет существует ли получившийся домен, если да, то открывает его в браузере.
Программу надо сохранить при помощи редактора AppleScript (AppleScript Editor) с нужным именем (↑⌘S), формат файла должен быть «программа» («application»).
Вот сама программа (наверное маску
-- Ищет по маскам хост, подставляя имя программы,
-- если найден, открывает его в браузере
-- bolknote.ru апрель 2011
tell application "System Events"
set appname to the name of the current application
end tell
repeat with mask in {"%.yandex-team.ru", "www.%.ru", "www.%.com"}
set AppleScript's text item delimiters to "%"
set mask to text items of mask
set AppleScript's text item delimiters to appname
set hostname to "" & mask
if resolve(hostname) then
open location "http://" & hostname
exit repeat
end if
end repeat
on resolve(host)
try
do shell script "host '" & host & "'"
return true
on error
return false
end try
end resolveЭто пока мой первый опыт программирования в AppleScript, так что, возможно,
Добавлено позднее: в комментариях один из читателей предложил более простой и изящный вариант. Ура!
Вопрос про iPod Touch G1
Кто знает, подскажите, пожалуйста.
У подруги iPod Touch первого поколения. Когда был куплен (с рук, б/у), там стояла
Подруга, подключив его к iTunes, обновила прошивку до 1.1.5 (это последняя для этой модели). После обновления с него исчезли все приложения, а в iTunes теперь (не знаю был ли до этого или всё было поставлено через
Теперь вопрос — это ли способ, не делая джейлбрейк, ставить приложения на это устройство? Если нет, то чем сейчас модно делать джейлбрейк iPod’ов? Я уже попробовал ZiPhone, не получилось, выдаёт
Почему я использую «Семажик», чтобы постить в блог
Когда я писал движок своего блога (а я его именно писал, а не взял готовый, мне было интересно попробовать
Я просто реализовал протокол ЖЖ (на деле даже два — Flat и Metaweblog) и несколько лет, не зная горя, писал в блог даже с телефонов, где нет ничего, кроме J2ME.
Так что «выкинь „Семажик“ и пиши через веб» — это совет от незнания, чтобы постить через веб, нужно обеспечить такую возможность, а у меня нет времени и желания этим заниматься, мне просто не интересно.
Так что я просто потратил немного времени и нашёл себе клиент, который меня устраивает — это Phoenix. Он не такой удобный, как «Семажик», но, в целом, неплох.
Добавлено позже: не знаю как так вышло, сран… клиент, который меня устраивает, этот Phoenix удалил мне запись вместе с комментариями.
IE 10 Platform Preview 1
Microsoft уже предлагает скачать Internet Explorer 10 Platform Preview 1.
Помнится, многие рассуждали о том, что MS опять забросит свой браузер на годы. Как видите, нет, только вышел IE9, как уже можно скачать превью следующей версии.
Размер табуляции в CSS
В CSS3 есть хорошее свойство
Тем временем, свойство уже реализовано в некоторых браузерах, с собственным префиксом. Свойство первым поддержала «Опера» (с версии 10.60, именно от этой компании и было выдвинуто предложение добавить это свойство в CSS3), затем оно было реализовано в четвёртой версии FireFox. Остальные браузеры пока не подтянулись.
Вот как выглядит
body {
-o-tab-size: 4; /* размер табуляции — 4 (для Оперы 10.60+) */
-moz-tab-size: 4; /* размер табуляции — 4 (для FireFox 4+) */
-webkit-tab-size: 4; /* для будущих версий Safari и Chrome */
tab-size: 4; /* размер табуляции — 4, на будущее */
}Значение
Добавлено позднее: для WebKit уже есть патч для поддержки свойства
Uptime в Windows (на CMD)
Я заморочился и написал uptime на чистом CMD, раз уж на PowerShell уже до меня сделали. CMD — ужасный язык программирования!
Это я после Турции до программирования дорвался. Посмотреть что получилось.
@ECHO OFF
REM Евгений Степанищев //bolknote.ru 2011/04/09
REM Здесь CALL нельзя использовать, иначе хилый CMD не выдержит и лопнет —
REM подстановки переменных через %var% и !var! хватать перестанет
FOR /F "usebackq tokens=3" %%i ^
IN (`net stats srv ^| findstr /R "[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]*"`) DO SET DATE0=%%i
SET YEAR0=%DATE0:~6%
SET MONTH0=%DATE0:~3,2%
SET DAY0=%DATE0:~0,2%
SET YEAR1=%DATE:~6%
SET MONTH1=%DATE:~3,2%
SET DAY1=%DATE:~0,2%
REM Избавляемся от ведущих нулей, иначе CMD будет считать
REM числа восьмеричными
IF %DAY0:~0,1% == 0 SET DAY0=%DAY0:~1%
IF %MONTH0:~0,1% == 0 SET MONTH0=%MONTH0:~1%
IF %DAY1:~0,1% == 0 SET DAY1=%DAY1:~1%
IF %MONTH1:~0,1% == 0 SET MONTH1=%MONTH1:~1%
SET /A SUM=%DAY1%-%DAY0%
SETLOCAL ENABLEDELAYEDEXPANSION
IF %YEAR1% == %YEAR0% (
SET /A END=%MONTH1%-1
FOR /L %%M IN (%MONTH0%,1,!END!) DO (
CALL :getMonthDays %%M %YEAR0%
SET /A SUM+=!DAYS!
)
) ELSE (
REM 02.2010 -> +10 months
FOR /L %%M IN (%MONTH0%,1,12) DO (
CALL :getMonthDays %%M %YEAR0%
SET /A SUM+=!DAYS!
)
REM 02.2011 -> +2 months
FOR /L %%M IN (1,1,%MONTH1%) DO (
CALL :getMonthDays %%M %YEAR0%
SET /A SUM+=!DAYS!
)
REM Full years
SET /A START=%YEAR0%+1
SET /A STOP=%YEAR1%-1
FOR /L %%Y IN (!START!,1,!STOP!) DO (
CALL :isLeapYear %%Y
IF !FEB! == 29 (
SET /A SUM+=366
) ELSE (
SET /A SUM+=365
)
)
)
ECHO %SUM%
GOTO :EOF
REM ====== Функции ==========
REM Високосный ли год?
REM isLeapYear <год>
:isLeapYear
SET /A FEB=(%1/400)*400
IF %FEB% == %1 (
SET FEB=29
GOTO :EOF
)
SET /A FEB=(%1/100)*100
IF %FEB% == %1 (
SET FEB=28
GOTO :EOF
)
SET /A FEB=(%1/4)*4
IF %FEB% == %1 (
SET FEB=29
GOTO :EOF
)
SET FEB=28
GOTO :EOF
REM Количество дней в месяце
REM getMonthDays <месяц> <год>
:getMonthDays
CALL :isLeapYear %2
IF %1 == 2 (
SET DAYS=%FEB%
GOTO :EOF
)
IF /I %1 LSS 8 (
SET DAYS=30
SET /A DAYS+="%1&1"
) ELSE (
SET DAYS=31
SET /A DAYS-="%1&1"
)
GOTO :EOF
Uptime в Windows (на Powershell)
Написал на PowerShell скромный аналог утилиты uptime из Линукса (эта утилита показывает сколько дней компьютер работает без перезагрузки):
[math]::round(((Get-Date) - ($os=gwmi Win32_OperatingSystem).ConvertToDateTime($os.lastbootuptime)).TotalDays, 2)В основном в сети предлагается запустить «net stats srv» и посмотреть строку «статистика после» («statistics since»), впрочем и вариантов на PowerShell тоже хватает. Кстати, можно сделать ещё и такой вариант:
[math]::round(((Get-Date) - (((net stats srv)[3] -split ' ')[2,3] -join ' ' | Get-Date)).TotalDays, 2)Почти LISP.
Алиас для /etc/init.d/… restart
Устал я писать каждый раз строки вида «sudo /etc/init.d/nginx restart» для перезапуска многочисленных серверов, поэтому сделал себе короткий алиас. Я бы не упомянул об этом, если бы не два отличия.
Вот что получилось (у меня это в .bashrc):
rst () { command sudo /etc/init.d/$@ restart; }
function _rst() {
local cur
cur=${COMP_WORDS[COMP_CWORD]}
if [ 1 -eq ${COMP_CWORD} ]; then
COMPREPLY=( $(compgen -f -- /etc/init.d/$cur | xargs -n1 basename -- ) )
else
COMPREPLY=()
fi
}
complete -F _rst rstМагия гитхаба
Прочувствовал магию «Гитхаба». Я сейчас дописываю один плагин для phpBB (это популярный движок форумов), в процессе написания нашёл ошибку в плагине automod (плагин, который нужен чтобы ставить другие плагины).
Поскольку automod выложен
Авторы automod, когда увидят мой запрос, сделают merge с моей новой веткой и мои изменения помогут сделать мир лучше.
Очень просто и круто.
«Парсер» студии Лебедева и nginx
Смог запустить Парсер на nginx. Поставил
server {
listen 80;
server_name parser.internal;
set $root /var/www/parser;
root $root;
location ~ \.(p|cgi)$ {
include fastcgi_params;
fastcgi_pass unix:/var/www/cgiwrap-dispatch.sock;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param PATH_TRANSLATED $root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $root$fastcgi_script_name;
}
}SimpleCGI после запуска создаёт файловый сокет
Причём, что интересно, с SimpleCGI спокойно работает и Парсер из пакета, на который я жаловался, что он падает
Добавлено позже: если нужно указать путь до auto.p, то можно добавить «fastcgi_param CGI_PARSER_CONFIG путь/до/auto.p».
«Парсер» студии Лебедева и thttpd
Сегодня потратил часть дня, чтобы выяснить, что Парсер не заработает с thttpd.
Вообще, мне очень нравится
У меня Ubuntu 10.04, поэтому я всё поставил из пакетов, Парсер в том числе, пакет неофициальный, я его нашёл в разделе прислали пользователи.
После того как я всё настроил, ничего не заработало. Отладка через strace быстро показала, что Парсер падает. Я его перекомпилировал. Если будете перекомпилировать, вот мой рецепт.
Я поставил следующие пакеты (легко допускаю, что
В каталог
CPPFLAGS='-I/opt/pcre-8.12 -I/opt/pcre/include/' \
./configure --prefix=/opt/parser3/ --with-shared-gc --with-static-pcre=/opt/pcre
make
sudo make installПосле того как я стал пользоваться собранным мною Парсером,
Тут я догадался (поскольку в консоли не видел
Я создал небольшой
if(cgi) {
// few absolute obligatory
const char* path_info=getenv("PATH_INFO");
if(!path_info)
SAPI::die("CGI: illegal call (missing PATH_INFO)");
const char* script_name=getenv("SCRIPT_NAME");
if(!script_name)
SAPI::die("CGI: illegal call (missing SCRIPT_NAME)");
// … ещё много кода …
}При помощи CGI, написанного на bash, я выгрузил все переменные окружения, которые предоставляет thttpd (у меня версия 2.25b), оказалось, что двух последних переменных в дампе нет. Причём в интернете эта проблема уже поднималась (правда без связи с Парсером) и была успешна разрешена авторами thttpd. Наверное в последней версии
Добавлено: я
Добавлено ещё позже: так, по коду выходит следующее: если
При этом
Чтобы понимать:
http://example.org/cgi-bin/test.cgi — формируется SCRIPT_NAME, но не PATH_INFO и PATH_TRANSLATED
http://example.org/cgi-bin/test.cgi/ — формируется PATH_INFO и PATH_TRANSLATED, но не SCRIPT_NAMEИ ещё позднее: попробовал
WebDAV
Пытаюсь настроить WebDAV, чтобы им можно было пользоваться на nginx. Пока не получилось. Модуль WebDAV из nginx не умеет обрабатывать OPTIONS и PROPFIND,
Для этого я взял davserver — небольшой сервер, написанный на Пайтоне. У него два достоинства: он на Пайтоне и он есть
Выяснилось, что это плохая идея.
try:
os.system("mkdir '%s'" % path)
self._log('mkcol: Created new collection %s' % path)
return 201Кажется, они даже не заморачиваются экранированием спецсимволов в path, правда я бегло смотрел.
Пока не решил возьму ли
Чудеса с Гугл.Ридером
Добавлено позднее: неожиданно пришли комментарии. Правда не все. Видимо, Гугл лихорадит.
Перепрошил Intel WiFi 5100 ABG → ABN
Этот набор букв в заголовке означает, что благополучно перешил свой
Если вы хотите повторить мой путь, то учтите, что можно легко запортить карту, а восстановление испорченной карты дело непростое. Итак, если вы решились (я перепрошивал
Для начала вам потребуется последняя версия программы
Шаг второй — нужно выяснить адрес вашей карты. Для этого откройте диспетчер устройств и найдите там ресурсы вашей карты, как на скриншоте:
Как видно, адрес моей карты — F69FE000. Убедитесь, что правильно копируете это число. Это важно.
Скачайте скрипт, который поможет вам сдампить текущие данные вашей карты, во второй строчке этого скрипта замените «########» на адрес вашей карты.
Запустите
Скачиваете скрипт, который пропатчит вашу карту, опять же, вместо «########» нужно написать адрес вашей карты.
Снова открываете в меню «Command», в длинное текстовое поле копируете скрипт (с заменённым адресом), нажимаете «Enter», когда скрипт завершит свою работу (курсор станет обычным, а в окне под текстовым полем появится лог работы скрипта), перезагружаете компьютер.
Молитесь. В нормальном случае, Windows скажет, что обнаружено новое устройство и поставит драйвер для карты Intel 5100 ABN. Если карта пропала, то, увы,
Добавлено: тут надо пояснить почему вообще есть возможность перепрошить этот адаптер на категорию «n». Всё дело в том, что он уже поддерживает эту категорию, и на уровне железа, и на уровне прошивки. Просто эта возможность там выключена. Как я понял
Как посмотреть какие каналы WiFi используются
У Паши Катурова увидел хорошую программу под Windows, называется inSSIDer 2 (есть и под Linux, кстати), позволяет посмотреть какой канал
Если упрощённо, чем больше
Моя точка (по уровню сигнала легко понять, что я её назвал «WiMAX») работала на каналах №№1 и 5. На первом висят уже несколько точек, поэтому я переместил свою точку на третий и седьмой каналы (стоит походить по квартире, в разных участках могут быть видны различные точки).
Кстати, легко видеть, что трое моих соседей используют шифрование WEP, которое взламывается минут за 10—15 и ни одна из точек (кроме моей) не поддерживает полноскоростную категорию «n».
Добавлено: в комментариях (спасибо!) напомнили о проблеме, которую я уже успел начисто забыть: каналы WiFi перекрываются. Есть хорошая картинка, показывающая как именно они перекрыты, заодно она объясняет почему все мои соседи выбрали канал 1, 6 или 11. Руководствуясь этими данными, я выключил второй канал (всё равно устройств «n» у меня пока нет) и переставил свою точку на 13.
На закладке «2.4 GHz Channels» (это частота, на которой работают устройства категорий «b», «g» и «n»), можно визуально оценить как ваша точка использует частоты и где располагаются точки соседей. У меня сейчас картина такая:
Как видно я занимаю канал №13, который частично перекрывается с каналами 8—12, уровень сигнала моей точки у меня в квартире заметно выше соседских, кроме того, половина моего канала никем, кроме меня не занята.
При густой «населённости» правило, видимо, такое: старайтесь не делить канал с точками, которые приближаются к вашей по уровню сигнала.
Правда я ещё не до конца уверен правильно ли я сделал, что отключил второй канал у точки. Надо читать. Насколько я понимаю, мои устройства (а у меня их адово количество — 8 штук) могли раньше коннектиться по любому из двух каналов, чтобы меньше друг другу мешать.
Одно из различий Python и JavaScript
Чем дальше, тем между большим количеством языков программирования мне приходится переключаться. Одно из различий объектной модели Пайтона и ДжаваСкрипта мне портит кровь (у них парадигмы ООП вообще сильно различаются), если я вовремя не соображу, что надо переключиться с одного языка на другой.
Суть в том, что в Пайтоне метод ходит в гости со своим контекстом:
class A:
test = 'A'
def show(self): print self.test
class B: test = 'B'
a, b = A(), B()
show = a.show
b.show = a.show
show() # A
b.show() # AТогда как в JavaScript такой код будет работать совершенно иначе, там методы в чужой монастырь со своим уставом не ходят (если их не попросить):
var test = 'global';
A = function () {
this.test = 'A',
this.show = function () { alert(this.test) }
};
B = function () { this.test = 'B'; }
a = new A(); b = new B();
b.show = a.show
show = a.show
show() // global
b.show() // B
b.show.apply(a) // AПоявление «global» наверное надо разъяснить тем, кто JS знает плохо. На самом деле первая строчка (в данном случае) может читаться как «window.test = ’global’», а «show = a.show» как «window.show = a.show», тогда, должно быть, всё
Изменения в speeddial новой альфы «Оперы»
Ребята из «Оперы» экспериментируют с возможностями SpeedDial в своём браузере. Помните, я писал о специальных версиях некоторых сервисов «Яндекса» для SpeedDial?
К сожалению, «Опера» их разломала в свежей альфе, зато добавила новую возможность, которой очень нехватало: специальным заголовком
Preview-refresh: 10или
<meta http-equiv="preview-refresh" content="10" />Время указывается в секундах. Кстати, теперь можно надёжно узнать через media queries, что «Опера» показывает страницу в SpeedDial: достаточно проверить, что
Сколько есть способов восстановить chmod?
Иногда на собеседованиях спрашивают такую задачу, на соображалку: предположим вы случайно сняли права исполнения с команды chmod. Как их восстановить?
Я решил подумать сколько способов исправить эту ситуацию я знаю.
Первый способ — скопировать chmod с соседней машины при помощи scp, sshfs и т. п. Если такая машина имеется, конечно.
Способ второй:
cp /bin/sh ~/chmod2
cat /bin/chmod > ~/chmod2
sudo ~/chmod2 +x /bin/chmod
rm ~/chmod2Третий способ (при условии, что у вас
sudo apt-get --reinstall install `dpkg -S /bin/chmod | cut -f1 -d:`Способ четвёртый:
gcc -x c - <<CHMOD
#include <sys/stat.h>
main(){chmod("/bin/chmod", S_IXUSR | S_IXGRP | S_IXOTH);}
CHMOD
sudo ./a.out
rm a.outКто ещё знает способы?
Пайтон: замкнувшее замыкание
Есть немало вещей, которые мне не нравятся в Пайтоне. Не так давно мы на работе наткнулись ещё на одну.
У нас есть код, который выглядит примерно так (можно написать и одну функцию, но так нагляднее):
def outer(useless = None):
def inner():
if useless is None:
print "Pichal'ka"
return inner
outer()()Ничего необычного, одна функция определяется внутри другой, использует переменную используя переменную из внешней функции. Всё логично, всё работает.
Теперь меняем код:
def outer(useless = None):
def inner():
if useless is None:
print "Pichal'ka"
# тут много кода, начало мы уже потеряли
if False: useless = None
return inner
outer()()Запускаем код и видим (Пайтон 2.6.5):
Traceback (most recent call last):
File "sample.py", line 10, in <module>
outer()()
File "sample.py", line 3, in inner
if useless is None:
UnboundLocalError: local variable 'useless' referenced before assignmentКакими бы благородными мотивами не руководствовались создатели Пайтона, мне такое поведение не нравится. Вдруг я забыл как переменная попадает в функцию, присвоил ей
Избавиться от эффекта можно, изменив прототип внутренней функции на «inner(useless=useless)».
То же, кстати, происходит при импорте модуля:
import random
def outer():
print random.choice
#import random
outer()Раскомментируйте строчку со вторым импортом и получите ошибку.
Все эти ошибки возникают
Я не придумал хороших причин так делать с точки зрения языка (может их
Кто в офисе?
Побывал сегодня на работе и, в перерыве между делами, написал небольшой скрипт на bash.
На оптимальность решений не претендую, конечно, всё равно основное время работы — это ожидание данных из сокета.
# Кто сегодня в офисе?
# private data vars
WAPIHOST='██████.██████-████.██'
SAPIHOST='█████.██████.██'
SAPI='/█████/██████.xhtml?██████████=█&█████_██=██'
# non-private data vars
WAPI='/where/%s'
NOW=$(date +%s)
function whereAreYou {
exec 3<>/dev/tcp/$WAPIHOST/80
echo -e "GET ${WAPI/\%s/$1} HTTP/1.0\nHost: $WAPIHOST\n\n" >&3
local DATA=$(grep -E '^.?$' -A1 <&3)
if [[ ! $DATA =~ 'VPN' && $DATA =~ 'updated_at' ]]; then
local date=$(echo $DATA | sed -E 's/^.*updated_at"[^"]+"([^"]+).+/\1/' | xargs -Io date -d'o' +%s)
if [ $(($NOW-$date)) -le 3600 ]; then
echo "$1 - $(date -d@$date +%k:%M)"
fi
fi
}
exec 4<>/dev/tcp/$SAPIHOST/80
echo -e "GET $SAPI HTTP/1.0\nHost: $SAPIHOST\n\n" >&4
while read -r line <&4; do
nick=$(echo $line | egrep -o "href='http://$SAPIHOST/\w+" | cut -b$((15+${#SAPIHOST}))-)
[ -n "$nick" ] && whereAreYou $nick
done