суббота, 4 октября 2014 г.

Скахин Алексей / pihel

Скахин Алексей, pihel Биография:
Родился в городе Вологда 9 марта 1987 года. В 2004 году завершил обучение в средней школе №12 города Вологда. В 2009 году окончил ВоГТУ по специальности программное обеспечение. Тема дипломного проекта: "Синтез виртуальной среды с применением скалярных и аналитических функций возмущения и трехмерных массивов вокселей".

В бывшем радиолюбитель: 3ий взрослый разряд по радиотелеграфии, радиолюбитель в кв диапазоне. Позывной RA1QKJ. Возможно уже числится не за мной.

О себе:
В свободное от работы время люблю играть в волейбол и путешествовать на машине.

Навыки:
1. PHP: занимаюсь разработкой с 2004 года
 а. Bitrix - интеграция, интернет магазины, информационные порталы, государственные порталы (8 сертификатов (золотой партнер), tr35.ru)
 b. Drupal - интеграция, разработка модулей
2. JS: использую библиотеку JQuery
3. C++: библиотека QT, C++ Builder
4. VBS: автоматизация рутины (авто сборка ПО, создание копий приложений и т.д.)
5. СУБД: MySql, MS SQl, Oracle (+pl-sql приложения)
6. Linux: пользователь Fedora и Ubuntu
7. Управление версиями: SVN, CVS, MS Visual Source of Site, Git
8. Построение отчетов: FastReport, Excel (через ActiveX, XML шаблон), OpenOffice через UNO, html
9. Векторная графика в браузере: SVG (Библиотека raphaeljs)
10. Flex: разработка клиент-серверных приложений.

Места работы:
1. ВНКЦ ЦЭМИ РАН: разработка внутренней информационной системы (php/js/mysql) 2007-2008 г.
2. C404: веб студия интернет решений (php/js/mysql) 2008-2010
3. T-R-O-Y-A: веб студия интернет решений (php/js/mysql/bitrix) 2008-...
4. Rstyle Softlab ОПР ДСУП: разработка системы управления предприятием, старший программист (rsl/vbs/fast report/ms sql) 2008-2010
5. Макси: разработка системы управления предприятием, программист (с++/fast report/ORACLE) 2010-...

Сделал в 2012:
1. Народное голосование за законопроекты Государственной думы - голосование, комментирование, аналитика.

Сделал в 2011:
1. Земельные участки Вологды - отсечение агентств, отображение на карте, возможности фильтрации и сортировки
2. Законодательное собрание Вологодской области - редизайн, изменение структуры, мобильная версия, экспорт законов на сайт из LanDocs
3. магазин лицензионного софта - bitrix
4. Вологодска Городская Дума - bitrix, Yandex.Api, гос. портал с поддержкой пользователей
5. Золотой партнер 1C-Bitrix
6. Адреналин спорт - bitrix, интеграция с 1c
7. Автоматизация OpenOffice: c++, uno, open office
8. Веб камеры Вологды - просмотр он-лайн и запись истории

Сделал в 2010:
1. МУП Аптека на дворянской - bitrix, выгрузка товаров, цен и остатков из системы управления предприятием Uniko.
2. Дизайн студия ТРОЯ - bitrix, техподдержка клиентов.
3. Законодательное собрание Вологодской области - видеоблог, приемная, перенос данных: Bitrix, IIS, mail server, mssql
4. ВологдаМеталлооптторг - Интренет магазин: Bitrix, IIS
5. Приложение для вконтакте: Ставки на бирже
6. Сайт управляющей компании Нордсити: битрикс
7. Сайт-визитка maria-milavina.ru: drupal
8. Экспорт объявлений вконтакте: curl, php, mysql, многопоточность
9. Разработка модуля для Drupal: загрузка архива (rar, zip), поиск изображений в архиве, создание превью, водный знак, поворот, загрузка изображений на список ФТП.
Сделал в 2009:
1. http://prokuratura.vologda.ru - гос. портал с онлайн поддержкой граждан (Bitrix)
2. http://sportavto.com - портал и интернет магазин автозапчастей (Bitrix)
3. http://mobipad.ru/ - доступ к файлам за смс (разработка модуля для drupal)
4. Векторный графический редактор в браузере: svg, vml, raphael, jquery
5. Виртуализация пространства: трассировка, возмущение квадрик

воскресенье, 19 июня 2011 г.

Адаптация модуля связи Punbb на Drupal 7

Api Drupal 7 сильно изменилось, в связи с этим перевод модуля был долгим, но я все же это сделал :)
Предлагаю всем желающим обновиться.

Ссылка для скачивания модуля новая: http://pihel.jino.ru/files/punbb7.zip

воскресенье, 15 мая 2011 г.

Особенности OnBeforeIBlockElementUpdate в Bitrix

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

После недолгих разбирательств (создания истории изменений) выяснилось, что ошибка скорей техническая. Т.к. ошибку удалось локализовать, она проявлялась при привязки раздела к статье из списка элементов. Тогда как изменение раздела из самой статьи не приводило к ошибке.
Следующим этапом было штудирование файла init.php, где хранятся обработчики событий портала.
В файле init.php хранился обработчик, заменяющий текст статьи на другой в автоматическом режиме.
AddEventHandler("iblock", "OnBeforeIBlockElementUpdate", Array("MyClass", "OnBeforeIBlockElementUpdateHandler"));

class MyClass
{
    function OnBeforeIBlockElementUpdateHandler(&$arFields)
    {
       $arFields["DETAIL_TEXT"] = str_replace('src="../../upload/', 'src="/upload/', $arFields["DETAIL_TEXT"]);
    }
}

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

Правильный код в этом случае выглядит так (т.е. необходима проверка существования поля):
AddEventHandler("iblock", "OnBeforeIBlockElementUpdate", Array("MyClass", "OnBeforeIBlockElementUpdateHandler"));

class MyClass
{
    function OnBeforeIBlockElementUpdateHandler(&$arFields)
    {
        if(!empty($arFields["DETAIL_TEXT"])) {
          $arFields["DETAIL_TEXT"] = str_replace('src="../../upload/', 'src="/upload/', $arFields["DETAIL_TEXT"]);
        }
    }
}

вторник, 29 марта 2011 г.

четверг, 3 февраля 2011 г.

Особенности Oracle: данные выборки при joine таблиц

Все кто пишет SQL запросы так или инче знает, что данные основной выборки можно использовать где угодно, кроме секции from.
Вот такой запрос выполнится с ошибкой:
SELECT t1.id, t1.name 
FROM t1, 
(SELECT id FROM tmp WHERE tmp.sec_id = t1.id) as t2
Но оказывается это ограничение можно обойти в ORACLE. Достаточно оформить подзапрос в функцию, возвращающую таблицу и все отработает без проблем.

Пример:
Есть таблица, содеражщая 2 столбца: имя, число. Нам нужно вывести данные, продублировав поле "имя" число раз, заданное в поле "число". (Понятно, что данный пример можно сделать рекурсивным запросом, но факт такой возможности может не раз пригодится). Запрос:
SELECT t1.num, t1.name FROM t1, 
table (virtual_date_table(t1.num, sysdate, sysdate))
Функция, возвращающая таблицу:
CREATE OR REPLACE 
FUNCTION       admin.virtual_date_table(p_num_rows in INTEGER, p_start_date IN DATE, p_end_date IN DATE)
RETURN virtual_date_table_type
IS
  l_data virtual_date_table_type := virtual_date_table_type();
  l_step NUMBER := 1;
BEGIN
  l_step := (p_end_date - p_start_date) / p_num_rows;
  FOR i IN 1 .. p_num_rows
  LOOP
    l_data.extend;
    l_data(l_data.count) := p_start_date + i * l_step;
  END LOOP;

  RETURN l_data;
END;
/
Результат выборки:
num | name
1   | value1
3   | value3
3   | value3
3   | value3

воскресенье, 14 ноября 2010 г.

Доступ к Exchange почте по протоколу Mapi

Хочу рассказать сегодня как получить список писем, аттачей из Windows Exchange и программно отсылать письма через протокол Simple MAPI.
Для этого нам понадобится небольшой класс. Он слегка недоделан: отправка почты и получение списка аттачей, но это доделать не так сложно.
Описание протокола Simple MAPI можно почитать по адресу: http://msdn.microsoft.com/en-us/library/dd296728(v=VS.85).aspx

Итак, описание класса на C++ (Builder):
#ifndef SimpleMapiH
#define SimpleMapiH

using namespace std;

#include <windows.h>
#include <windowsx.h>
#include <mapi.h>
#include <winbase.h>
#include <vector>

//структура с информацией о письме
struct TMail {
  AnsiString from;
  AnsiString subj;
  unsigned int files;
  TDateTime date;
  //указатели на письмо
  LPSTR lpszMessageID;
  MapiMessage *lpMessage;
};

class SimpleMapi {
   private:
      //библиотека и указатели на нужные нам функции
      HANDLE hMAPILib;
      LPMAPILOGON lpfnMAPILogon;
      LPMAPIFINDNEXT lpfnMAPIFindNext;
      LPMAPILOGOFF lpfnMAPILogoff;
      LPMAPIREADMAIL lpfnMAPIReadMail;
      LPMAPIFREEBUFFER lpfnMAPIFreeBuffer;

      //текущая сессия
      LHANDLE lhSession;

      //буфферы
      char szSeedMessageID[512];
      char szMessageID[512];
      LPSTR lpszSeedMessageID;
      LPSTR lpszMessageID;

      //указатель на письмо
      MapiMessage *lpMessage;

      //тип ошибки
      ULONG err;

      //разбор даты
      TDateTime __fastcall ParseDate(AnsiString date);
      
   public:
        //полный список писем
        vector<tmail> MailList;

        __fastcall SimpleMapi();
        //подключение к Exchenge
        bool __fastcall Connect();
        //перейти к первому письму из списка
        bool __fastcall GetFirst();
        //перейти к следующему письму из списка
        bool __fastcall GetNext();
        //получить указатель на полную информацию о текущем письме
        bool __fastcall GetElement();
        //заполнить структуру текущим письмом
        TMail __fastcall Fetch();
        //получить список всех писем (заполняем вектор)
        bool __fastcall GetList();
        //отключаемся от Exchange
        void __fastcall Disconnect();
        //отправить письмо - не реализовано
        void __fastcall SendMail();
        //получить список приложений письма по указателю
        vector<ansistring> __fastcall GetAttachs(LPSTR lmID, MapiMessage *lpMes);
};

#endif

среда, 29 сентября 2010 г.

Кастомизация визуального редактора Bitrix

Довольно частая вещь как вставка изображения через визуальный редактор с возможностью увеличения в Bitrix никак не решена.

Можно конечно загрузить 2 варианта изображения (большое и маленькое), в текст вставить изображение превью и указать ссылку на большое. Но хотелось бы автоматизировать этот процесс.

Официальная тех. поддержка отказалась решать эту проблему, а документация не содержала списка событий. Хорошо хоть была возможность перегрузить js класс редактора (Документация). Не понятно было какой из сотен методов мне нужен.

Методом перебора был найден один интересный метод SAttr в котором происходила установка атрибутов абсолютно всех html элементов внутри редактора.
Он принимает внутрь 3 параметра: Объект, Свойство, Значение.

Приведу пример, в котором после загрузки изображения в редактор происходит вставка превью, и устанавливается ссылка на оригинал (Добавлять надо в bitrix/php_interface/init.php):
<?
//событие загрузки визуального редактора
AddEventHandler("fileman", "OnIncludeHTMLEditorScript", "OnIncludeHTMLEditorHandler"); 

//наш обработчик
function OnIncludeHTMLEditorHandler()
{
 ?>
 <script>
        //запоминаем ссылку на родителя
        SAttr_= SAttr;
 SAttr = function (e,a,v) { //элемента, свойство, значение
          //выполняем сначала родителя (устанавливаем свойства)
          this.SAttr_(e,a,v);
          //произошла установка title изображения
          //title может быть установлен при изменении или загрузке изображения
          if(a == 'title' && e.tagName == 'IMG') {
            var src = e.src;

            //формируем новое изображение
            var img = '';
            if(e.hspace > 0) img = img + ' hspace='+e.hspace;
            if(e.vspace> 0) img = img + ' vspace='+e.vspace;
            if(e.border> 0) img = img + ' border='+e.border;
            if(e.align != "") img = img + ' align="'+e.align+'"';
            //if(e.alt!= "") img = img + ' alt="'+e.alt+'"';
            if(e.title!= "") img = img + ' title="'+e.title+'"';

            //вставляем наше измененное изображение
            //я использовал плагин zoomie для jquery, без собственно ресайза изображения
            pObj.pMainObj.insertHTML('<img alt="'+src+'" class="zoomi" width='+e.width+' height='+e.height+' src="'+src+'" '+img+'>');
            
            //удаляем неизмененное изображение
            e.parentNode.removeChild(e);
          }  
 }
 </script>
 <?
}
?>

Пример работы

суббота, 28 августа 2010 г.

Моя машинка

Вот наконец купил себе новую машинку: Kia Rio 2010.
Из дополнительного оборудования: спойлер, защита картера. Общая сумма 454 т.р.

пятница, 6 августа 2010 г.

Скрипт автоматического тестирования интерфейса

По работе мне требовалось заполнить около 1000 сложных форм. Естественно делать вручную мне этого не хотелось и у меня родился скрипт для автоматического тестирования.

Программа состоит из 2 частей:
  • Запись действий: положение мыши, нажатие на кнопки, время событий
  • Воспроизведение записанных событий.
Управление клавиатурой будет добавлено поздней.

Описание классов:
#ifndef mouseH
#define mouseH

#include <vector>
#include <dos.h>
#include <time.h>
#include <windows.h>

struct step { //структура для хранения событий
        int x, y; //положение курсора
        int sleep; //время до события от предыдущего
};

class TMouseRec { //класс записи событий
        private:
                int second; //время для записи
                int teak;
                time_t time_start; //время старта
                time_t time_cur; //текущее время
                time_t time_bef; //время предыдущего события
        public:
                std::vector stp; //вектор структур событий
        public:
                TMouseRec(int _second);
                void getXY(int &x, int &y); // положение курсора
                void setStep();
                void start(); //точка входа
};

class TMousePlay { //класс воспроизведения, записанных событий
        private:
                std::vector stp;
                int width, height; //ширина, высота экрана
        public:
                TMousePlay(std::vector &_stp);
                void move(int x, int y); //переместить курсор
                void click(int x, int y); //нажать на кнопку
                void start(bool cycle = false);//точка входа
};

#endif

понедельник, 17 мая 2010 г.

Linux: создание демона

Тема написание демонов широко освещена в интернете (Гугл), так что написанное тут не будет ни для кого секретом.
Просто опишу здесь пример реализации демона, выполняющий каждые 10 минут произвольную команду linux (в данном случае - who, список подключенных пользователей) и записывающий результат в лог.
Код на Си(c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>

int Daemon(void);
char* getTime();
int writeLog(char msg[256]);
char* getCommand(char command[128]);

char* getTime() { //функция возвращает форматированную дату и время
    time_t now;
    struct tm *ptr;
    static char tbuf[64];
    bzero(tbuf,64);
    time(&now);
    ptr = localtime(&now);
    strftime(tbuf,64, "%Y-%m-%e %H:%M:%S", ptr);
    return tbuf;
}

char* getCommand(char command[128]) { //функция возвращает результат выполнения linux команды
    FILE *pCom;
    static char comText[256];
    bzero(comText, 256);
    char  buf[64];
    pCom = popen(command, "r"); //выполняем
    if(pCom == NULL) {
        writeLog("Error Command");
        return "";
    }
    strcpy(comText, "");
    while(fgets(buf, 64, pCom) != NULL) { //читаем результат
        strcat(comText, buf);
    }
    pclose(pCom);
    return comText;
}

int writeLog(char msg[256]) { //функция записи строки в лог
    FILE * pLog;
    pLog = fopen("/home/CENTRAL/skan/daemon/daemon.log", "a");
    if(pLog == NULL) {
        return 1;
    }
    char str[312];
    bzero(str, 312);
    strcpy(str, getTime());
    strcat(str, " ==========================\n");
    strcat(str, msg);
    strcat(str, "\n");
    fputs(str, pLog);
    //fwrite(msg, 1, sizeof(msg), pLog);
    fclose(pLog);
    return 0;
}

int main(int argc, char* argv[]) {
    writeLog("Daemon Start");

    pid_t parpid, sid;
    
    parpid = fork(); //создаем дочерний процесс
    if(parpid < 0) {
        exit(1);
    } else if(parpid != 0) {
        exit(0);
    } 
    umask(0);//даем права на работу с фс
    sid = setsid();//генерируем уникальный индекс процесса
    if(sid < 0) {
        exit(1);
    }
    if((chdir("/")) < 0) {//выходим в корень фс
        exit(1);
    }
    close(STDIN_FILENO);//закрываем доступ к стандартным потокам ввода-вывода
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
    
    return Daemon();
}

int Daemon(void) { //собственно наш бесконечный цикл демона
    char *log;
    while(1) {
        log = getCommand("who");
        if(strlen(log) > 5) { //если в онлайне кто-то есть, то пишем в лог
          writeLog(log);
        }
        sleep(600);//ждем 10 минут до следующей итерации
    }
    return 0;
}