Упустил квадрик :(

Первый раз вышел на улицу с ребёнком запустить квадрик, не справился с управлением и он улетел в сторону реки.

Искали почти час пока не стемнело, не нашли :(

Расстроен жутко. Получил его только а начале недели, и тут такая досада.

jjrc h8cОсталась только камера, аппаратура и запасной аккум.

Сижу в грусти и печали :(

Может ещё один заказать?

Опубликовал:
Раздел: Мои новости

Backup сервера на Яндекс.Диск

2 февраля 2015

Как известно, админы делятся на тех кто не делает бэкапы, и тех кто уже делает.

Кнопка 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 поставить) %)

Опубликовал:

Рукожопства пост: починил планшет

18 января 2015

Перестал тут давеча китайский планшетик (Yuandao/Window N101) мой подавать признаки жизни. Диагноз: не включается.
В принципе я давно знал что у него проблема с зарядкой, в том плане, что родная дохнет, разъем разбалтывается и все, не заряжается.

И так пробовал, и так, ну никак.

Разобрал его, поджал контакты, однофигственно никак. Решил переделать заменить зарядку, но покупать что-то во-первых лень, а во-вторых, не уверен что поможет, поэтому нашел конец кабеля с USB, отрезал разъем от родной зарядки, ну и смотал все это дело синей изолентой…

Думается все должно засвистеть и заплясать, ан нет… при подключении зарядки — напряжение на контактах разъема есть, на контактах аккумулятора со временем напряжение тоже растет (изначально когда открыл было порядка 3.0V, что совсем не айс). Доползло где-то до 3.9, но планшет вроде как и не подает признаков жизни. Ну все думаю, совсем беда…

Но, прислушался, слышу динамики чутка шипят. Зажал кнопку выключения для принудительного отключения — затихли… Включил — опять зашипели. Подождал, отправил сообщение — планшет блямкнул уведомлением.

Ага! Работает, только экран не але.

Где-то читал, что бывает глючит и типа отпаять ему аккумулятор (обесточить совсем), дать полежать и обратно. Проманипулировал — ничего.

И тут — эврика: при поднятии аккумулятора — зажегся экран. Поэкспериментировал — судя по всему что-то с шлейфом.

Крепление шлейфа экрана Yuandao N101

Крепление шлейфа экрана Yuandao N101

Как всегда на помощь пришла синяя изолента — подклеил снизу шлейфа, зафиксировал сверху — и все работает.

И, что приятно — заряжается:

Зарядка планшета N101

Зарядка планшета N101

Ну и собственно сам шнурок для зарядки на фоне самого планшета и повербанка от Xiaomi:

Зарядка Yuandao N101 от USB

Зарядка Yuandao N101 от USB

По хорошему осталось найти зарядку, выдающую честных 2A, иначе, подозреваю, заряжаться будет очень долго. Пока таких в прямой досягаемости нет, но что-нибудь придумаю.

P.S. Паяльником, кроме проводов аккумулятора паял провода к динамику, которые чисто случайно оборвал, хлипкие они :)

Опубликовал:
Раздел: Мои новости

Python: RSS to Twitter (oauth версия)

11 марта 2012

Старый вариант репостинга в твиттер из 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 (устарело)

23 июня 2011

Сегодня, в связи с тем что гугл собирается закрывать свой 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

19 апреля 2011

Вчера озаботился возможностью что-то опубликовать в блоке посредством 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

Опубликовал:

И смех, и грех.

13 апреля 2011

Нашел сегодня на башорге:

В Пскове, если водилы попали в дтп, им нужно выложить по полтыщи деревянных с лица на пиво полицаям, чтоб товарищи гайцы приехали на место дтп в ближайшие пару часов.

вчера две тачки столкнулись у супермаркета аккурат напротив главного псковского здания гибдд. думали, раз так, то не придется платить дань в количестве тех самых пиццот рублей. ан нет, простояли 11 часов, пока «органы» не соизволили к ним свои попы вытащить. и это при том, что никаких чп и аврала в городе не было.

выводы сами делайте…

Опубликовал:
Раздел: Мои новости

Решение задачки для php программистов с хабра

5 апреля 2011

Увидел на хабре задачку при собеседовании для 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"));
?>

Опубликовал:

Переезд на новый ВДС

30 ноября 2010

Собственно сегодня с утреца получил письмо от хостера, о том что freebsd 6 больше не комильфо и пора бы обновить сервер до 8ки (а мне все лень было):

вообщем пол дня продолбался, но все перенес, заодно обнаружилось, что я забыл продлить домен этого блога и он радостно уже неделю был в дауне, посему быстренько продлил домен и теперь все работает. субъективно работает быстрее чем раньше, но пока сложно сказать, посмотрим что будет когда появиться хоть какая то нагрузка…

P.S. В посте аж две реферальные ссылки, по ним можно не нажимать :)

Опубликовал:
Раздел: Мои новости