Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Клуб профессиональных программистов :: Выпуск #119


Клуб профессиональных программистов «Весельчак У»
Информационная рассылка сайта и форума.  Выпуск 119.  27 августа 2011 г.

Здравствуйте, уважаемые читатели!

Сегодня предлагаем вам фрагмент статьи «Разработка на языке C, управляемая тестированием».

Также предлагаем подборку свежих тем нашего форума.




Пополнение «Книжной полки разработчика систем со встроенными микропроцессорами»:





Приятного чтения!




Оглавление




В прошлых статьях (части 1, 2, 3) мы освоили инструмент для модульного тестирования программ, написанных на языке C, под названием Unity. Однако обладание отдельным инструментом и даже уверенные навыки работы с ним еще не гарантируют достижения конечной цели. Нужно уметь вписать операции, которые способен выполнять данный инструмент, в общую технологию.

Само по себе модульное тестирование — нужная и важная часть процесса производства ПО. Однако наиболее полно раскрыть его потенциал позволяет технология, которая получила название «разработка, управляемая тестированием» (Test Driven Design, TDD), или в дальнейшем РУТ.

Оценить что-то новое проще в сравнении со старым, привычным. Поэтому сначала вспомним, как производилась разработка до появления РУТ.


Разработка, не управляемая тестированием


С названием для данного раздела у меня возникли совершенно непредвиденные затруднения.

Поначалу само собой напрашивалось название «Традиционные методы разработки», но тогда логически следует, что далее я буду описывать «нетрадиционные» методы, а это слово в последнее время приобрело какой-то двусмысленный оттенок, идет ли речь о медицине, сексуальной ориентации или чем-то еще. Вариант «общепринятые методы» немногим лучше, — ведь TDD получает все большее признание и уже не является экзотикой. Чтобы не тратить драгоценное время на подобные второстепенные вопросы, я решил остановиться на непритязательно-нейтральном «Разработка, не управляемая тестированием» (РНУТ).

Итак, что представляет собой РНУТ? На самом деле этот подход очень хорошо знаком всем без исключения разработчикам: код пишется, компилируется, а затем тестируется (как именно тестируется, в данный момент неважно; основной акцент делаем на последовательности действий, а именно: тестированию подвергается уже готовый, полностью написанный код).

Долгое время такая последовательность казалась естественной и единственно возможной. Ведь тестирование — это по сути проверка, а проверить можно лишь то, что уже существует.

Однако тестировать готовый код не всегда легко. Во-первых, не каждый код сам по себе пригоден для тестирования. Простой пример: некоторая функция (метод) получает извне (скажем, из базы данных) некоторые данные, а затем производит их обработку по сложному алгоритму с множеством ветвлений в зависимости от значений этих данных. Чтобы протестировать эту функцию, необходимо сначала заполнить базу данных тестовыми данными, поскольку в реальной БД может не оказаться необходимых для тестирования значений. Занесение таких данных в рабочую БД может оказать негативное влияние на рабочий процесс, если БД активно используется, а разворачивание специальной базы для тестирования и заполнение ее данными может оказаться достаточно трудоемким. В таких условиях отношение разработчиков к тестированию гарантированно будет негативным, даже если они и осознают реальную пользу от него. Понадобится глубокий рефакторинг кода, чтобы сделать такую функцию действительно пригодной для простого и эффективного тестирования.

Во-вторых, при тестировании готового кода зачастую бывает достаточно трудно добиться полного покрытия кода тестами; особенно хлопотно тестировать код обработки ошибок, которые трудно вызвать или имитировать. Пример: в нашей системе используется запись данных на SD-карты. Есть некоторый код, который обрабатывает ошибки в случае, если запись на карту невозможна из-за ее аппаратной неисправности (дефектные ячейки). Попробуйте-ка испортить исправную карту таким образом, чтобы она выдавала именно нужную нам для тестирования ошибку (либо сделать аппаратный имитатор сбойной карты). Поскольку все это сделать в принципе можно, но достаточно трудоемко, в итоге подобные ветки кода так и остаются не протестированными должным образом, образуя потенциальную мину замедленного действия, которая рванет, когда редкое условие все-таки сработает.

В-третьих, в программах нередко встречаются фрагменты незадействованного кода. Причины для этого разные. Иногда «запасливый» программист запасает функции впрок в полной уверенности, что они понадобятся в ближайшем будущем. Особенно часто такая ситуация встречается при проектировании и реализации «снизу-вверх», когда сначала пишутся вспомогательные модули, а затем основные, пользующиеся услугами вспомогательных. Некоторые из них оказываются вовсе невостребованными, другие и пригодились бы в принципе, но об их существовании уже забыли, к тому же написать их заново оказывается быстрее, чем найти в ворохе плохо оформленного кода. Иногда «мертвый» код появляется по объективным причинам, поскольку изменились требования к продукту и часть ранее реализованных функций теперь не нужна. Независимо от причин появления «мертвого» кода в программе, его наличие не способствует повышению качества продукта, поскольку распознать его не так просто, а сопровождать программу, изобилующую подобными шарадами и головоломками, становится труднее.Наконец, когда сроки сдачи проекта поджимают, слишком велик соблазн пожертвовать тестированием, сократив его объем, а то и проигнорировав вовсе, ведь клиент платит не за тесты. Поскольку планирование программных проектов — дисциплина весьма тонкая, вероятность того, что до полноценного тестирования дело не дойдет вовсе, достаточно велика.

Итак, при том, что РНУТ представляется довольно логичной и понятной, ей присущ ряд недостатков, которые затрудняют последующее тестирование и не лучшим образом влияют на качество продукта.


Разработка, управляемая тестированием


Разработка, управляемая тестированием (РУТ), как легко догадаться, представляет собой РНУТ, вывернутую наизнанку. При таком подходе сначала пишутся тесты и лишь потом сам код, который этим тестам удовлетворяет. РУТ поначалу удивляет и даже шокирует многих разработчиков; сама идея тестировать то, чего еще нет, кажется на первый взгляд абсурдной. Но это лишь на первый взгляд.

РУТ — одна из основ так называемых «гибких» (agile) технологий разработки, популярность которых в настоящее время стремительно возрастает («гибкими» они называются из-за способности приспосабливаться к динамичным, постоянно меняющимся требованиям к изделию). «Гибкие» технологии сами по себе весьма интересны и заслуживают отдельной статьи (и даже не одной), но сейчас мы не будем отходить от основной темы.

...


Полностью прочитать статью можно на нашем сайте, в разделе «Инструменты и технологии проектирования ПО».

  • Программирование :: .NET технология от и до
  • Распараллелил функцию в главном потоке (средствами Rx Framework, но это значения не имеет, пробовал и через BeginInvoke()):
    Цитата
    public void Start()
            {
                //...
                var startSession = Observable.ToAsync<string, string>(this.StartSession);
                startSession(credentionals.Login, credentionals.Password);
                //...
            }

    Она вызывает асинхронно долгоиграющий метод, который в конце должен кинуть эвент всем, кто его слушает:
    Цитата
    private void StartSession(string login, string password)
            {
                //...
                this.OnStarted(EventArgs.Empty);
            }

    Встал вопрос - как сделать так, чтоб метод this.OnStarted() вызывался в главном потоке? Не могу понять, возможно ли это вообще.
    Знаю, что обратная сторона Fork'а - Join, но при его помощи не выходит "слить" потоки обратно.

    Из многопоточности пока только освоил разделение, lock'и и ManualResetEvent's  :)

    PS: дело в том, что подписчики на событие Started - в основном GUI-компоненты, и они вредничают, если менять их не из главного потока. Переделывать UI на безопасные BeginInvoke() - много мороки, много кода уже написано.
    Еще раз пересмотрел все темы про потоки - ничего подобного там нет... Я так понял, это связано больше с параллелизмом, но ведь даже за всеми фреймворками по паралеллизму стоят рядовые инструменты, значит это можно сделать стандартными средствами.


  • Программирование :: С/С++
  • Имеется небольшое приложение на WTL, используется boost::thread. При выборе директории через стандартный диалог считывается информация о файлах внутри и выводиться в список, это сделано в отдельном потоке для того, что бы был доступен GUI. Предположим мне нужно выбрать другу директорию и считывать информацию о ее файлах этим же потоком, но ведь он уже выполняется. Как мне его прервать и запустить снова с параметрами другой директории?

    Итак для большей наглядности приведу несколько ф-ций:

    По нажатию на кнопочку "FILL" вызываеться диалог "Browse for folder"

    Код:
    LRESULT CMainDlg::OnFill(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
    {
    {
    TCHAR szPath[MAX_PATH];
    BOOL res = FALSE;

    LPMALLOC pMalloc;
    if (::SHGetMalloc(&pMalloc) == NOERROR)
    {
    BROWSEINFO bi;
    ::ZeroMemory(&bi,sizeof bi);
    bi.ulFlags = BIF_RETURNONLYFSDIRS;
    LPITEMIDLIST pidl = ::SHBrowseForFolder(&bi);
    if (pidl != NULL)
    {
    if (::SHGetPathFromIDList(pidl,szPath))
    {
    if (szPath) //если нажата кнопка ОК
    {
    TheThread (szPath); //вызывается отдельный поток

    }
    }
    }
    }
    return 0;
    }
    }

    вот что делает этот самый поток

    Код:
    int CMainDlg::TheThread (const CString& pth)
    {
    boost::thread my_thread(boost::bind(&CMainDlg::ReadFilesInf, this, pth)); //вызывается метод ReadFilesInf с параметром szPath
    return 0;

    }


    вот сам метод ReadFilesInf

    Код:
    int CMainDlg::ReadFilesInf (const CString& pth)
    {
    int userReplay;

    path p (pth.GetString());


    /* привожу для наглядности
    struct FileInformation
    {
    CString fName;
    CString fPath;
    CString size;
    CString time;
    };*/


    FileInformation information;

    EnterCriticalSection(&cs);

    recursive_directory_iterator end;
    recursive_directory_iterator it(p);
    while (it != end)
    {
    try
    {
    path curPath(*it);
    if (is_regular_file(curPath))
    {
    CTime w_time = last_write_time(*it);
    CString str = w_time.Format( L"%d, %b, %Y, %H:%M" );
    LPCTSTR timeCreation = str;

    std::wstring fileSizeStr = boost::lexical_cast<std::wstring>(file_size(curPath));
    std::wstring filePathStr = boost::lexical_cast<std::wstring>(curPath);


    information.fName = curPath.leaf().c_str();
    information.fPath = curPath.branch_path().c_str();
    information.size = fileSizeStr.c_str();
    information.time = timeCreation;

    list_.fileList_.push_back (information); //list_ это мой виртуальный список   fileList_ это вектор который хранит информацию о файлах
    list_.SetItemCountEx(list_.fileList_.size(), LVSICF_NOINVALIDATEALL);

    }
    ++it;
    }
    catch (boost::system::system_error const& e)
    {
    if (e.code().value() != ERROR_ACCESS_DENIED)
    {
    throw;
    }

    }
    }
    LeaveCriticalSection(&cs);

    return 0;
    }

    П.С. Господа приношу извинения если не достаточно доступно изложил суть вопроса.
  • Программирование :: Delphi
  • Помогите пожалйуста! Я только начала изучать Delphi в институте и много еще не знаю.  У меня маленькая база данных где отображены фамилия и имя в компоненте DBGrid. Есть панель DBNavigator, сделала поиск.  Тут все работает, добавляет, удаляет и так далее. Вот я хочу, чтобы при нажатии на какую - либо фамилию в DBGride открывалась форма с полной информацией о данном человеке. Как мне это сделать? Вот код программы:

    Код: (delphi)
    unit Unit1;

    interface

    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, DB, DBClient, ExtCtrls, DBCtrls, Grids, DBGrids, StdCtrls,
      ComCtrls;

    type
      TForm1 = class(TForm)
        DBNavigator1: TDBNavigator;
        DataSource1: TDataSource;
        ClientDataSet1: TClientDataSet;
        Edit1: TEdit;
        Button1: TButton;
        Edit2: TEdit;
        Label1: TLabel;
        Label2: TLabel;
        DBGrid1: TDBGrid;
        procedure Button1Click(Sender: TObject);
        procedure DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
          Field: TField; State: TGridDrawState);
      
      private

        { Private declarations }
      public
        { Public declarations }
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    if not ClientDataSet1.Locate(
        'Фамилия;Имя',
        VarArrayOf([Edit1.Text,Edit2.Text]),
       [loCaseInsensitive, loPartialKey])then
        ShowMessage('Запись не найдена');
    end;



    procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
      Field: TField; State: TGridDrawState);
    begin
     if gdFocused in State then
       with (Sender as TDBGrid).Canvas do
       begin
         Brush.Color := clFuchsia;
         FillRect(Rect);
         TextOut(Rect.Left, Rect.Top, Field.AsString);
       end;
    end;

    end.
  • Если использовать вот такой вариант:
    Код: (delphi)
    const pathImage    = 'D:\Image.jpg';
    var OnLoad: boolean = true;

    procedure TForm2.FormCanResize(Sender: TObject; var NewWidth,
      NewHeight: Integer; var Resize: Boolean);
    var
      ScaleForm: Double;
    begin

      if OnLoad then
      begin
        if Assigned(Image1.Picture) then
        begin
          NewWidth := Image1.Picture.Width;
          NewHeight := Image1.Picture.Height;
        end;
        OnLoad := false;
        Exit;
      end;

      ScaleForm := NewWidth / NewHeight;
      if ScaleForm > Scale then
      begin
        NewHeight := Trunc(NewWidth / Scale);
      end
      else
      begin
        NewWidth := Trunc(Scale * NewHeight);
      end;


    end;

    procedure TForm2.FormCreate(Sender: TObject);
    begin
      if (FileExists(pathImage)) then
        Image1.Picture.LoadFromFile(pathImage);

      Scale := Image1.Picture.Width / Image1.Picture.Height;
    end;
    Свойства TImage;
    (http://s53.radikal.ru/i140/1108/16/0c1b09f0d685.jpg)

    То при запуске программы вид:
    (http://s44.radikal.ru/i106/1108/32/38c29359e143.jpg)

    Если попробовать прижать мышью заголовок формы и оттащить окно (можно еще так: мышку поместить в угол формы, собираясь изменить размер и при прикосновении произойдет аналогичное), то сразу станет так:
    (http://i050.radikal.ru/1108/bf/d09c5f28eed7.jpg)
    вот это как раз то, что и хотелось бы получить - именно такой вид. Некий рефреш происходит?
    Но каким образом сделать с самого начала подобное растяжение по всему пространству в форме?

    Delphi XE
  • Программирование :: Программирование 1С
  • Приветствую всех!

    Не пойму куда правильно вставить СГРУППИРОВАТЬ ПО ... Везде выдает ошибки: то к группе не относится то еще что то

    Код:
    Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    | РеализацияТМЗОбороты.Регистратор КАК ДокументДвижения,
    | РеализацияТМЗОбороты.Склад КАК Склад,
    | РеализацияТМЗОбороты.Номенклатура КАК Номенклатура,
    | РеализацияТМЗОбороты.ДоговорКонтрагента КАК ДоговорКонтрагента,
    | РеализацияТМЗОбороты.ДоговорКонтрагента.Владелец КАК Контрагент,
    | Выбор Когда (РеализацияТМЗОбороты.СуммаОборот)>0 Тогда РеализацияТМЗОбороты.СуммаОборот
    |иначе 0 Конец КАК Сумма,
    | Выбор Когда (РеализацияТМЗОбороты.СуммаОборот)< 0 Тогда РеализацияТМЗОбороты.СуммаОборот
    |иначе 0 Конец КАК СуммаВозвратов,
    | РеализацияТМЗОбороты.СуммаОборот Как СуммаСВозвратами,
    | РеализацияТМЗОбороты.НДСОборот КАК НДС,
    | РеализацияТМЗОбороты.АкцизОборот КАК Акциз,
    | РеализацияТМЗОбороты.СтоимостьОборот КАК Стоимость,
    | РеализацияТМЗОбороты.КоличествоОборот КАК Количество,
    | РеализацияТМЗОбороты.СуммаОборот - РеализацияТМЗОбороты.НДСОборот - РеализацияТМЗОбороты.АкцизОборот КАК СуммаБезНалогов,
    | РеализацияТМЗОбороты.СуммаОборот - РеализацияТМЗОбороты.НДСОборот - РеализацияТМЗОбороты.АкцизОборот - РеализацияТМЗОбороты.СтоимостьОборот КАК Профит,
    |   (РеализацияТМЗОбороты.СуммаОборот - РеализацияТМЗОбороты.НДСОборот - РеализацияТМЗОбороты.АкцизОборот)/РеализацияТМЗОбороты.КоличествоОборот КАК Сумма1,
    | РеализацияТМЗОбороты.СуммаОборот/РеализацияТМЗОбороты.КоличествоОборот КАК Сумма2";

    Если мИспользоватьПартии Тогда
    Текст = Текст + ",
    | РеализацияТМЗОбороты.Партия Как Партия";
    КонецЕсли;

    Текст = Текст + "
    | {ВЫБРАТЬ
    | РеализацияТМЗОбороты.Организация.* КАК Организация,
    | РеализацияТМЗОбороты.СчетУчета.* КАК СчетУчета,
    | РеализацияТМЗОбороты.Номенклатура.* КАК Номенклатура,
    | РеализацияТМЗОбороты.ДоговорКонтрагента.Владелец.* КАК Контрагент,
    | РеализацияТМЗОбороты.ДоговорКонтрагента.* КАК ДоговорКонтрагента,";

    Если мИспользоватьПартии Тогда
    Текст = Текст + "
    | РеализацияТМЗОбороты.Партия.* КАК Партия,";
    КонецЕсли;

    Текст = Текст + "
    | РеализацияТМЗОбороты.Склад.* КАК Склад,
    | РеализацияТМЗОбороты.Период Как Период,
    | НачалоПериода(Период, День) КАК ПериодДень ,
    | НачалоПериода(Период, Неделя) КАК ПериодНеделя ,
    | НачалоПериода(Период, Декада) КАК ПериодДекада ,
    | НачалоПериода(Период, Месяц) КАК ПериодМесяц ,
    | НачалоПериода(Период, Квартал) КАК ПериодКвартал ,
    | НачалоПериода(Период, Полугодие) КАК ПериодПолугодие ,
    | НачалоПериода(Период, Год) КАК ПериодГод
    |  //СВОЙСТВА
    |}
    |ИЗ
    | РегистрНакопления.РеализацияТМЗ.Обороты(
    | &ДатаНач,
    | &ДатаКон,";

    Если мИспользоватьПартии Тогда
    Текст = Текст + "
    | Регистратор,{Организация.*, СчетУчета.*, ДоговорКонтрагента.*, Номенклатура.*, Склад.*, ДоговорКонтрагента.Владелец.* КАК Контрагент, Партия.*}) КАК РеализацияТМЗОбороты";
    Иначе
    Текст = Текст + "
    | Регистратор,{Организация.*, СчетУчета.*, ДоговорКонтрагента.*, Номенклатура.*, Склад.*, ДоговорКонтрагента.Владелец.* КАК Контрагент}) КАК РеализацияТМЗОбороты";
    КонецЕсли;

    Текст = Текст + "
    | //СОЕДИНЕНИЯ
    |{ГДЕ
    | Период.* Как Период,
    | Склад.*,
    | Организация.*,
    | Номенклатура.*,
    | СчетУчета.*,
    | ДоговорКонтрагента.Владелец.* КАК Контрагент,
    | ДоговорКонтрагента.*,
    | Регистратор.* КАК ДокументДвижения";

    Если мИспользоватьПартии Тогда
    Текст = Текст + ",
    | Партия.*";
    КонецЕсли;

    Текст = Текст + "
    |  //СВОЙСТВА
    |  //КАТЕГОРИИ
    |}";

    Текст = Текст + "
    |{УПОРЯДОЧИТЬ ПО
    | Склад.*,
    | организация.*,
    | Номенклатура.*,
    | СчетУчета.*,
    | ДоговорКонтрагента.*,
    | Контрагент.*,";

    Если мИспользоватьПартии Тогда
    Текст = Текст + "
    | Партия.*,";
    КонецЕсли;

    Текст = Текст + "
    | Период,
    | ДокументДвижения.*
    |  //СВОЙСТВА
    |}

    |ИТОГИ
    | СУММА(Сумма),
    | СУММА(СуммаВозвратов),
    | СУММА(СуммаСВозвратами),
    | СУММА(НДС),
    | СУММА(Акциз),
    | СУММА(Стоимость),
    | СУММА(Количество),
    | СУММА(СуммаБезНалогов),
    | СУММА(Профит),
    | СУММА(Сумма1),
    |   СУММА(Сумма2)
    |ПО
    | ОБЩИЕ
    |{ИТОГИ ПО
    | Склад.*,
    | Организация.*,
    | Номенклатура.*,
    | СчетУчета.*,
    | Контрагент.*,
    | ДоговорКонтрагента.*,
    | ДокументДвижения.*,";

    Если мИспользоватьПартии Тогда
    Текст = Текст + "
    | Партия.*,";
    КонецЕсли;

    Текст = Текст + "
    | НачалоПериода(Период, День) КАК ПериодДень ,
    | НачалоПериода(Период, Неделя) КАК ПериодНеделя ,
    | НачалоПериода(Период, Декада) КАК ПериодДекада ,
    | НачалоПериода(Период, Месяц) КАК ПериодМесяц ,
    | НачалоПериода(Период, Квартал) КАК ПериодКвартал ,
    | НачалоПериода(Период, Полугодие) КАК ПериодПолугодие ,
    | НачалоПериода(Период, Год) КАК ПериодГод
    |  //СВОЙСТВА
    | }";

    Вот здесь делю суммы на количество(ниже отрывок из кода), оказалось так что делится все на каждое перебираемое количество, а нужно чтобы делил на суммированное количество

    Код:
     |   (РеализацияТМЗОбороты.СуммаОборот - РеализацияТМЗОбороты.НДСОборот - РеализацияТМЗОбороты.АкцизОборот)/РеализацияТМЗОбороты.КоличествоОборот КАК Сумма1";

    Пробую через СУММА(РеализацияТМЗОбороты.КоличествоОборот), но для этого нужно прописывать СГРУППИРОВАТЬ ПО, вот и не пойму куда ее вписать :)


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

    Код:
    ЗапросТЧ.Текст = "ВЫБРАТЬ
                     | РасходТаблРасход.НомерСтроки КАК НомерСтроки,
                     | РасходТаблРасход.Товар КАК Товар,
                     | СУММА(РасходТаблРасход.Количество) КАК Количество,
                     | РасходТаблРасход.Единица,
                     | СУММА(РасходТаблРасход.Цена) КАК Цена,
                     | СУММА(РасходТаблРасход.Сумма) КАК Сумма,
                     | РасходТаблРасход.НДС
                     |ИЗ
                     | Документ.Расход.ТаблРасход КАК РасходТаблРасход
                     |ГДЕ
                     | РасходТаблРасход.Ссылка = &ТекДок
                     |
                     |СГРУППИРОВАТЬ ПО
                     | РасходТаблРасход.НомерСтроки,
                     | РасходТаблРасход.Товар,
                     | РасходТаблРасход.Единица,
                     | РасходТаблРасход.НДС
                     |
                     |УПОРЯДОЧИТЬ ПО
                     | НомерСтроки
                    [font=Verdana] |ИТОГИ
                     | СУММА(Сумма) [/font]
                     |ПО
                     | ОБЩИЕ";

    В таблицу по циклу выгружаются данные из запроса, а сверху выходить итоговая сумма по колонке Сумма. Как этот итог опустить вниз таблицы? Можно ли как-то "Итог" присвоить какой-нибудь переменной, чтобы ее потом в параметр печатной области вставить?


    спс за внимание!

  • Программирование :: Программирование 1С :: 1С 7.x
  • Здравствуйте, в 1с v7 Торговля и склад, в справочнике цен делаю полное наполнение по группе товаров, проходит расчет остатков--и останавливается на такой ошибке
    Код:
    Документ = ДвижениеРегистраОстатков №   105 от 31.12.09
    Если Запрос.Товар=Док1.Товар
    {Справочник.Цены3.ФормаСписка.ФормаСписка.Модуль(1190)}: Поле агрегатного объекта не обнаружено (Товар)

    Подскажите в чем проблема пожалуйста?!
  • Операционные системы :: Windows
  • В ХР не работает связь модема и компа,если модем настроен роутером,самопределяет IP,а в 2000 и в 7 работает,в чем может быть дело?
  • Направления программирования :: Drivers
  • ObOpenObjectByName() возвращает код ошибки 0хс0000024 :

    Код:
    RtlInitUnicodeString(&obj_name, L"\\Device\\Tcp");

    InitializeObjectAttributes(&objAttr, &obj_name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

    status = ObOpenObjectByName(&objAttr, NULL, KernelMode, NULL, NULL, NULL, &hObject);
    if (!NT_SUCCESS(status))
    {
    DbgPrint("[Driver entry]: ObOpenObjectByName error!\n %x",status);
    }

    Поможет кто-нибудь понять в чём дело?
  • Направления программирования :: Web
  • Добрый день, уважаемые! Много букв, но по другому не получается...

    Разрабатываю тизерную сеть, и вот столкнулся с такой проблемой...

    Оказывается очень распространено сейчас - накрутка различных тизерных/баннерных/рекламных сетей. При чем делается это очень различными способами. Веб-мастара кликают по своим тизерам на своих сайтах и получают бабло, а у рекламодателей деньги на ветер, конверт покупок нулевой.

    Хотелось бы услышать методы борьбы с такими накрутчиками...

    Понятно что первое приходит на ум - это установка cookies на время, далее блокировка по хэшу IP + User_agent, или возможно просто по IP на какое-то время. Непринимать траф с известных IP-proxy, анонимайзеров, учитывать геотаргетинг, это все понятно.

    Но как мы знаем - cookies - это не проблема, User_agent, HTTP_REFERER - это всего лишь заголовки и легко меняются.

    А по поводу IP - здесь тоже есть особые технологии...

    Уже давно есть такие системы, называемые САР - Системы Активной Раскрутки, когда за кредиты (выкупаются за ничтожные деньги) вы можете отдавать на раскрутку свой сайт, когда часть пользователей этой САР смотрят ваш сайт около минуты и получают деньги.

    Но также есть разработки "продвинутых САР", которые отличаются вот чем:

    - особые технологии просмотра сайта через Flash позволяют полностью скрыть, что просмотр идет с САР
    - есть набор определенных команд, которые может исполнять эта САР.

    Можно выставить сайт в режим автосерфинга, тогда пользователям даже не нужно смотреть сайт, можно свернуть браузер (или программу), и будут автоматически просматриваться сайты рекламодателей этой САР, но команды будут работать.

    По поводу команд - это, допустим, вставить любой JS-код, при просмотре через САР. Таким образом JS-код может найти через DOM нужные ссылки на тизеры, и кликнуть случайно в 5% случаях допустим... Или даже сгенерить iframe динамически и подгрузить этот линк...

    Еще есть команды - навести курсор в определенные координаты, кликнуть по объекту. Т.е. полная имитация действий пользователя

    Нашел людей, которые помогают настроить эти команды, скрипты... Накручивают легко даже Goggle Adsense, РСЯ Директ. И вообще, способов борьбы с этим, как я понимаю просто не существует!

    Единственные вещи, которые приходят на ум:

    1) при открытии сайта рекламодателя (клик на тизере) делать что-то типа простой нераздражающей каптчи, и только потом переход на сайт рекламодателя и засчет как клик

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

    1 - раздражать будет посетителей, а также опять будут придумывать средства как это обойти... Хотя каптча какая-нибудь на флэш - автоматом не обойдется, но будет раздражать... И также найдутся другие способы - сервисы с оплатой за задания - зайди, кликни, введи каптчу...
    2 - сложно в реализации, т.к. рекламодатели не всегда рекламируют свои сайты, а допустим ПП (партнерские программы), но они не всегда предоставляют детальную статистику - по каким УРЛ-ам был переход...

    Хотелось бы услышать ваше мнение. У кого какие мысли по этому поводу?

    Спасибо.

А теперь прощаемся с Вами до следующего выпуска.


С уважением, команда Клуба.


В избранное