Скоро некоторые из нас пойдут отдавать свои голоса за очередных кандидатов в депутаты. Депутаты являются нашими представителями и им мы предоставляем право принимать некоторые законодательные решения за нас. В данных условиях логично выбирать тех кто делает свой выбор также как и мы.


Голоса депутатов находятся на vote.duma.gov.ru. Нам остаётся проголосовать за важные для нас законопроекты в соответствии со своим видением и получить рейтинг на основе которого и делать выбор на выборах.


Я выбрал наименее затратный путь и написал JavaScript расширение для Chrome. Работа с ним организованна через консоль браузера (Ctrl + Shift + J). Бонусом я протестировал поддержку русского языка в JavaScript без препроцессоров.


Под катом вас ждёт код с комментариями и комментарии к статье.



В папке "vote" три файла "manifest.json", "insert.js", "script.js" в кодировке UTF-8 (без BOM).


Код:


Файл "manifest.json":


{ 
  "manifest_version": 2,
  "name": "Твой кандидат",
  "description": "Расширение для подсчёта персонального рейтинга депутатов на vote.duma.gov.ru",
  "version": "1.0",
  "content_scripts": [
    {
      "matches": [ "http://vote.duma.gov.ru/*" ],
      "js": [ "insert.js" ],
      "run_at": "document_end"
    }
  ],
  "web_accessible_resources": [
    "script.user.js"
  ]
} 

Часть манифеста "web_accessible_resources" даёт доступ странице загружать и использовать перечисленные в ней файлы плагина. "script.js" это основной скрипт в котором вся логика.


Хром не даёт прямого доступа расширениям к переменным страницы. Мы внедряем свой скрипт("script.js") в саму страницу при помощи "insert.js".


Файл "insert.js":


var script   = document.createElement('script');
script.type  = 'text/javascript';
script.src   = chrome.extension.getURL("script.user.js");
script.async = 1;
document.head.appendChild(script);

Файл "script.user.js":


// ==UserScript==
// @name Твой кандидат
// @description Расширение для подсчёта персонального рейтинга депутатов на vote.duma.gov.ru
// @author ivan386
// @license MIT
// @version 1.0
// @run-at document-end
// @include http://vote.duma.gov.ru/*
// ==/UserScript==

(function() {
    'use strict';

var вывести = function( текст ){
    console.log( текст );
    document.querySelector( "#текст" ).innerText = текст;
};

var голосовать = function( ваш_голос )
{
    if ( typeof deputiesData !== 'undefined' )
    {
        // Для хранения рейтинга и остальных данных депутатов используется localStorage
        var депутаты = JSON.parse( localStorage.getItem( "депутаты" ) || "{}" );

        // В переменной deputiesData храняться голоса депутатов за текущий закнопроект и другие данные.
        deputiesData.forEach( function( депутат )
        {
            var ls_депутат = депутаты[ депутат.url ];

            // Восстанавливаем сохранённый рейтинг или устанавливаем 0
            депутат.рейтинг = ( !ls_депутат ) ? 0 : ls_депутат.рейтинг;

            // Восстанавливаем статистику
            депутат.статистика = ( !ls_депутат ) ? {} : ( ls_депутат.статистика || {} );

            // Копируем имя
            депутат.имя = депутат.sortName;

            // Сохраняем статистику голосов депутатов на будущее.
            if ( typeof( депутат.статистика[ депутат.result ] ) === 'undefined' )
                депутат.статистика[ депутат.result ] = 1;
            else
                депутат.статистика[ депутат.result ] ++;

            депутат.количество = 0
            for ( var голоса in депутат.статистика )
                депутат.количество += депутат.статистика[голоса];

            // У каждого депутата есть ссылка с его ID на результаты его голосования.
            // Используем её как уникальный идентификатор.
            депутаты[ депутат.url ] = депутат;

            // Результат голосования каждого депутата лежит в переменной result
            // Соответствия взяты из функции renderer скрипта на странице с результатами голосования на vote.duma.gov.ru.
            // Значение -1 соответствует голосу "За"
            // Значение 0 соответствует голосу "Воздержался"
            // Значение 1 соответствует голосу "Против"
            // Значение 2 соответствует голосу "Не голосовал"

            // Меняем рейтинг депутата в соответствии с нашим выбором.
            депутат.рейтинг += ( депутат.result == ваш_голос ) ? 1 : -1;
        } );

        //Сохраняем рейтинг и другие данные в localStorage
        localStorage.setItem( "депутаты" , JSON.stringify( депутаты ) );

        вывести( "голос " + ( ваш_голос == -1 ? "За" : "Против" ) + " принят" );
    }
    else
        вывести( "на странице не найдено результатов голосования депутатов за законопроект" );

};

var за = function()
{
    // Значение -1 соответствует голосу "За"
    return голосовать( -1 );
};

var против = function()
{
    // Значение 1 соответствует голосу "Против"
    return голосовать( 1 );
};

var по_рейтингу = function( список )
{
    var список_по_рейтингу = [];
    var вывод = [];

    for ( var ключ in список )
        список_по_рейтингу.push( список[ ключ ] );

    список_по_рейтингу.sort( function( первый, второй )
    {
        // Сортируем в порядке убывания рейтинга
        return второй.рейтинг - первый.рейтинг;
    } );

    список_по_рейтингу.forEach( function( элемент )
    {
        // Выводим результаты в консоль
        вывод.push( элемент.имя + ": " + элемент.рейтинг + ( элемент.количество ? " (" + элемент.количество + ")" : "" ) );
    } );

    return вывод.join( "\n" );
};

var рейтинг_депутатов = function()
{
    var депутаты = JSON.parse( localStorage.getItem( "депутаты" ) || "{}" );

    вывести( по_рейтингу( депутаты ) );
};

var рейтинг_партий = function()
{
    var депутаты = JSON.parse( localStorage.getItem( "депутаты" ) || "{}" );
    var партии = {};

    for ( var идентификатор in депутаты )
    {
        var депутат = депутаты[ идентификатор ];
        var партия = партии[ депутат.factionCode ];
        if ( партия )
        {
            // Рейтинг партии складывается из рейтинга депутатов.
            партия.рейтинг += депутат.рейтинг;
            партия.количество ++;
        }
        else
            партии[ депутат.factionCode ] = { имя: депутат.faction , рейтинг: депутат.рейтинг , количество: 1 };
    }

    вывести( по_рейтингу( партии ) );
};

var окно = (typeof unsafeWindow === 'undefined') ? window : unsafeWindow;

document.body.insertBefore( document.createElement( "div" ) , document.body.firstChild ).innerHTML = 'Твой кандидат:\n <button onclick="за()">За</button>\n <button onclick="против()">Против</button>\n <button onclick="рейтинг_партий()">Рейтинг партий</button>\n <button onclick="рейтинг_депутатов()">Рейтинг депутатов</button>\n <div id="текст"></div>';

окно.за = за;
окно.против = против;
окно.рейтинг_депутатов = рейтинг_депутатов;
окно.рейтинг_партий = рейтинг_партий;

if ( typeof( окно.deputiesData ) !== 'undefined' )
    deputiesData = окно.deputiesData;

вывести( "за() - проголосовать за\nпротив() - проголосовать против\nрейтинг_депутатов() - выводит текущий рейтинг депутатов в соответствии с вашими голосами\nрейтинг_партий() - выводит текущий рейтинг партий в соответствии с вашими голосами\n" );

})();

Установка


  1. Копируем папку "vote" с содержимым на локальный диск.
  2. В браузере Chrome открываем "chrome://extensions/" или "Главное Меню > Дополнительные инструменты > Расширения"
  3. Ставим галочку "Режим разработчика"
  4. Нажимаем "Загрузить распакованное расширение..."
  5. Находим и выбираем папку "vote" со скриптами.
  6. Нажимаем ОК.

Использование


Голосуем

  1. Заходим на страницы с голосами депутатов на vote.duma.gov.ru.
    Например: http://vote.duma.gov.ru/vote/95967 (ссылка взята здесь)
  2. Открываем консоль браузера (Ctrl + Shift + J).
    3.1. Если против пишем:


    против()

    3.2. Если за пишем:


    за()

  3. Нажимаем Enter

Получаем рейтинг

  1. Заходим на любую страницу vote.duma.gov.ru.
  2. Открываем консоль браузера (Ctrl + Shift + J) ещё не открыта.
    3.1. Для вывода рейтинга депутатов:


    рейтинг_депутатов()

    3.2. Для вывода рейтинга партий:


    рейтинг_партий()

  3. Нажимаем Enter

Либо можно воспользоваться кнопками вверху страницы.


Результат


В результате каждый пользователь этого скрипта получает свой рейтинг депутатов и партий в соответствии со своим выбором и выбором депутатов.


Пример рейтинга депутатов:


Иванов Иван Иванович: 5
Петров Пётр Петрович: 0
Сидоров Владимир Владимирович: -5

Пример рейтинга партий (в скобках количество депутатов):


Пиастрская: 100 (10)
Фарианская: 0 (1)
АнтиПиастрская: -100 (1)

Все имена и события вымышлены. Совпадения случайны.


Заключение


Надеюсь этот скрипт поможет делать более осознанный выбор своего представителя в законодательной власти. А заодно и покажет пример написания расширения для анализа данных на государственных сайтах .


Об ошибках прошу писать в личные сообщения.


Источники


  1. Создаём своё расширение для Google Chrome
  2. Как запускать расширения Хрома не из магазина WebStore
  3. Учимся писать userscript'ы
  4. Скрипты на GitHub
  5. Система анализа результатов голосований на заседаниях Государственной Думы
Поделиться с друзьями
-->

Комментарии (54)


  1. Miraage
    29.07.2016 17:15
    +25

    Вот это импортозамещение в названии переменных/функций!


    1. ivan386
      29.07.2016 17:29

      Главное что работает без препроцессора благодаря Unicode.


      1. 0x9d8e
        29.07.2016 18:23

        У меня не работает. Одни сплошные is not defined, сначала на «deputiesData», затем на «против», при том, что расширение как-бы работает.


        1. ivan386
          29.07.2016 18:25

          за() и против() работают только на страницах результатов голосования. Попробуйте здесь: http://vote.duma.gov.ru/vote/95967


          1. 0x9d8e
            29.07.2016 18:30

            Теперь работает. Дело было в том, что увидев под заголовком «Файл insert.js» точно такой-же удивился почему два куска кода из одного файла под двумя одинаковыми заголовками, перепроверил, но сделал «по ману». Не знаю, или в статье сначала ошибка была, или я глючу.


            1. ivan386
              29.07.2016 18:31

              Была ошибка. Я исправил.


              1. 0x9d8e
                29.07.2016 18:55
                +1

                Спасибо, очень пригодится. Тем более что не получается (да и не хочется) следить кто там как голосует, а выбор хочется сделать обоснованный.
                Жаль нельзя делать запросы на выборку законопроектов. Скажем выбрать голосования по запретительныем и ужесточающим нововведениям, где категория != ПДД. Всё равно придётся всё это читать, но уже полегче.


    1. stas404
      29.07.2016 19:28
      -2

      Не подсказывайте депутатам идеи для новых законопроектов.


    1. Old_Chroft
      31.07.2016 10:50

      Адинэсники смотрят на вас с недоумением…
      Кстати, лет 8 (восемь!) назад видел CSS, где классы и id на русском — и что удивительно, даже всеми проклинаемый в то время IE6 его вполне переваривал.


      1. Mirnin
        01.08.2016 16:37

        Адинэсники заметили неладное только когда начали читать комментарии. Сам адинэсник, читал будто так и должно быть…


  1. Zenitchik
    29.07.2016 18:19
    +3

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


    1. ivan386
      29.07.2016 18:31
      +1

      Позже продумаю и накидаю кнопочки и вывод списка на страницу. Или это может кто-то сделать за меня.


    1. ivan386
      30.07.2016 12:31

      Сделал


  1. pengyou
    29.07.2016 18:38
    +3

    Осень близко, волнуются эректораты.


  1. Jabher
    29.07.2016 19:07
    +3

    лопни мои глаза!


  1. Alexey2005
    29.07.2016 19:57

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


    1. arvitaly
      29.07.2016 21:05
      +3

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


      1. AVX
        29.07.2016 21:42

        Объём блокчейна будет неимоверно большим. Даже технически будут сложности.


        1. arvitaly
          29.07.2016 23:40

          Мне кажется, количество документов не соизмеримо с количество денежных транзакций?


          1. AVX
            29.07.2016 23:58
            +2

            Вы недооцениваете бюрократию :)


  1. Aleksandr_Kukolev
    29.07.2016 20:03
    -3

    Что то не так с подсчетом процентов. 53.1 + 0.4 = 53.5, а ни как не 53.6


    1. Evgeny42
      29.07.2016 21:12
      +4

      Ну очевидно же, что для показа округляется, и результат округляется после суммирования не округленных процентов.


  1. prostofilya
    29.07.2016 20:11

    Глянул статистику, везде против 1-2 человека, а то и ноль. Будто перед голосованием кнопку просто потестили на работоспособность.


    1. prostofilya
      29.07.2016 20:13
      +3

      или пока одного из депутатов нет, его сосед по парте жмёт за него, чтоб его с работы выперли


    1. Alexey2005
      29.07.2016 20:22

      В таких условиях нужно изменить способ расчёта рейтинга, чтоб учитывать отсутствующих депутатов. Ведь если депутат не явился на голосование, он тем самым саботировал принятие данного закона (если бы не явились все 100%, закон бы не приняли вовсе).


      1. Denai
        30.07.2016 03:49

        Так депутатам вроде как и нельзя «не явиться»


      1. dmitry_ch
        30.07.2016 13:13

        Так они там друг за друга голосуют.

        Быстрый поиск такое вот дает: https://www.youtube.com/watch?v=GGj9ZsYhNzA уж не знаю, чего он там «прыгает», но выглядит не очень приглядно.

        Так что на голосовании нужно что-то большее, чем просто кнопка или просто карточка (они «ответственному» будут их сдавать, и тот бегать с пачкой). Ну не сетчатку же глаза сканить в процессе голосования?


        1. sim31r
          30.07.2016 20:15
          +1

          Так они там друг за друга голосуют.

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


          1. Old_Chroft
            31.07.2016 11:03

            [...]присутствие на рабочем месте всех представителей партии такая же формальность[...]
            А так хочется видеть вменяемых людей, которые принимают решения за всю страну…


          1. Zenitchik
            31.07.2016 11:59

            Не всегда. Даже по спискам можно увидеть, что за некоторые законопроекты некоторые партии голосуют в разнобой.


    1. Evgeny42
      29.07.2016 21:13

      Это люди которым нечего в жизни терять или скрывать :)


    1. Zenitchik
      29.07.2016 22:41
      +2

      Ну, где как. Впечатление складывается такое, что демократы, не считая ЛДПР, только в КПРФ остались. А остальные — за закручивание гаек.


  1. AVX
    29.07.2016 22:00
    +2

    Да, это лучше, чем ничего. Но далеко от массового использования. Даже вот мне, как достаточно технически грамотного, просто лень лазить в консоль хрома и что-то там делать. А если этим будут пользоваться 2,5 гика вместо тысяч или миллионов обычных пользователей — толку не прибудет.
    Как я вижу реализацию: делается сайт «персональный рейтинг депутатов» (или как-то так, не сильно важно), там вместо этого JS скрипта всё выполняется на сервере (php, или что ещё), пользователю выводится список законов или других актов, принимаемых госдумой (поправки к законам, и т.п.), и предлагается проголосовать: за против воздержался. После того, как проголосовал по интересующим вопросам (или всем, что довольно тяжело будет сделать сразу, их очень много), пользователю будет выведено: список депутатов (и из какой они партии), с которыми Ваше мнение совпадает больше всего (в порядке убывания), список партий, аналогично (алгоритмы нужно ещё продумать, это только задумка). Базу данных каждого пользователя хранить локально на его же компе (для безопасности), и его же предупреждать достаточно заметной ссылкой на соответствующую страницу с разъяснениями, что хранить эти данные на сайте — не лучшая затея, т.к. и на сайт будут давить спецслужбы чтобы доступ к этим данным получить, да и пользователю спокойнее. Хотя, можно оставить и какую-то регистрацию и хранить данные на сайте, чтобы пользователь мог авторизоваться с разных мест, и данные не были привязаны к компу, но с соответствующими рисками безопасности.
    Далее. Можно выводить статистику самую разную: рейтинг депутатов (публичный, персональный), рейтинг партий аналогично, потенциальные друзья по политическим интересам (если они зарегистрировались и указали свои, например, профили в соцсетях, и разрешили это в настройках), а потом (когда база пользователей наберётся достаточно большая) можно прикрутить и собственно голосование за самих депутатов. И кто знает, может быть, такая система сможет быть весомой и реальной альтернативой официальным выборам…
    А если позже реализовать подобное на госуслугах — то ещё один шаг к электронному правительству, и больше шансов на реально честные выборы.

    P.S. простите за излишнюю политизированность, если есть.


    1. vstr
      30.07.2016 20:54
      +1

      Дичайше плюсую. Давно пора сделать подобный ресурс с объективной информацией о депутатах, а именно — о пофамильном голосовании за различные законы, будь то вредительские инициативы в ИТ-отрасли или, к примеру, поборы на капремонт. Искать информацию на официальном сайте госдуры очень неудобно, а ЕР-овцы в своей агитации естественно умалчивают о том, как они голосовали за идиотские законы.


      1. komjah
        31.07.2016 10:47
        +1

        А зачем что-то говорить у них большинство в думе 53%, так что это именно они (ЕР) или принимают закон или отклоняют.

        Что же касается рейтинга еще хотелось бы видеть граждан вносящих откровенно идиотские инициативы.


    1. Zenitchik
      31.07.2016 12:03

      Есть проблема. Кто-то должен ещё расшифровывать законопроекты. Иначе в каждый законопроект вникать по часу придётся, чтобы осмысленно проголосовать. И к этому кому-то должно быть доверие (это вообще нереально).


      1. sim31r
        31.07.2016 22:18

        Интересное наблюдение. В данной области тоже присутствует разделение труда и нужен специалист в области законов, которому можно доверять. Но изначально таким специалистом и является депутат со своими помощниками, который принимает решения в интересах своих избирателей, не требуя от них никакого участия вообще. Получается что так, что так, нужно доверенное лицо, после сокращения всех переменных получаем исходные начальные условия.
        Пример из жизни типичный, избираются депутаты от КПРФ, но после избрания переходят в более выгодную им партию власти (в оппозиции «пенсионерской» у них перспектив меньше), случаи не единичные.
        Вангую, что примерно так же будет и с доверенным лицом/сайтом, после того, как наберет ХХХ тысяч подписчиков, на него обратят внимание заинтересованные лица и подстроят трактовку в свою пользу, или займется партия власти, или оранжевые силы третьего не дано, высоки ставки и сильны игроки (по моим наблюдениям даже geektimes.ru не избежал данной участи в силу популярности). В итоге, лучше с политикой не связываться вообще, расклад сил по существу не изменить.
        Но данное решение можно перенести в другие области, более спокойные. Например в область медицины. От выбора врачей (они поважнее депутатов, от врачей напрямую зависят жизни), до подбора дешевых аналогов лекарств (многие врачи в сговоре с фармацевтами и впаривают специфические лекарства, дорогие, а часто и вредные в данном случае).
        Что-то подобное работает в области онлайн продаж, в реальном времени поддерживается рейтинг продавцов, магазинов и товаров.



  1. deNULL
    29.07.2016 22:12
    +1

    Не совсем понимаю — почему было не опубликовать расширение в Chrome Web Store?

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


    1. ivan386
      30.07.2016 13:00
      +3

      Там 5$ хотят, иконку рисовать надо и регистрироваться в платёжной системе.


      1. Zenitchik
        31.07.2016 12:05

        А почему бы тогда не запаковать приложение, чтобы оно ставилось единым для chromium-браузеров образом? У кого Гугл-Хром — пусть незапакованное подключают, а у меня-то Vivaldi никаких проблем не создаёт.


      1. NickKolok
        02.08.2016 21:56

        У меня при разработке расширения возникла аналогичная проблема. По итогам обсуждения на гитхабе сделали юзерскрипт. Пример инструкции по установке. Настоятельно рекомендую.


        1. ivan386
          03.08.2016 17:13

          Уже сделал. Файл "script.user.js" можно теперь в Greasemonkey и Tampermonkey добавить.


  1. Survtur
    30.07.2016 20:49

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

    Но я очень хочу воспользоваться возможностью найти депутата, соответствующего моим ожиданиям. И уверен, что сайт будет очень популярным. Всё-таки думающих людей у нас много.


  1. Arepo
    31.07.2016 13:35
    +1

    Скачал результату по всем голосованиям и выложил в гитхаб здесь: https://github.com/data-dumaGovRu/vote
    Общий размер получился 1438Мб в форматированном JSON.


    1. ivan386
      31.07.2016 14:43

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


      1. Arepo
        31.07.2016 14:55

        Судя по всему не так всё просто: парни из ЕР, похоже, вообще не голосуют против, вместо этого они вообще не голосуют целой фракцией и вопрос не набирает кворума.


        1. ivan386
          31.07.2016 15:03

          Интересно какой в этом смысл?


          1. Arepo
            31.07.2016 15:18

            Ничего не надо делать, а то пока весь зал оббегаешь, за всех проголусуешь… А так, если кворума нет, то вопрос автоматически отклоняется


      1. sim31r
        31.07.2016 22:39

        Ну я как представитель из области IT ничего против «прогульщиков» не имею. Можно работать удаленно за троих, а можно просиживать в офисе создавая видимость работы. Странно что столь категоричное мнение повторяется на IT ресурсе. За политикой и депутатами не слежу вообще. Может там есть какие-то нюансы, но со стороны кажется, пусть работают удаленно, лишь бы была обществу польза. Удаленно можно более детально вникнуть в суть принимаемых законов или заняться местечковыми делами с избирателями, у некоторых это под 10 000 км от «кнопки».
        И опять же, новости из области развития ИИ подразумевают, что скоро депутаты останутся не у дел, специализированный ИИ может сформировать более точные законы и намного быстрее. Пример налог, НДС, может быть в разных случаях от 0% до 20%, выбор на первый взгляд кажется хаотичным. Сомневаюсь что число было оптимизировано до третьего знака после запятой, а в масштабах страны это миллиарды рублей. Во всех почти сетевых магазинах цена каждого товара оптимизируется весьма сложным алгоритмом до копеек в реальном времени, а в масштабах государства указания в стиле «плюс минус километр»


  1. Igogo2012
    31.07.2016 17:00
    +1

    То чувство, когда 1C программист взялся за JS


    1. ivan386
      31.07.2016 17:55

      Это лёгкая стадия. Вот тяжёлый вариант: JavaScript по-русски — pycckuu.js


  1. KaaPex
    02.08.2016 10:19

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


    1. ivan386
      02.08.2016 17:26

      Адаптировал для Greasemonkey и Tampermonkey а делать красиво прошу самостоятельно.