
Упустил квадрик :(
Первый раз вышел на улицу с ребёнком запустить квадрик, не справился с управлением и он улетел в сторону реки.
Искали почти час пока не стемнело, не нашли 🙁
Расстроен жутко. Получил его только а начале недели, и тут такая досада.
Осталась только камера, аппаратура и запасной аккум.
Сижу в грусти и печали 🙁
Может ещё один заказать?
Backup сервера на Яндекс.Диск
Как известно, админы делятся на тех кто не делает бэкапы, и тех кто уже делает.

Так то у меня есть бекапы средствами хостинга, но для собственного спокойствия решил таки сделать небольшой скриптик для бекапа всего важного на яндекс.диск, благо появился консольный клиент яндекс.диска под linux.
Особенности:
1. каждая БД сохраняется отдельным файлом, потом все вместе архивируются
2. архивируется каталог /etc
3. архивируется каталог /root
4. архивируется каталог /home
5. итоговый архив шифруется с помощью gpg
6. если архивов в папке больше 7шт (настраивается переменной MAX_FILES), то старые удаляются.
Вся установка/настройка скрипта сводится к:
1. установка и настройка клиента яндекс.диска по ссылке выше
2. копирование скрипта куда-нибудь на сервер
3. настроить логин/пароль к mysql базе
MYSQL_USER="user" MYSQL_PASSWORD="password"
4. ввести пароль для шифрования файле бекапа (через gpg)
GPG_PASSOWRD="gpg_password"
5. прописать скрипт в cron на запуск например в 4 утра.
0 4 * * * /home/cron/backup.sh >/dev/null 2>&1
сам скрипт:
#!/bin/bash MYSQL_USER="user" MYSQL_PASSWORD="password" GPG_PASSOWRD="gpg_password" BACKUP_DIRECTORY="/home/backups" MAX_FILES=7 databases=`mysql --user=$MYSQL_USER --password=$MYSQL_PASSWORD -e "SHOW DATABASES;" | tr -d "| " | grep -v Database` curr_date=`date +%Y\.%m\.%d` for db in $databases; do echo `date +%H:%M:%S` ": Dumping database: $db" OPT="" if [[ "$db" == "mysql" ]] ; then OPT=" --events" fi mysqldump --user=$MYSQL_USER --password=$MYSQL_PASSWORD --databases $db --add-drop-table --add-locks --create-options --single-transaction -Q -c -e $OPT > /tmp/$curr_date.$db.sql done echo `date +%H:%M:%S` ": Create DB archive" cd /tmp tar czf /home/db_$curr_date.tgz *.sql echo `date +%H:%M:%S` ": Remove tmp sql files" rm /tmp/*.sql echo `date +%H:%M:%S` ": Backup etc files" cd /etc/ tar czf /home/etc_$curr_date.tgz * echo `date +%H:%M:%S` ": Backup root files" cd /root/ tar czf /home/root_$curr_date.tgz * echo `date +%H:%M:%S` ": Backup all files" cd /home/ tar czf $BACKUP_DIRECTORY/backup_$curr_date.tgz * --exclude="backups" --exclude="*/wp-content/cache/*" /usr/bin/gpg -c --force-mdc --batch --yes --passphrase=$GPG_PASSOWRD $BACKUP_DIRECTORY/backup_$curr_date.tgz echo `date +%H:%M:%S` ": Remove tmp files" rm /home/db_$curr_date.tgz /home/etc_$curr_date.tgz /home/root_$curr_date.tgz $BACKUP_DIRECTORY/backup_$curr_date.tgz echo `date +%H:%M:%S` ": Remove old backup files" bf=`ls -1 $BACKUP_DIRECTORY/backup*.tgz.gpg | sort -d` fc=`ls -1 $BACKUP_DIRECTORY/backup*.tgz.gpg | wc -l` if [ "$fc" -gt "$MAX_FILES" ] ; then for file in $bf do if [ "$fc" -gt "$MAX_FILES" ] ;then fc=$(($fc - 1)) rm -f $file fi done fi echo `date +%H:%M:%S` ": Yandex.Disk sync" /usr/bin/yandex-disk sync
В планах:
1. сделать сохранение месячных и недельных бекапов
2. подумать над инкрементными ежедневными бекапами (хотя тут наверное проще какую-нибудь Bacula поставить) %)
Рукожопства пост: починил планшет
Перестал тут давеча китайский планшетик (Yuandao/Window N101) мой подавать признаки жизни. Диагноз: не включается.
В принципе я давно знал что у него проблема с зарядкой, в том плане, что родная дохнет, разъем разбалтывается и все, не заряжается.
И так пробовал, и так, ну никак.
Разобрал его, поджал контакты, однофигственно никак. Решил переделать заменить зарядку, но покупать что-то во-первых лень, а во-вторых, не уверен что поможет, поэтому нашел конец кабеля с USB, отрезал разъем от родной зарядки, ну и смотал все это дело синей изолентой…
Думается все должно засвистеть и заплясать, ан нет… при подключении зарядки — напряжение на контактах разъема есть, на контактах аккумулятора со временем напряжение тоже растет (изначально когда открыл было порядка 3.0V, что совсем не айс). Доползло где-то до 3.9, но планшет вроде как и не подает признаков жизни. Ну все думаю, совсем беда…
Но, прислушался, слышу динамики чутка шипят. Зажал кнопку выключения для принудительного отключения — затихли… Включил — опять зашипели. Подождал, отправил сообщение — планшет блямкнул уведомлением.
Ага! Работает, только экран не але.
Где-то читал, что бывает глючит и типа отпаять ему аккумулятор (обесточить совсем), дать полежать и обратно. Проманипулировал — ничего.
И тут — эврика: при поднятии аккумулятора — зажегся экран. Поэкспериментировал — судя по всему что-то с шлейфом.
Как всегда на помощь пришла синяя изолента — подклеил снизу шлейфа, зафиксировал сверху — и все работает.
И, что приятно — заряжается:
Ну и собственно сам шнурок для зарядки на фоне самого планшета и повербанка от Xiaomi:
По хорошему осталось найти зарядку, выдающую честных 2A, иначе, подозреваю, заряжаться будет очень долго. Пока таких в прямой досягаемости нет, но что-нибудь придумаю.
P.S. Паяльником, кроме проводов аккумулятора паял провода к динамику, которые чисто случайно оборвал, хлипкие они 🙂
С Новым, 2015-м, годом!
Откроет Новый Год тихонько дверь,
И в миг, когда часы пробьют двенадцать,
Заглянет в дом пушистый белый зверь,
Чтоб на двенадцать месяцев остаться.

Python: RSS to Twitter (oauth версия)
Старый вариант репостинга в твиттер из RSS давно не работает.
Снова понадобилась такая штука, сделал новый вариант репостинга через oauth.
Используются модули oauth-python-twitter2 и python-bitly.
Все предельно просто, настройка заключается в заполнении значений переменных
bit_api=""
bit_login=""
consumer_key=""
consumer_secret=""
access_key=""
access_secret=""
rss_url="/rss"
После чего запуск скрипта в cron в соотвествии с требованиями по скорости постинга. Можно в принципе и в CMS встроить, чтобы постинг мгновенный был.
Сам код:
#!/usr/local/bin/python
# -*- coding: utf8 -*-
import urllib, libxml2, pickle, os
from time import sleep
from oauthtwitter import OAuthApi
import bitly
bit_api=""
bit_login=""
consumer_key=""
consumer_secret=""
access_key=""
access_secret=""
rss_url="/rss"
if __name__ == '__main__':
doc = libxml2.parseFile(rss_url)
links=[]
for item in doc.xpathEval('//channel/item/link'):
links.append(item.content)
titles=[]
for item in doc.xpathEval('//channel/item/title'):
titles.append(item.content)
rss_path = os.path.join(os.path.dirname(__file__), 'rss.db')
file = open (rss_path)
old_links=pickle.load(file)
file.close()
items=[]
f= 0
for x in xrange( 0,len(links)):
for old in old_links:
f= 0
if (old==links[x]):
f=1
break
if (f== 0):
items.append(x)
twitter = OAuthApi(consumer_key, consumer_secret, access_key, access_secret)
bitly_api = bitly.Api(bit_login, bit_api)
for x in items:
title=titles[x].decode("utf8")
if len(title)<=120:
print "link %s: %s" % (x,links[x])
if x!= 0:
sleep(15)
try:
twitter.UpdateStatus(title+" "+bitly_api.shorten(links[x]))
#print title.encode("utf8")+" "+bitly_api.shorten(links[x])
except ValueError:
pass
file=open(rss_path,"w")
ser=pickle.dump(links,file)
file.close()
Критика, как обычно, приветствуется.
Перевод текстов посредством Bing API (устарело)
Сегодня, в связи с тем что гугл собирается закрывать свой translate api, таки собрался и сотворил класс для перевода текста через SOAP сервис Bing
В связи с тем, что по каким-то странным обстоятельствам нормальной документации нет, а есть только куцый пример на VB (о ужас!) и C# с использованием видимо готовых библиотек пришлось повозиться и подбирать параметры и вид, в котором надо данные отправить сервису, чтоб он не ругался непонятными словами.
В результате родилось вот что:
<?php
class Bing_Translate_API {
function translate($text, $from = 'en', $to = 'ru') {
if (mb_strlen($text)>2000)
{
echo "шмахтунг\n";
return false;
}
$c=new SoapClient("http://api.bing.net/search.wsdl",array(
"AppId"=>"bingApiId",
"Version"=>"2.2"
));
$arr=array(
"parameters"=>array(
"AppId"=>"bingApiId",
"Market"=>"en-us",
"Version"=>"2.2",
"Sources"=>array(
"Translation"
),
"Translation"=>array(
"SourceLanguage"=>$from,
"TargetLanguage"=>$to
),
"Query"=>$text)
);
$r=$c->Search($arr);
if (isset($r->parameters->Translation->Results->TranslationResult->TranslatedTerm))
{
return $r->parameters->Translation->Results->TranslationResult->TranslatedTerm;
}
else
{
echo "ахтунг\n";
return false;
}
}
}
?>
а вызывать пользоваться этим безобразием теперь вообщем-то просто:
<?php
echo Bing_Translate_API::translate("text to translate","en","ru");
?>
Кроме того, выяснилось, что у Bing API есть ограничение на размер запроса примерно в 2кБ текста. А Примерно потому, что через раз он текст с размером 2048 символов не переводил, уж не знаю почему.
BingApiId получать по ссылке http://www.bing.com/developers/
З.Ы. я знаю что код кривой, и при малейшем чихе упадет, но делать ничего не буду, это есть пример 🙂
Изобретая велосипеды: xmlrpc
Вчера озаботился возможностью что-то опубликовать в блоке посредством xmlrpc из php.
Проковырявшись в общей сложности часа 4 с библиотекой xmlrpc и встроенной функцией xmlrpc_encode_equest и так и не добившись нормальной работы всего этого безобразия, собрался и сегодня за 1.5 часа сделал свой велосипед 🙂
<?php
/*
* Велосипед для работы с xmlrpc
* версия 0.1beta
*
* Copyright (c) 2011 mrdaark.
* Все права защищены
*
*/
/*
* Функция для отправки запроса на xmlrpc сервер
* использует библиотеку curl
* в качестве параметров:
* @url - url адрес сервера
* @request - запрос формируемый с помощью функции xmlrpc_request
*/
function xmlrpc_send($url,$request)
{
if(!function_exists('curl_init')) {
die ("Curl PHP package not installed\n");
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/xml; charset=utf-8"));
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
$response = curl_exec($ch);
$response = xmlrpc_decode($response);
curl_close($ch);
return $response;
}
/*
* Функция формирования xml запроса на xmlrpc
* в качестве параметров:
* @method - вызываемый метод
* @params - массив списка параметров
*/
function xmlrpc_request($method,$params)
{
$xml ="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$xml.="<methodCall><methodName>".$method."</methodName><params>";
if (is_array($params))
{
foreach ($params as $v)
{
if (is_numeric($v))
{
$xml.="<param><value><int>".$v."</int></value></param>";
}
else if (is_string ($v))
{
$xml.="<param><value><string>".$v."</string></value></param>";
}
else if (is_bool($v))
{
$xml.="<param><value><boolean>". ($v ? "1":"0") ."</boolean></value></param>";
}
else if (is_array($v))
{
$xml.="<param>"._xmlrpc_genstruct($v)."</param>";
}
}
}
$xml.="</params></methodCall>";
return $xml;
}
/*
* Функция формирования именованной структуры
* в качестве параметров:
* @params - массив списка параметров
*/
function _xmlrpc_genstruct($params)
{
if (is_array($params))
{
$xml="<value><struct>";
foreach ($params as $k=>$v)
{
//формируем поля запроса.
if (is_numeric($v))
{
$xml.="<member><name>".$k."</name><value><int>".$v."</int></value></member>";
}
else if (is_string ($v))
{
$xml.="<member><name>".$k."</name><value><string>".$v."</string></value></member>";
}
else if (is_bool($v))
{
$xml.="<member><name>".$k."</name><value><boolean>". ($v ? "1":"0") ."</boolean></value></member>";
}
else if (is_array($v))
{
$xml.="<member><name>".$k."</name>";
if (_xmlrpc_is_struct($v))
{
$xml.=_xmlrpc_genstruct($v);
}
else
{
$xml.=_xmlrpc_genarray($v);
}
$xml.="</member>";
}
}
$xml.="</struct></value>";
return $xml;
}
else
{
return "";
}
}
/*
* Функция формирования неименованного массива
* в качестве параметров:
* @params - массив списка параметров
*/
function _xmlrpc_genarray($params)
{
if (is_array($params))
{
//проверим необходимость добавления имени
$xml="<value><array><data>";
foreach ($params as $v)
{
//формируем поля запроса.
if (is_numeric($v))
{
$xml.="<value><int>".$v."</int></value>";
}
else if (is_string ($v))
{
$xml.="<value><string>".$v."</string></value>";
}
else if (is_bool($v))
{
$xml.="<value><boolean>". ($v ? "1":"0") ."</boolean></value>";
}
else if (is_array($v))
{
if (_xmlrpc_is_struct($v))
{
$xml.=_xmlrpc_genstruct($v);
}
else
{
$xml.=_xmlrpc_genarray($v);
}
}
}
$xml.="</data></array></value>";
return $xml;
}
return "";
}
/*
* Функция проверки переданного массива на
* предмет необходимости формирования
* именованной структуры
* в качестве параметров:
* @params - массив списка параметров
*/
function _xmlrpc_is_struct($params)
{
$keys=array_keys($params);
foreach ($keys as $k=>$v)
{
if ($k!=$v)
{
return true;
}
}
return false;
}
?>
Пользоваться безобразием просто, вот примерчик постинга в блог на wordpress:
<<?php
require("xmlrpc.php");
//формируем массив с параметрами запроса
$content=array();
$content['title']="Тестовая запись";
$content['categories'] = array("news");
$content['description']="Описание тестовой запись (то, что до тега <!--more-->)";
$content['mt_text_more']="Собственно основная часть постинга";
$content['mt_keywords']="ключевые, слова";
//формируем xml запрос
$request=xmlrpc_request("metaWeblog.newPost",
array(1,"admin","password",$content,false));
//отправляем серверу
xmlrpc_send("http://example.com/wordpress/xmlrpc.php",$request);
?>
вроде все просто и понятно. Работает на данный момент только с кодировкой UTF-8. Собственно и затеялось как раз потому, что два предыдущих варианта напрочь отказывались нормально отправлять в UTF-8.
Реализованы не все типы, возможные в xmlrpc, однако мне для постинга в WordPress этого пока хватит, буде кому понадобится еще чего можете меня попинать — допишу, ну или сами, а я добавлю со ссылкой на автора 🙂
P.S. походу wordpress чудит с кавычками. файл исходника xmlrpc.phps
И смех, и грех.
Нашел сегодня на башорге:
В Пскове, если водилы попали в дтп, им нужно выложить по полтыщи деревянных с лица на пиво полицаям, чтоб товарищи гайцы приехали на место дтп в ближайшие пару часов.
вчера две тачки столкнулись у супермаркета аккурат напротив главного псковского здания гибдд. думали, раз так, то не придется платить дань в количестве тех самых пиццот рублей. ан нет, простояли 11 часов, пока «органы» не соизволили к ним свои попы вытащить. и это при том, что никаких чп и аврала в городе не было.
выводы сами делайте…
Решение задачки для php программистов с хабра
Увидел на хабре задачку при собеседовании для php программистов http://habrahabr.ru/blogs/php/116686/
Решил попробовать сам ее решить, вроде не сложно. вместе с отладкой, сделал за ~20минут, т.е. в норматив не уложился, что херово.
Получилось вот так, хз насколько это оптимально. Есть идеи что улучшить?
<?php
function read_conf($path)
{
$f=file_get_contents($path);
//разбиваем на строки
$lines=explode("\n",$f);
$tmp=array();
//режем строки на key=>value
foreach($lines as $v)
{
if (trim($v)!="")
{
list($key,$value)=explode("=",$v,2);
$tmp[trim($key)]=trim($value);
}
}
$res=array();
//режем ключи по параметрам
foreach ($tmp as $key=>$value)
{
$keys=explode(".",$key);
if (count($keys)!=1)
{
//тут будем делать подмассивчики
$key=array_pop($keys);
$first_key=array_shift($keys);
if (!isset($res[$first_key]))
{
$res[$first_key]=array();
}
$pres=&$res[$first_key];
while (count($keys)!= 0)
{
$tmp_key=array_shift($keys);
if (!isset($pres[$tmp_key]))
{
$pres[$tmp_key]=array();
}
$pres=&$pres[$tmp_key];
}
$pres[$key]=$value;
}
else
{
$res[$key]=$value;
}
}
return $res;
}
print_r(read_conf("conf.ini"));
?>




