Wrong declaration of new Template. Backtrace:
/var/www/barzha.top/controller/Controller.php:1195 Template->__construct(view/modern, )<br>/var/www/barzha.top/controller/Controller_User.php:359 Controller->getTariffs(Template Object
(
    [srctemplate] => <div class="user_channel_block">
    <div class="container">
        <div class="row">
            <div class="col-sm-2"></div>
            <div class="col-sm-10">
                <div class="chs_info">
 <div class="chs_line">
  <div class="row">
   <div class="col-sm-6">
    <div class="h1">Информация о канале</div>
   </div>
   <!--
    <div class="col-sm-6 right">
     <button type="button" class="admpen btn btn-danger"><span class="glyphicon glyphicon-pencil"></span>Написать администратору</button>    
    </div>
    -->
  </div>
 </div>
 <div class="chs_line">
  <div class="col-sm-2">
   <img class="ch_img img-circle" src="%PhotoBig%" alt="%Title%">
  </div>
  <div class="col-sm-10">
   <div class="ch_name">
    <a href="">%Title%</a> 
    <block_link><a class="link" href="http://cflink.ru/%Link%" target="_blank">@%Link%</a></block_link>
   </div>
   <div class="row">
    <div class="col-sm-7">
     <div style="display:none;" class="ch_cat">
      <a href="">%Type%</a>
     </div>
     <div class=clrln></div>
     <block_cat>
      <div class="cat_cat">
       Категория: <b><a href="/channel/%Link%">%Cat%</a></b>
      </div>
     </block_cat>
     <div class="ch_col">
      Подписчиков: <b>%Members%</b>
     </div>
     <div class="ch_col">
      Стоимость рекламы: <b>%Cost%</b> руб.
     </div>
    </div>
    <div class="col-sm-5 opiskanala">
     <block_description>
      <b>Описание канала:</b>
      %Description%
     </block_description>
    </div>
   </div>
  </div>
  <!--
   <div class="col-sm-3 right">
    <a class="zametka" href=""><span class="glyphicon glyphicon-bookmark"></span> Оставить заметку</a>
   </div>
   -->
  <div class="clear"></div>
 </div>
 <block_sysmsgs>
  <div class="chs_line">
   %SystemMessages%
  </div>
 </block_sysmsgs>
 
 
 
 
 
 
 
 
 
 
 <div class="hidden">
  <div class="chs_line">
   <div class="variants_rek">
    <div class="line_chan">
     Реклама на Telegram канале <a class="link" href="http://cflink.ru/%Link%" target="_blank">@%Link%</a>
    </div>
    <div class="variant_list">
     <div class="row">
      <div class="col-sm-2">
       <span>Размещение</span>
      </div>
      <div class="col-sm-1">
       <span><b>%Cost%</b> Р</span>
      </div>
      <div class="col-sm-2">
       <span>1 час / 2 дня</span>
      </div>
      <div class="col-sm-3">
       <span>Просмотров: <b>1400+</b></span>
      </div>
      <div class="col-sm-2">
       <span>CPM: <b>595.83 Р</b></span>
      </div>
      <div class="col-sm-2"><button class="btn btn-success">Выбрать</button></div>
     </div>
     <div class="row">
      <div class="col-sm-2">
       <span>Размещение</span>
      </div>
      <div class="col-sm-1">
       <span><b>%Cost%</b> Р</span>
      </div>
      <div class="col-sm-2">
       <span>5 час / 1 дня</span>
      </div>
      <div class="col-sm-3">
       <span>Просмотров: <b>2400+</b></span>
      </div>
      <div class="col-sm-2">
       <span>CPM: <b>595.83 Р</b></span>
      </div>
      <div class="col-sm-2"><button class="btn btn-success">Выбрать</button></div>
     </div>
    </div>
   </div>
  </div>
  <div class="chs_line">
   <div class="alert alert-warning">
    После того как юзер выбрал вариант размещения ему показываем что может составить пост и отправить рекламу на модерацию. <br><br>
    кстати после выбора варианта - мы его подсвечиваем, либо фоном либо цвет кнопки, хз подумаем <br><br>
    Когда выбираем дату можем кликнуть на сам календарь и выбрать дату и время, а можем выбрать из предложенных вариантов администратора (это он указывает у себя в настройках канала) <br><br>
    Также я бы вывел блок с уже отправленными этому каналу заявками со статусами заявок
   </div>
  </div>
  <div class="chs_line">
   <div class="publ-box">
    <div class="row">
     <div class="col-sm-3">
      <b>Статус предложения</b><br>
      <span>Составление</span>
     </div>
     <div class="col-sm-3">
      <b>Дата публикации</b><br>
      <span><a data-toggle="modal" data-target="#addDate">Январь 9, 10:35</a></span>
     </div>
     <div class="col-sm-3">
      <b>Ответ не позже</b><br>
      <span><a data-toggle="modal" data-target="#addAnswer">Январь 10, 10:35</a></span>
     </div>
    </div>
   </div>
  </div>
 </div>
 <block_requestallowed>
  <block_notenoughmoney>
   <div class="chs_line">
    <div class="alert alert-danger">
     <ru>У вас недостаточно средств, чтобы оставить заявку на рекламу в этом канале! Для продолжения следует <a href="/pay">пополнить баланс</a>.</ru>
     <en>You don't have enough money to send request to this channel! You should <a href="/pay">add money</a> to continue.</en>
    </div>
   </div>
  </block_notenoughmoney>
  <div class="chs_line">
   <div class="ch_ads">
    <div class="add_ads">
     <div class="col-sm-4">
      <!--<img src="%imgfolder%/calendar.jpg" alt="">-->
      <div style="overflow:hidden;">
       <div class="form-group">
        <div class="row">
         <div class="col-sm-12">
          <div id="datetimepicker12"></div>
         </div>
        </div>
       </div>
       <script type="text/javascript">
        $(
         function () {
          $('#datetimepicker12').datetimepicker(
           {
            inline: true,
            format: 'DD.MM.YYYY HH:mm:ss'
           }
          );
         }
        );
       </script>
      </div>
      <block_comment>
       <div class="adm_say">
        <div class="alert alert-warning">
         %Comment%
        </div>
       </div>
      </block_comment>
     </div>
     <div class="col-sm-8">
      <div class="alert alert-info">
       Выберите дату слева, составьте рекламный пост и отправьте на утверждение.
      </div>
      <div class="ch_post">
       <ul class="nav nav-tabs">
        <li class="active"><a data-toggle="tab" href="#post">Пост</a></li>
        <!--<li><a data-toggle="tab" href="#repost">Перепост</a></li>-->
       </ul>
       <div class="tab-content">
        <div id="post" class="tab-pane fade in active">
         <div class="post_line">
          <b>Какой канал рекламируете?</b>
          <select id="ChannelID">
           <option value="0">
            <ru>Никакой</ru>
            <en>No one</en>
           </option>
           <loop_channels>
            <option id="%ID%">%Title% (@%Link%)</option>
           </loop_channels>
           <block_nochannels>
           </block_nochannels>
          </select>
          <br><br>
          <b>Напишите ваш рекламный материал</b>
          <textarea placeholder="Отправьте администратору канала заранее отформатированный текст, согласно правил форматирования которые представлены ниже. " id="Text"></textarea>
          <br><br>
          <div class="table_format">
           <table class="table table-striped">
            <thead>
             <tr>
              <th>Правило</th>
              <th>Результат</th>
             </tr>
            </thead>
            <tbody>
             <tr>
              <td>[Ссылка] (https://barzha.top)</td>
              <td><a href="javascript:;" rel="noopener" onclick="return false;">Ссылка</a></td>
             </tr>
             <tr>
              <td>*Жирный*</td>
              <td><b>Жирный</b></td>
             </tr>
             <tr>
              <td>_Курсив_</td>
              <td><em>Курсив</em></td>
             </tr>
             <tr>
              <td>`Выделение кода`</td>
              <td><code>Выделение кода</code></td>
             </tr>
            </tbody>
           </table>
          </div>
          <span class="btn-file">
           Выберите файл:<br>
           <form id='uploadform_%id%' name='uploadform' target='uploadbuffer' enctype='multipart/form-data' method='post' action='index.php'>
            <p>
             <input type='hidden' name='action'     id='action' value='%id%'>
             <input type='hidden' name='id'         id='id'     value=''>
             <input type='file'   name='fileupload' id='fileupload' onchange='doupload_v2("%id%");' accept_='application/vnd.ms-excel'>
             <!-- <button onclick='doupload_v2("%id%");'>Reload</button> -->
            </p>
           </form>
           <p>
           <div id='status_%id%'>
            <block_file>
             <a href="%rootdir%/%Image%" target="_blank">
             <img class="img" src="%rootdir%/%Image_pf%">
             </a>
             <a href="javascript:;" onclick="deleteFile('%Image%', '%id%');">
              <span class="fa fa-times"></span>
              <ru>Удалить файл</ru>
              <en>Delete file</en>
             </a>
            </block_file>
            <block_nofile>
             <ru>Нет файла</ru>
             <en>No file</en>
            </block_nofile>
            
           </div>
           <iframe name='uploadbuffer' class='uploadbuffer' id='uploadbuffer_%id%' onload='uploaded_v2("%id%");'></iframe>
           <p>
          </span>
          <b>Оставить комментарий:</b>
          <textarea placeholder="Напишите требование по рекламе или сразу задайте вопрос администратору канала" id="Comment"></textarea>
         </div>
        </div>
        <div id="repost" class="tab-pane fade">
         <div class="post_line">
          <p>Ссылка на репост</p>
          <input type="text" placeholder="http://cflink.ru/casebiz/3">
         </div>
        </div>
       </div>
      </div>
      <div class="post_app">
       <div class="row">
        <div class="ch_alert alert alert-danger center">
         Внимательно проверьте рекламный пост перед отправкой. После отправки поста правка невозможна. После отправки поста с вашего счёта будет списано <b>%Cost% рублей</b>, которые будут зачислены на счёт администратора канала после того, как вы одобрите публикацию.
        </div>
        <div class="center">
         <button class="btn btn-success" onclick="sendRequest();">Отправить предложение <span>%Cost% руб.</span></button>
        </div>
       </div>
      </div>
     </div>
    </div>
   </div>
   <div class="clear"></div>
  </div>
  <div class="chs_line hidden" id="sendRequestRslt_div">
   <div class="alert alert-danger" id="sendRequestRslt">
    Здесь будет блок отзывов о рекламе в этом канале, они появляются после того как реклама опубликовалась и пользователи обменялись отзывами.
   </div>
  </div>
 </block_requestallowed>
 <block_adminonly>
  <div class="chs_line">
   <div class="ch_rewievs">
    <div class="row">
     <div class="col-sm-6">
      <h3>Кто рекламировался:</h3>
      <div class="overflow_box">
       <loop_itemsWho>
        <div class="line_adv row">
         <div class="col-sm-2">
          <img class="img-responsive img-circle" src="%PhotoBig%" alt="%Title%">
         </div>
         <div class="col-sm-7">
          <a href="/channel/%Link%">%Title%</a>
         </div>
         <div class="col-sm-3 right">
          <span>17.11.17</span><b>17:45</b>
         </div>
        </div>
       </loop_itemsWho>
      </div>
     </div>
     <div class="col-sm-6">
      <h3>Где рекламировался:</h3>
      <div class="overflow_box">
       <loop_itemsWhere>
        <div class="line_adv row">
         <div class="col-sm-2">
          <img class="img-responsive img-circle" src="%PhotoBig%" alt="%Title%">
         </div>
         <div class="col-sm-7">
          <a href="/channel/%Link%">%Title%</a>
         </div>
         <div class="col-sm-3 right">
          <span>17.11.17</span><b>17:45</b>
         </div>
        </div>
       </loop_itemsWhere>
      </div>
     </div>
    </div>
    <block_reviews>
     <div class="row">
      <div class="col-sm-12">
       <h3>Отзывы о канале:</h3>
       <loop_reviews>
        <div class="line_review row">
         <div class="col-sm-1">
          <img class="img-responsive img-circle" src="%PhotoBig%" alt="Отзыв о канале %Title%">
         </div>
         <div class="col-sm-7">
          <div class="rev_user">
           <b>%Firstname% %Lastname%</b> %DateAddedFmt%<br>
           %Comment%
          </div>
         </div>
         <div class="col-sm-4">
          <ul class="right">
           <li>
            <b>Ответственность:</b>
            <i class="fa fa-star%Liability_1%"></i>
            <i class="fa fa-star%Liability_2%"></i>
            <i class="fa fa-star%Liability_3%"></i>
            <i class="fa fa-star%Liability_4%"></i>
            <i class="fa fa-star%Liability_5%"></i>
           </li>
           <li>
            <b>Сроки:</b>
            <i class="fa fa-star%Terms_1%"></i>
            <i class="fa fa-star%Terms_2%"></i>
            <i class="fa fa-star%Terms_3%"></i>
            <i class="fa fa-star%Terms_4%"></i>
            <i class="fa fa-star%Terms_5%"></i>
           </li>
           <li>
            <b>Адекватность:</b>
            <i class="fa fa-star%Adequacy_1%"></i>
            <i class="fa fa-star%Adequacy_2%"></i>
            <i class="fa fa-star%Adequacy_3%"></i>
            <i class="fa fa-star%Adequacy_4%"></i>
            <i class="fa fa-star%Adequacy_5%"></i>
           </li>
          </ul>
         </div>
        </div>
       </loop_reviews>
      </div>
     </div>
    </block_reviews>
   </div>
  </div>
 </block_adminonly>
 <div class="chs_line divstats">
  <!-- Styles -->
  <style>
   #chartdiv {
   width : 100%;
   height : 500px;
   }
  </style>
  <!-- Resources -->
  <script src="https://www.amcharts.com/lib/3/amcharts.js"></script>
  <script src="https://www.amcharts.com/lib/3/serial.js"></script>
  <script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script>
  <link rel="stylesheet" href="https://www.amcharts.com/lib/3/plugins/export/export.css" type="text/css" media="all" />
  <script src="https://www.amcharts.com/lib/3/themes/light.js"></script>
  <!-- Chart code -->
  <script>
   var chart = AmCharts.makeChart(
    "chartdiv", {
     "type": "serial",
     "theme": "light",
     "marginRight": 40,
     "marginLeft": 40,
     "autoMarginOffset": 20,
     "mouseWheelZoomEnabled":true,
     "dataDateFormat": "YYYY-MM-DD",
     "valueAxes": [
      {
       "id": "v1",
       "axisAlpha": 0,
       "position": "left",
       "ignoreAxisWidth":true
      }
     ],
     "balloon": {
      "borderThickness": 1,
      "shadowAlpha": 0
     },
     "graphs": [
      {
         "id": "g1",
         "balloon":{
           "drop":true,
           "adjustBorderColor":false,
           "color":"#ffffff"
         },
         "bullet": "round",
         "bulletBorderAlpha": 1,
         "bulletColor": "#FFFFFF",
         "bulletSize": 5,
         "hideBulletsCount": 50,
         "lineThickness": 2,
         "title": "red line",
         "useLineColorForBulletBorder": true,
         "valueField": "value",
         "balloonText": "<span style='font-size:18px;'>[[value]]</span>"
      }
     ],
     "chartScrollbar": {
         "graph": "g1",
         "oppositeAxis":false,
         "offset":30,
         "scrollbarHeight": 80,
         "backgroundAlpha": 0,
         "selectedBackgroundAlpha": 0.1,
         "selectedBackgroundColor": "#888888",
         "graphFillAlpha": 0,
         "graphLineAlpha": 0.5,
         "selectedGraphFillAlpha": 0,
         "selectedGraphLineAlpha": 1,
         "autoGridCount":true,
         "color":"#AAAAAA"
     },
     "chartCursor": {
         "pan": true,
         "valueLineEnabled": true,
         "valueLineBalloonEnabled": true,
         "cursorAlpha":1,
         "cursorColor":"#258cbb",
         "limitToGraph":"g1",
         "valueLineAlpha":0.2,
         "valueZoomable":true
     },
     "valueScrollbar":{
       "oppositeAxis":false,
       "offset":50,
       "scrollbarHeight":10
     },
     "categoryField": "date",
     "categoryAxis": {
         "parseDates": true,
         "dashLength": 1,
         "minorGridEnabled": true
     },
     "export": {
         "enabled": true
     },
     "dataProvider": [
      %StatsDaily%
     ]
    }
   );
   
   chart.addListener("rendered", zoomChart);
   
   zoomChart();
   
   function zoomChart() {
    chart.zoomToIndexes(chart.dataProvider.length - 40, chart.dataProvider.length - 1);
   }
  </script>
  <!-- HTML -->
  <div id="chartdiv"></div>
  <!--
   <div class="h4">График ниже отобразим в нем кол-во рекламных постов канала</div>
   будет круговая диаграмма с процентным соотношением 
   -->
 </div>
 <div class="chs_line">
  <div class="row">
   <div class="col-sm-7">
    <div class="graph1">
     <div class="h4">Суточный охват записей <button class="btn primary_btn navbar-btn show_day_stat"><i class="fa fa-info-circle" aria-hidden="true"></i></button></div>
     <div style="display:none;" class="day_stat alert alert-warning">
      <p>В графике показаны данные суточного охвата по просмотрам за 24 часа с момента публикации.</p>
      <p>Если в день вышло более одной публикации - просмотры суммируются и делятся на кол-во публикаций в этот день. Таким образом мы получаем среднее арифметическое.</p>
     </div>
     <script>
      jQuery('.show_day_stat').on(
       'click',function(){
        jQuery('.day_stat').toggle(); 
       }
      );
     </script>
     <canvas id="myChart" width="400" height="150"></canvas>
     <script>
      var ctx = document.getElementById("myChart");
      var myChart = new Chart(ctx, 
       {
        type: 'line', data: {
         datasets: [
          {
           label: 'последние 14 дней',
           data: [%StatsDaily_views_data%]
          }, 
         ],
         labels: [%StatsDaily_views_labels%]
        },
        options: {
         scales: {
          yAxes: [
           {
            ticks: {
             beginAtZero: true
            }
           }
          ]
         }
        }
       }
      );
     </script>
    </div>
    <div class="graph1">
     <div class="h4">График изменения цен <button class="btn primary_btn navbar-btn show_day_stat2"><i class="fa fa-info-circle" aria-hidden="true"></i></button></div>
     <div style="display:none;" class="day_stat2 alert alert-warning">
      <p>В графике показан порядок изменения цен на рекламную запись, размещаемую на 24 часа.</p>
     </div>
     <script>
      jQuery('.show_day_stat2').on(
       'click',function(){
        jQuery('.day_stat2').toggle(); 
       }
      );
     </script>
     <canvas id="myChart2" width="400" height="150"></canvas>
     <script>
      var ctx2 = document.getElementById("myChart2");
      var myChart2 = new Chart(
       ctx2, {
        type: 'line',
        data: {
         datasets: [
          {
           label: 'Текущая неделя (руб.)',
           data: [%StatsDaily_cost_data%]
          }, 
         ],
         labels: [%StatsDaily_cost_labels%]
        },
        options: {
         scales: {
          yAxes: [
           {
            ticks: {
             beginAtZero: true
            }
           }
          ]
         }
        }
       }
      );
     </script>
    </div>
    
   </div>
   <div class="col-sm-5">
    <block_messages>
     <div class="chs_liners">
      <div class="h4">Записи канала</div>
      <div class="ch_desc">
       <loop_messages>
        <div class="post_blog">
         <div class="titletext">
          <div class="row">
           <div style="display:none;" class="col-sm-1">
            <img class="ch_img img-responsive img-circle" src="%PhotoBig%" alt="%Title%">
           </div>
           <div class="col-sm-12">
            <a href="">%Title%</a>
           </div>
           <div style="display:none;" class="col-sm-3 right">
            %DateAdded% 
           </div>
          </div>
         </div>
         <div class="posttext">%Text%</div>
         <div style="margin-top:10px;padding-top:10px;border-top:1px solid #cfd1d3;" class="row">
          <div class="col-sm-8">
           <div class="row">
            <div class="col-sm-6">
             <block_views1>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 24 часа"><b>BAR1:</b> %Views1%</span></div>
             </block_views1>
            </div>
            <div class="col-sm-6">
             <block_views2>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 48 часов"><b>BAR2:</b> %Views2%</span></div>
             </block_views2>
            </div>
            <div class="col-sm-6">
             <block_views3>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 72 часа"><b>BAR3:</b> %Views3%</span></div>
             </block_views3>
            </div>
            <div class="col-sm-6">
             <block_views7>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 7 дней"><b>BAR7:</b> %Views7%</span></div>
             </block_views7>
            </div>
            <div class="col-sm-6">
             <block_views30>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 30 дней"><b>BAR30:</b> %Views30%</span></div>
             </block_views30>
            </div>
           </div>
          </div>
          <div class="col-sm-4">
           <block_views>
            <div class="views right"><i class="fa fa-eye" aria-hidden="true"></i>%Views%</div>
           </block_views>
          </div>
         </div>
        </div>
       </loop_messages>
      </div>
     </div>
    </block_messages>
   </div>
  </div>
 </div>
</div>
<!-- Modal -->
<div id="addDate" class="modal fade" role="dialog">
 <div class="modal-dialog">
  <!-- Modal content-->
  <div class="modal-content">
   <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" onclick="getChannels();">&times;</button>
    <h4 class="modal-title">Дата публикации</h4>
   </div>
   <div class="modal-body">
    <div class="row">
     <div class="col-sm-6">
      <div id="datepickermodal"></div>
      <script type="text/javascript">
       $(
        function () {
         $('#datepickermodal').datetimepicker(
          {
           locale: 'ru',
           inline: true,
           format: 'DD.MM.YYYY HH:mm:ss',
       
          }
         );
        }
       );
      </script>
     </div>
     <div class="col-sm-6">
      <p>Также вы можете выбрать свободную дату и время предложенные администратором канала</p>
      <button><b>10.01.18</b> (<span>17:59</span>)</button><button><b>13.01.18</b> (<span>17:59</span>)</button><button><b>15.01.18</b> (<span>17:59</span>)</button><button><b>17.01.18</b> (<span>17:59</span>)</button><button><b>19.01.18</b> (<span>17:59</span>)</button><button><b>22.01.18</b> (<span>17:59</span>)</button>
     </div>
    </div>
   </div>
  </div>
 </div>
</div>
<!-- Modal -->
<div id="addAnswer" class="modal fade" role="dialog">
 <div class="modal-dialog">
  <!-- Modal content-->
  <div class="modal-content">
   <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" onclick="getChannels();">&times;</button>
    <h4 class="modal-title">Ответ не позже</h4>
   </div>
   <div class="modal-body">
    <div id="datepickermodal"></div>
    <script type="text/javascript">
     $(
      function () {
       $('#datepickermodal').datetimepicker(
        {
         locale: 'ru',
         inline: true,
         format: 'DD.MM.YYYY HH:mm:ss',
        }
       );
      }
     );
    </script>
   </div>
  </div>
 </div>
</div>
            </div>
        </div>
    </div>
</div>
    [template] => <div class="user_channel_block">
    <div class="container">
        <div class="row">
            <div class="col-sm-2"></div>
            <div class="col-sm-10">
                <div class="chs_info">
 <div class="chs_line">
  <div class="row">
   <div class="col-sm-6">
    <div class="h1">Информация о канале</div>
   </div>
   <!--
    <div class="col-sm-6 right">
     <button type="button" class="admpen btn btn-danger"><span class="glyphicon glyphicon-pencil"></span>Написать администратору</button>    
    </div>
    -->
  </div>
 </div>
 <div class="chs_line">
  <div class="col-sm-2">
   <img class="ch_img img-circle" src="%PhotoBig%" alt="%Title%">
  </div>
  <div class="col-sm-10">
   <div class="ch_name">
    <a href="">%Title%</a> 
    <block_link><a class="link" href="http://cflink.ru/%Link%" target="_blank">@%Link%</a></block_link>
   </div>
   <div class="row">
    <div class="col-sm-7">
     <div style="display:none;" class="ch_cat">
      <a href="">%Type%</a>
     </div>
     <div class=clrln></div>
     <block_cat>
      <div class="cat_cat">
       Категория: <b><a href="/channel/%Link%">%Cat%</a></b>
      </div>
     </block_cat>
     <div class="ch_col">
      Подписчиков: <b>%Members%</b>
     </div>
     <div class="ch_col">
      Стоимость рекламы: <b>%Cost%</b> руб.
     </div>
    </div>
    <div class="col-sm-5 opiskanala">
     <block_description>
      <b>Описание канала:</b>
      %Description%
     </block_description>
    </div>
   </div>
  </div>
  <!--
   <div class="col-sm-3 right">
    <a class="zametka" href=""><span class="glyphicon glyphicon-bookmark"></span> Оставить заметку</a>
   </div>
   -->
  <div class="clear"></div>
 </div>
 <block_sysmsgs>
  <div class="chs_line">
   %SystemMessages%
  </div>
 </block_sysmsgs>
 
 
 
 
 
 
 
 
 
 
 <div class="hidden">
  <div class="chs_line">
   <div class="variants_rek">
    <div class="line_chan">
     Реклама на Telegram канале <a class="link" href="http://cflink.ru/%Link%" target="_blank">@%Link%</a>
    </div>
    <div class="variant_list">
     <div class="row">
      <div class="col-sm-2">
       <span>Размещение</span>
      </div>
      <div class="col-sm-1">
       <span><b>%Cost%</b> Р</span>
      </div>
      <div class="col-sm-2">
       <span>1 час / 2 дня</span>
      </div>
      <div class="col-sm-3">
       <span>Просмотров: <b>1400+</b></span>
      </div>
      <div class="col-sm-2">
       <span>CPM: <b>595.83 Р</b></span>
      </div>
      <div class="col-sm-2"><button class="btn btn-success">Выбрать</button></div>
     </div>
     <div class="row">
      <div class="col-sm-2">
       <span>Размещение</span>
      </div>
      <div class="col-sm-1">
       <span><b>%Cost%</b> Р</span>
      </div>
      <div class="col-sm-2">
       <span>5 час / 1 дня</span>
      </div>
      <div class="col-sm-3">
       <span>Просмотров: <b>2400+</b></span>
      </div>
      <div class="col-sm-2">
       <span>CPM: <b>595.83 Р</b></span>
      </div>
      <div class="col-sm-2"><button class="btn btn-success">Выбрать</button></div>
     </div>
    </div>
   </div>
  </div>
  <div class="chs_line">
   <div class="alert alert-warning">
    После того как юзер выбрал вариант размещения ему показываем что может составить пост и отправить рекламу на модерацию. <br><br>
    кстати после выбора варианта - мы его подсвечиваем, либо фоном либо цвет кнопки, хз подумаем <br><br>
    Когда выбираем дату можем кликнуть на сам календарь и выбрать дату и время, а можем выбрать из предложенных вариантов администратора (это он указывает у себя в настройках канала) <br><br>
    Также я бы вывел блок с уже отправленными этому каналу заявками со статусами заявок
   </div>
  </div>
  <div class="chs_line">
   <div class="publ-box">
    <div class="row">
     <div class="col-sm-3">
      <b>Статус предложения</b><br>
      <span>Составление</span>
     </div>
     <div class="col-sm-3">
      <b>Дата публикации</b><br>
      <span><a data-toggle="modal" data-target="#addDate">Январь 9, 10:35</a></span>
     </div>
     <div class="col-sm-3">
      <b>Ответ не позже</b><br>
      <span><a data-toggle="modal" data-target="#addAnswer">Январь 10, 10:35</a></span>
     </div>
    </div>
   </div>
  </div>
 </div>
 <block_requestallowed>
  <block_notenoughmoney>
   <div class="chs_line">
    <div class="alert alert-danger">
     У вас недостаточно средств, чтобы оставить заявку на рекламу в этом канале! Для продолжения следует <a href="/pay">пополнить баланс</a>.
     
    </div>
   </div>
  </block_notenoughmoney>
  <div class="chs_line">
   <div class="ch_ads">
    <div class="add_ads">
     <div class="col-sm-4">
      <!--<img src="%imgfolder%/calendar.jpg" alt="">-->
      <div style="overflow:hidden;">
       <div class="form-group">
        <div class="row">
         <div class="col-sm-12">
          <div id="datetimepicker12"></div>
         </div>
        </div>
       </div>
       <script type="text/javascript">
        $(
         function () {
          $('#datetimepicker12').datetimepicker(
           {
            inline: true,
            format: 'DD.MM.YYYY HH:mm:ss'
           }
          );
         }
        );
       </script>
      </div>
      <block_comment>
       <div class="adm_say">
        <div class="alert alert-warning">
         %Comment%
        </div>
       </div>
      </block_comment>
     </div>
     <div class="col-sm-8">
      <div class="alert alert-info">
       Выберите дату слева, составьте рекламный пост и отправьте на утверждение.
      </div>
      <div class="ch_post">
       <ul class="nav nav-tabs">
        <li class="active"><a data-toggle="tab" href="#post">Пост</a></li>
        <!--<li><a data-toggle="tab" href="#repost">Перепост</a></li>-->
       </ul>
       <div class="tab-content">
        <div id="post" class="tab-pane fade in active">
         <div class="post_line">
          <b>Какой канал рекламируете?</b>
          <select id="ChannelID">
           <option value="0">
            Никакой
            
           </option>
           <loop_channels>
            <option id="%ID%">%Title% (@%Link%)</option>
           </loop_channels>
           <block_nochannels>
           </block_nochannels>
          </select>
          <br><br>
          <b>Напишите ваш рекламный материал</b>
          <textarea placeholder="Отправьте администратору канала заранее отформатированный текст, согласно правил форматирования которые представлены ниже. " id="Text"></textarea>
          <br><br>
          <div class="table_format">
           <table class="table table-striped">
            <thead>
             <tr>
              <th>Правило</th>
              <th>Результат</th>
             </tr>
            </thead>
            <tbody>
             <tr>
              <td>[Ссылка] (https://barzha.top)</td>
              <td><a href="javascript:;" rel="noopener" onclick="return false;">Ссылка</a></td>
             </tr>
             <tr>
              <td>*Жирный*</td>
              <td><b>Жирный</b></td>
             </tr>
             <tr>
              <td>_Курсив_</td>
              <td><em>Курсив</em></td>
             </tr>
             <tr>
              <td>`Выделение кода`</td>
              <td><code>Выделение кода</code></td>
             </tr>
            </tbody>
           </table>
          </div>
          <span class="btn-file">
           Выберите файл:<br>
           <form id='uploadform_%id%' name='uploadform' target='uploadbuffer' enctype='multipart/form-data' method='post' action='index.php'>
            <p>
             <input type='hidden' name='action'     id='action' value='%id%'>
             <input type='hidden' name='id'         id='id'     value=''>
             <input type='file'   name='fileupload' id='fileupload' onchange='doupload_v2("%id%");' accept_='application/vnd.ms-excel'>
             <!-- <button onclick='doupload_v2("%id%");'>Reload</button> -->
            </p>
           </form>
           <p>
           <div id='status_%id%'>
            <block_file>
             <a href="%rootdir%/%Image%" target="_blank">
             <img class="img" src="%rootdir%/%Image_pf%">
             </a>
             <a href="javascript:;" onclick="deleteFile('%Image%', '%id%');">
              <span class="fa fa-times"></span>
              Удалить файл
              
             </a>
            </block_file>
            <block_nofile>
             Нет файла
             
            </block_nofile>
            
           </div>
           <iframe name='uploadbuffer' class='uploadbuffer' id='uploadbuffer_%id%' onload='uploaded_v2("%id%");'></iframe>
           <p>
          </span>
          <b>Оставить комментарий:</b>
          <textarea placeholder="Напишите требование по рекламе или сразу задайте вопрос администратору канала" id="Comment"></textarea>
         </div>
        </div>
        <div id="repost" class="tab-pane fade">
         <div class="post_line">
          <p>Ссылка на репост</p>
          <input type="text" placeholder="http://cflink.ru/casebiz/3">
         </div>
        </div>
       </div>
      </div>
      <div class="post_app">
       <div class="row">
        <div class="ch_alert alert alert-danger center">
         Внимательно проверьте рекламный пост перед отправкой. После отправки поста правка невозможна. После отправки поста с вашего счёта будет списано <b>%Cost% рублей</b>, которые будут зачислены на счёт администратора канала после того, как вы одобрите публикацию.
        </div>
        <div class="center">
         <button class="btn btn-success" onclick="sendRequest();">Отправить предложение <span>%Cost% руб.</span></button>
        </div>
       </div>
      </div>
     </div>
    </div>
   </div>
   <div class="clear"></div>
  </div>
  <div class="chs_line hidden" id="sendRequestRslt_div">
   <div class="alert alert-danger" id="sendRequestRslt">
    Здесь будет блок отзывов о рекламе в этом канале, они появляются после того как реклама опубликовалась и пользователи обменялись отзывами.
   </div>
  </div>
 </block_requestallowed>
 <block_adminonly>
  <div class="chs_line">
   <div class="ch_rewievs">
    <div class="row">
     <div class="col-sm-6">
      <h3>Кто рекламировался:</h3>
      <div class="overflow_box">
       <loop_itemsWho>
        <div class="line_adv row">
         <div class="col-sm-2">
          <img class="img-responsive img-circle" src="%PhotoBig%" alt="%Title%">
         </div>
         <div class="col-sm-7">
          <a href="/channel/%Link%">%Title%</a>
         </div>
         <div class="col-sm-3 right">
          <span>17.11.17</span><b>17:45</b>
         </div>
        </div>
       </loop_itemsWho>
      </div>
     </div>
     <div class="col-sm-6">
      <h3>Где рекламировался:</h3>
      <div class="overflow_box">
       <loop_itemsWhere>
        <div class="line_adv row">
         <div class="col-sm-2">
          <img class="img-responsive img-circle" src="%PhotoBig%" alt="%Title%">
         </div>
         <div class="col-sm-7">
          <a href="/channel/%Link%">%Title%</a>
         </div>
         <div class="col-sm-3 right">
          <span>17.11.17</span><b>17:45</b>
         </div>
        </div>
       </loop_itemsWhere>
      </div>
     </div>
    </div>
    <block_reviews>
     <div class="row">
      <div class="col-sm-12">
       <h3>Отзывы о канале:</h3>
       <loop_reviews>
        <div class="line_review row">
         <div class="col-sm-1">
          <img class="img-responsive img-circle" src="%PhotoBig%" alt="Отзыв о канале %Title%">
         </div>
         <div class="col-sm-7">
          <div class="rev_user">
           <b>%Firstname% %Lastname%</b> %DateAddedFmt%<br>
           %Comment%
          </div>
         </div>
         <div class="col-sm-4">
          <ul class="right">
           <li>
            <b>Ответственность:</b>
            <i class="fa fa-star%Liability_1%"></i>
            <i class="fa fa-star%Liability_2%"></i>
            <i class="fa fa-star%Liability_3%"></i>
            <i class="fa fa-star%Liability_4%"></i>
            <i class="fa fa-star%Liability_5%"></i>
           </li>
           <li>
            <b>Сроки:</b>
            <i class="fa fa-star%Terms_1%"></i>
            <i class="fa fa-star%Terms_2%"></i>
            <i class="fa fa-star%Terms_3%"></i>
            <i class="fa fa-star%Terms_4%"></i>
            <i class="fa fa-star%Terms_5%"></i>
           </li>
           <li>
            <b>Адекватность:</b>
            <i class="fa fa-star%Adequacy_1%"></i>
            <i class="fa fa-star%Adequacy_2%"></i>
            <i class="fa fa-star%Adequacy_3%"></i>
            <i class="fa fa-star%Adequacy_4%"></i>
            <i class="fa fa-star%Adequacy_5%"></i>
           </li>
          </ul>
         </div>
        </div>
       </loop_reviews>
      </div>
     </div>
    </block_reviews>
   </div>
  </div>
 </block_adminonly>
 <div class="chs_line divstats">
  <!-- Styles -->
  <style>
   #chartdiv {
   width : 100%;
   height : 500px;
   }
  </style>
  <!-- Resources -->
  <script src="https://www.amcharts.com/lib/3/amcharts.js"></script>
  <script src="https://www.amcharts.com/lib/3/serial.js"></script>
  <script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script>
  <link rel="stylesheet" href="https://www.amcharts.com/lib/3/plugins/export/export.css" type="text/css" media="all" />
  <script src="https://www.amcharts.com/lib/3/themes/light.js"></script>
  <!-- Chart code -->
  <script>
   var chart = AmCharts.makeChart(
    "chartdiv", {
     "type": "serial",
     "theme": "light",
     "marginRight": 40,
     "marginLeft": 40,
     "autoMarginOffset": 20,
     "mouseWheelZoomEnabled":true,
     "dataDateFormat": "YYYY-MM-DD",
     "valueAxes": [
      {
       "id": "v1",
       "axisAlpha": 0,
       "position": "left",
       "ignoreAxisWidth":true
      }
     ],
     "balloon": {
      "borderThickness": 1,
      "shadowAlpha": 0
     },
     "graphs": [
      {
         "id": "g1",
         "balloon":{
           "drop":true,
           "adjustBorderColor":false,
           "color":"#ffffff"
         },
         "bullet": "round",
         "bulletBorderAlpha": 1,
         "bulletColor": "#FFFFFF",
         "bulletSize": 5,
         "hideBulletsCount": 50,
         "lineThickness": 2,
         "title": "red line",
         "useLineColorForBulletBorder": true,
         "valueField": "value",
         "balloonText": "<span style='font-size:18px;'>[[value]]</span>"
      }
     ],
     "chartScrollbar": {
         "graph": "g1",
         "oppositeAxis":false,
         "offset":30,
         "scrollbarHeight": 80,
         "backgroundAlpha": 0,
         "selectedBackgroundAlpha": 0.1,
         "selectedBackgroundColor": "#888888",
         "graphFillAlpha": 0,
         "graphLineAlpha": 0.5,
         "selectedGraphFillAlpha": 0,
         "selectedGraphLineAlpha": 1,
         "autoGridCount":true,
         "color":"#AAAAAA"
     },
     "chartCursor": {
         "pan": true,
         "valueLineEnabled": true,
         "valueLineBalloonEnabled": true,
         "cursorAlpha":1,
         "cursorColor":"#258cbb",
         "limitToGraph":"g1",
         "valueLineAlpha":0.2,
         "valueZoomable":true
     },
     "valueScrollbar":{
       "oppositeAxis":false,
       "offset":50,
       "scrollbarHeight":10
     },
     "categoryField": "date",
     "categoryAxis": {
         "parseDates": true,
         "dashLength": 1,
         "minorGridEnabled": true
     },
     "export": {
         "enabled": true
     },
     "dataProvider": [
      %StatsDaily%
     ]
    }
   );
   
   chart.addListener("rendered", zoomChart);
   
   zoomChart();
   
   function zoomChart() {
    chart.zoomToIndexes(chart.dataProvider.length - 40, chart.dataProvider.length - 1);
   }
  </script>
  <!-- HTML -->
  <div id="chartdiv"></div>
  <!--
   <div class="h4">График ниже отобразим в нем кол-во рекламных постов канала</div>
   будет круговая диаграмма с процентным соотношением 
   -->
 </div>
 <div class="chs_line">
  <div class="row">
   <div class="col-sm-7">
    <div class="graph1">
     <div class="h4">Суточный охват записей <button class="btn primary_btn navbar-btn show_day_stat"><i class="fa fa-info-circle" aria-hidden="true"></i></button></div>
     <div style="display:none;" class="day_stat alert alert-warning">
      <p>В графике показаны данные суточного охвата по просмотрам за 24 часа с момента публикации.</p>
      <p>Если в день вышло более одной публикации - просмотры суммируются и делятся на кол-во публикаций в этот день. Таким образом мы получаем среднее арифметическое.</p>
     </div>
     <script>
      jQuery('.show_day_stat').on(
       'click',function(){
        jQuery('.day_stat').toggle(); 
       }
      );
     </script>
     <canvas id="myChart" width="400" height="150"></canvas>
     <script>
      var ctx = document.getElementById("myChart");
      var myChart = new Chart(ctx, 
       {
        type: 'line', data: {
         datasets: [
          {
           label: 'последние 14 дней',
           data: [%StatsDaily_views_data%]
          }, 
         ],
         labels: [%StatsDaily_views_labels%]
        },
        options: {
         scales: {
          yAxes: [
           {
            ticks: {
             beginAtZero: true
            }
           }
          ]
         }
        }
       }
      );
     </script>
    </div>
    <div class="graph1">
     <div class="h4">График изменения цен <button class="btn primary_btn navbar-btn show_day_stat2"><i class="fa fa-info-circle" aria-hidden="true"></i></button></div>
     <div style="display:none;" class="day_stat2 alert alert-warning">
      <p>В графике показан порядок изменения цен на рекламную запись, размещаемую на 24 часа.</p>
     </div>
     <script>
      jQuery('.show_day_stat2').on(
       'click',function(){
        jQuery('.day_stat2').toggle(); 
       }
      );
     </script>
     <canvas id="myChart2" width="400" height="150"></canvas>
     <script>
      var ctx2 = document.getElementById("myChart2");
      var myChart2 = new Chart(
       ctx2, {
        type: 'line',
        data: {
         datasets: [
          {
           label: 'Текущая неделя (руб.)',
           data: [%StatsDaily_cost_data%]
          }, 
         ],
         labels: [%StatsDaily_cost_labels%]
        },
        options: {
         scales: {
          yAxes: [
           {
            ticks: {
             beginAtZero: true
            }
           }
          ]
         }
        }
       }
      );
     </script>
    </div>
    
   </div>
   <div class="col-sm-5">
    <block_messages>
     <div class="chs_liners">
      <div class="h4">Записи канала</div>
      <div class="ch_desc">
       <loop_messages>
        <div class="post_blog">
         <div class="titletext">
          <div class="row">
           <div style="display:none;" class="col-sm-1">
            <img class="ch_img img-responsive img-circle" src="%PhotoBig%" alt="%Title%">
           </div>
           <div class="col-sm-12">
            <a href="">%Title%</a>
           </div>
           <div style="display:none;" class="col-sm-3 right">
            %DateAdded% 
           </div>
          </div>
         </div>
         <div class="posttext">%Text%</div>
         <div style="margin-top:10px;padding-top:10px;border-top:1px solid #cfd1d3;" class="row">
          <div class="col-sm-8">
           <div class="row">
            <div class="col-sm-6">
             <block_views1>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 24 часа"><b>BAR1:</b> %Views1%</span></div>
             </block_views1>
            </div>
            <div class="col-sm-6">
             <block_views2>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 48 часов"><b>BAR2:</b> %Views2%</span></div>
             </block_views2>
            </div>
            <div class="col-sm-6">
             <block_views3>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 72 часа"><b>BAR3:</b> %Views3%</span></div>
             </block_views3>
            </div>
            <div class="col-sm-6">
             <block_views7>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 7 дней"><b>BAR7:</b> %Views7%</span></div>
             </block_views7>
            </div>
            <div class="col-sm-6">
             <block_views30>
              <div class="views"><span data-toggle="tooltip" data-original-title="просмотры за 30 дней"><b>BAR30:</b> %Views30%</span></div>
             </block_views30>
            </div>
           </div>
          </div>
          <div class="col-sm-4">
           <block_views>
            <div class="views right"><i class="fa fa-eye" aria-hidden="true"></i>%Views%</div>
           </block_views>
          </div>
         </div>
        </div>
       </loop_messages>
      </div>
     </div>
    </block_messages>
   </div>
  </div>
 </div>
</div>
<!-- Modal -->
<div id="addDate" class="modal fade" role="dialog">
 <div class="modal-dialog">
  <!-- Modal content-->
  <div class="modal-content">
   <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" onclick="getChannels();">&times;</button>
    <h4 class="modal-title">Дата публикации</h4>
   </div>
   <div class="modal-body">
    <div class="row">
     <div class="col-sm-6">
      <div id="datepickermodal"></div>
      <script type="text/javascript">
       $(
        function () {
         $('#datepickermodal').datetimepicker(
          {
           locale: 'ru',
           inline: true,
           format: 'DD.MM.YYYY HH:mm:ss',
       
          }
         );
        }
       );
      </script>
     </div>
     <div class="col-sm-6">
      <p>Также вы можете выбрать свободную дату и время предложенные администратором канала</p>
      <button><b>10.01.18</b> (<span>17:59</span>)</button><button><b>13.01.18</b> (<span>17:59</span>)</button><button><b>15.01.18</b> (<span>17:59</span>)</button><button><b>17.01.18</b> (<span>17:59</span>)</button><button><b>19.01.18</b> (<span>17:59</span>)</button><button><b>22.01.18</b> (<span>17:59</span>)</button>
     </div>
    </div>
   </div>
  </div>
 </div>
</div>
<!-- Modal -->
<div id="addAnswer" class="modal fade" role="dialog">
 <div class="modal-dialog">
  <!-- Modal content-->
  <div class="modal-content">
   <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" onclick="getChannels();">&times;</button>
    <h4 class="modal-title">Ответ не позже</h4>
   </div>
   <div class="modal-body">
    <div id="datepickermodal"></div>
    <script type="text/javascript">
     $(
      function () {
       $('#datepickermodal').datetimepicker(
        {
         locale: 'ru',
         inline: true,
         format: 'DD.MM.YYYY HH:mm:ss',
        }
       );
      }
     );
    </script>
   </div>
  </div>
 </div>
</div>
            </div>
        </div>
    </div>
</div>
    [filename] => view/modern/templates/user_channel.htt
    [viewroot] => view/modern/templates/
    [is_template] => 1
)
, stdClass Object
(
    [ID] => 3733
    [DateAdded] => 2018-01-09 06:41:19.75124
    [UserID] => 
    [Title] => 2pegramming
    [Link] => pepegramming
    [Cost] => 71.8
    [CategoryID] => 5
    [Members] => 783
    [Views] => 
    [TgUserID] => 
    [TgChatID] => -1001106477565
    [Type] => channel
    [Description] => Грустно о программировании. Все проблемы сюда: @davydovanton

Medium: https://medium.com/pepegramming

Ссылки на конкретные посты: http://telegra.ph/Pepegramming-Contents-03-11
Обратная связь: https://goo.gl/forms/iUd1Gufq6WnTsaO62
    [Comment] => 
    [CatID] => 
    [Cat] => 
    [DateUpdated] => 2019-02-23 08:18:19
    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
    [TgCreatorID] => 
    [IsVisible] => 1
    [IsMessagesVisible] => 1
    [IsMessagesIndexable] => 1
    [PhotoLastDateUpdated] => 2019-02-22 11:47:24
    [MinTgMsgID] => 1
    [MsgsScanned] => 1
    [MaxMsgLastDateUpdated] => 2019-02-23 08:53:23
    [Tags] => 
    [Source] => 
    [IsFound] => 1
    [MaxTgMsgID] => 143
    [NumMessages] => 116
    [CostSource] => members
    [Messages] => Array
        (
            [11108518] => stdClass Object
                (
                    [ID] => 11108518
                    [TgID] => 143
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-22 16:20:23
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/><br/>На следующей неделе будет стрим, поговорим о репозиториях, что это, зачем и как с ними жить. Посмотрим на реализацию в hanami и ROM. <br/><br/>Кроме того, во вторник, буду на митапе в москве. Буду раздавать стикеры и буду рад увидеться.<br/><br/><a href=http://amp.gs/9u3A target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Ruby митап №9</a><br/><br/>—————————————<br/><br/><a href=http://amp.gs/9u3r target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Ruby Debugging Magic Cheat Sheet</a><br/>Давно читаю блог Richard Schneeman, но к сожалению не каждую статью получается прочитать. Сегодня исключение, статья с хаками, которые помогут во время дебага. Часть  записал себе, часть использую сам. Например, <code>bundle open active&#092_support</code> выручает, когда дело касается дебага используемых библиотек. А о команде <code>RubyVM::InstructionSequence.compile(code).disasm</code> рассказывается в <a href=http://amp.gs/9u3N target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Ruby Under a Microscope</a>.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/9u3R target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>The Most Important Non-Programming Skills for Programmers</a><br/>Разбавлю технические темы статьей о софт скилах. На <a href=http://amp.gs/9u3K target=_blank rel=noopener>http://amp.gs/9u3K</a> появилась статья с “основными” софт скилами, которые могут помочь в карьере и жизни. Я не фанат подобных статей, но считаю, что софт скилы важны и о них стоит помнить и говорить. В частности о умении общаться и работать в команде, участии в сообществе и умении организовать  работу понятно для себя и окружающих.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/9u3d target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Register Transfer Language for CRuby</a><br/>Статья Владимира Макарова, в которой описывается, что было сделано в руби за последние 2 года. В частности рассказывается о Register Transfer Language, что это, зачем нужно в руби и приводятся бенчмарки между RTL CRuby и trunk CRuby. Статья  техничная, но если интересно будущее языка или кишки компиляторов - мастхев.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 459
                    [ViewsLastDateUpdated] => 2019-02-23 08:53:20
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [11108517] => stdClass Object
                (
                    [ID] => 11108517
                    [TgID] => 142
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-15 16:43:26
                    [Text] => Амплифер побил ссылку на первый пост, оригинал:<br/><br/><a href=https://medium.com/@rieckpil/30-minutes-every-day-for-your-craft-committing-code-to-github-for-365-consecutive-days-eec8b73b5105 target=_blank rel=noopener>https://medium.com/@rieckpil/30-minutes-every-day-for-your-craft-committing-code-to-github-for-365-consecutive-days-eec8b73b5105</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 825
                    [ViewsLastDateUpdated] => 2019-02-23 08:53:20
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 825
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [11108516] => stdClass Object
                (
                    [ID] => 11108516
                    [TgID] => 141
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-15 16:39:05
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/><br/>На неделе прошел стрим, объяснял с практической точки зрения зачем нужен dry-monads и как использовать. В следующий раз расскажу о репозиториях и покажу примеры из hanami. Ссылка на прошлый стрим:<br/><a href=http://amp.gs/9Ezb target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>pepegramming/137</a><br/><br/>Календарь с предстоящими стримами:<br/><a href=http://amp.gs/9E1I target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>http://amp.gs/9E1j</a><br/><br/>Кроме того, завтра, в Питере, буду рассказывать о опыте борьбы с требованиями. Буду рассказывать о персональных факапах в разделении монолита на сервисы:<br/><a href=http://amp.gs/9EzQ target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Winter SaintP Ruby Meetup</a><br/><br/>—————————————<br/><br/><a href=http://amp.gs/9EzM... target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>30 minutes every day for your craft: Committing code to GitHub for 365 consecutive days</a><br/>История человека, который каждый день тратил 30 минут на персональные проекты и обучение. В статье найдете советы о поиске время, что полезного из этого выйдет и что делать, когда не прет.<br/><br/>Добавлю, что важна регулярность и даже 5 минут в день приводят к результатам. Поэтому, важно не корить себя за спады и усталость.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/9Ezc target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Making a Game Boy Game&#33 (Part 1)</a><br/>В японии купил себе геймбой для музыки. Оказалось, что кроме LSDJ есть игры, которые хочется пройти. В статье  автор рассказывает о процессе создания игр для геймбоя. В первой части рассказывает о подготовке и создании спрайтов. Цитата, которая понравилась:<br/><br/>&gt The first order of business was to get the Game Boy to boot. Unless the Nintendo logo is present at the offset &#036104 and the rest of the header is set up correctly, the Game Boy hardware will assume the game cart isn’t inserted properly and refuse to boot.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/9Ez6 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Русский перевод</a>)<br/><br/><a href=http://amp.gs/9Ez5 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Understanding Database Sharding</a><br/>Статья от DigitalOcean, которая объясняет что такое шардинг в базах данных. В тексте рассказывает о том, что это, какие бенефиты и проблемы существуют. Кроме того, показываются примеры шардинга по ключу, отрезку и directory. Однозначный мастрид для тех, кто хочет узнать или вспомнить что это такое.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 764
                    [ViewsLastDateUpdated] => 2019-02-23 08:53:20
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 764
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [11108515] => stdClass Object
                (
                    [ID] => 11108515
                    [TgID] => 138
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-13 22:26:30
                    [Text] => А так же опрос, что бы улучшить качество стримов в следующий раз
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 721
                    [ViewsLastDateUpdated] => 2019-02-23 08:53:19
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [11108514] => stdClass Object
                (
                    [ID] => 11108514
                    [TgID] => 137
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-13 22:25:33
                    [Text] => Всем спасибо за стрим.<br/><br/>Ссылки:<br/><br/>youtube<br/><a href=https://youtu.be/im_uvC4n9rc target=_blank rel=noopener>https://youtu.be/im_uvC4n9rc</a><br/><br/>twitch (удалиться через 14 дней)<br/><a href=https://www.twitch.tv/videos/380045817 target=_blank rel=noopener>https://www.twitch.tv/videos/380045817</a><br/><br/>dry-monads<br/><a href=https://dry-rb.org/gems/dry-monads/ target=_blank rel=noopener>https://dry-rb.org/gems/dry-monads/</a><br/><br/>аналоги из чата<br/><a href=https://github.com/txus/kleisli target=_blank rel=noopener>https://github.com/txus/kleisli</a><br/><a href=https://github.com/bolshakov/fear target=_blank rel=noopener>https://github.com/bolshakov/fear</a><br/><a href=https://github.com/andypike/rectify target=_blank rel=noopener>https://github.com/andypike/rectify</a><br/><br/>примеры кода с монадами (смотреть экшены)<br/><a href=https://github.com/makedecision-org/core target=_blank rel=noopener>https://github.com/makedecision-org/core</a><br/><a href=https://github.com/safelylaunch/core target=_blank rel=noopener>https://github.com/safelylaunch/core</a><br/><br/>Буду рад идеям для следующих стримов, пожеланиям и что понравилось/не понравилось<br/><br/><i class=emoji style=background-image:url(//telegram.org/img/emoji/40/E29DA4.png)><b>❤️</b></i>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 745
                    [ViewsLastDateUpdated] => 2019-02-23 08:53:19
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [11108513] => stdClass Object
                (
                    [ID] => 11108513
                    [TgID] => 136
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-13 20:00:15
                    [Text] => Начинаем стрим.<br/><br/><a href=http://amp.gs/9PfJ target=_blank rel=noopener>http://amp.gs/9PfJ</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 701
                    [ViewsLastDateUpdated] => 2019-02-23 08:53:19
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [10760531] => stdClass Object
                (
                    [ID] => 10760531
                    [TgID] => 135
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-08 16:45:27
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/><br/>Начало февраля выдалось насыщенным, поэтому чтиво будет коротким. Постараюсь исправиться в следующий раз. Вчера выступил в минске, рассказывал о факапах на работе. В минске прекрасные ребята, рекомендую посетить митап или приехать на <a href=http://amp.gs/9pjx target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>конференцию в апреле</a>.<br/><br/>На следующей неделе (суббота, 16 февраля) буду говорить о сервисах в питере на митапе. Буду рад раздать стикеры и пообщаться:<br/><a href=http://amp.gs/9pjp target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Winter SaintP Ruby Meetup</a><br/><br/>А так же, 13 числа будет стрим. Расскажу о dry-monads и ROM/hanami repositories.<br/><br/>Подробности тут: <a href=http://amp.gs/9pjf target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>http://amp.gs/9pjk</a><br/><br/>—————————————<br/><br/><a href=http://amp.gs/9pjj target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Visualizing &amp Tuning Postgres Autovacuum · pganalyze</a><br/>Мартрид для тех, кто не знает или уже забыл что такое автовакум в постгресе. Объясняется что это, зачем и как работает.<br/><br/><a href=http://amp.gs/9pjm target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Architecture and Design Trends Report - January 2019</a><br/>Ребята из InfoQ опубликовали статью с архитектурными трендами на этот год. Из интересного: потребность в эволюционной архитектуре, микросервисы уходят в массы, как и проблемы distributed systems. Event based и actor based системы находятся на early adopters стадии и вряд ли перейдут дальше, а архитекторы уходят в технический leadership. <br/><br/><a href=http://amp.gs/9pjz target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Finding Twitch Streamers in a PUBG Match</a><br/>Статья из серии “а что, так можно было?”. На самом деле обожаю такие штуки. Сегодня рассказывается как автор искал стримы людей, которые играли вместе с ним в PUBG и что из этого вышло.<br/><br/><a href=http://amp.gs/9pjB target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Русский перевод</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2019-02-15 14:56:46
                    [Views1] => 
                    [Views2] => 534
                    [Views3] => 562
                    [Views7] => 1100
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [10760530] => stdClass Object
                (
                    [ID] => 10760530
                    [TgID] => 134
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-02-01 16:40:21
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/><br/>На неделе прошел стрим, говорили о ханами и драй систем. В следующий раз расскажу больше о dry-monads и покажу как устроены репозитории в ханами. Ссылка на прошлый стрим:<br/><a href=http://amp.gs/VoI6 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>pepegramming/133</a><br/><br/>А календарь с предстоящими стримами можно найти тут:<br/><a href=http://amp.gs/VoIb target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>http://amp.gs/VojI</a><br/><br/>Кроме того, на следующей неделе окажусь в минске, буду рассказывать о персональных факапах в разделении монолита на сервисы:<br/><a href=http://amp.gs/VoIQ target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Ссылка на митап</a><br/><br/>—————————————<br/><br/><a href=http://amp.gs/VoIF target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>How to break a Monolith into Microservices</a><br/>Начнем со статьи в блоге Мартина Фаулера о том, как разделять монолит на сервисы. Текст - лонгрид с большим количеством советов, которые выглядят правильно. Начинать стоит с простого домена,  зависимостей должно быть меньше между частями системы, начинать с “макросервисов” действительно проще. Но к сожалению реальность иная: сложно определить, что есть &quotпростой&quot домен, зависимости появляются и не контролируются, а макросервисы превращаются в месиво, которое живет отдельной жизнью. <br/><br/>Статья поверхностная и дьявол в деталях. Но здравые советы и вещи о которых стоит подумать заранее присутствуют.<br/><br/><a href=http://amp.gs/VoIo target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Thanks to Repositories</a><br/>Статья из блога Arkency о том, что такое репозитории и как реализовать с помощью virtus и AR. Сам уже давно думаю о том, чтобы попробовать накрутить репозиториев в рельсе и посмотреть как это будет выглядеть. <br/><br/><a href=http://amp.gs/VoIM target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Introducing dry-schema</a><br/>На неделе вышла новая библиотека в dry, которая призвана улучшить dry-validation. Что ждет dry-v можно посмотреть тут:<a href=http://amp.gs/VoI2 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Introducing dry-schema : ruby</a><br/><br/><a href=http://amp.gs/VoIL target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Hanami | Announcing Hanami v2.0.0.alpha1</a><br/>Ну а так же вышла альфа версия hanami 2.0. Это не полная версия того, что хотим сделать. Но посмотреть что будет можно локально.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2019-02-21 11:18:25
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [10323061] => stdClass Object
                (
                    [ID] => 10323061
                    [TgID] => 133
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-30 22:41:42
                    [Text] => Всем спасибо за стрим. Продакшен починили <i class=emoji style=background-image:url(//telegram.org/img/emoji/40/F09F9885.png)><b>😅</b></i><br/><br/>Ссылки:<br/><br/>youtube<br/><a href=https://youtu.be/gVC0RBnAxqE target=_blank rel=noopener>https://youtu.be/gVC0RBnAxqE</a><br/><br/>twitch (удалиться через 14 дней)<br/><a href=https://www.twitch.tv/videos/372361359 target=_blank rel=noopener>https://www.twitch.tv/videos/372361359</a><br/><br/>Гайды ханами (возможно нужен впн будет)<br/><a href=http://guides.hanamirb.org/ target=_blank rel=noopener>http://guides.hanamirb.org</a><br/><br/>dry<br/><a href=http://dry-rb.org/ target=_blank rel=noopener>http://dry-rb.org</a><br/><br/>пустой репозиторий с ханами и драй системой<br/><a href=https://github.com/davydovanton/pepegraming-stream/tree/master/simple%20hanami target=_blank rel=noopener>https://github.com/davydovanton/pepegraming-stream/tree/master/simple%20hanami</a><br/><br/>ханами репозиторий с драй и бизнес логикой<br/><a href=https://github.com/safelylaunch/core target=_blank rel=noopener>https://github.com/safelylaunch/core</a><br/><br/>Буду рад идеям для следующих стримов, пожеланиям и что понравилось/не понравилось<br/><br/><i class=emoji style=background-image:url(//telegram.org/img/emoji/40/E29DA4.png)><b>❤️</b></i>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 965
                    [ViewsLastDateUpdated] => 2019-02-17 22:49:27
                    [Views1] => 486
                    [Views2] => 679
                    [Views3] => 709
                    [Views7] => 796
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [10323056] => stdClass Object
                (
                    [ID] => 10323056
                    [TgID] => 132
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-30 20:00:39
                    [Text] => Начинаем стрим<br/><br/><a href=https://twitch.tv/davydovanton target=_blank rel=noopener>https://twitch.tv/davydovanton</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 766
                    [ViewsLastDateUpdated] => 2019-02-15 23:24:57
                    [Views1] => 484
                    [Views2] => 585
                    [Views3] => 593
                    [Views7] => 648
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [10323049] => stdClass Object
                (
                    [ID] => 10323049
                    [TgID] => 131
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-30 14:05:04
                    [Text] => Привет&#33<br/><br/>Сегодня среда, а значит день стрима. Будем делать маленькое hanami приложение для работы с rss. Так же будем использовать dry-system и dry-monads. Покажу зачем это надо, как использовать и объясню тестировать.<br/><br/>Стрим в 20:00 по москве: <a href=https://twitch.tv/davydovanton target=_blank rel=noopener>https://twitch.tv/davydovanton</a><br/><br/>Кроме того, сделал сайт с календарем стримов. Пока там только календарь, но в будущем планирую перевести туда посты.<br/><a href=http://amp.gs/Vw1H target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)><br/>http://pepegramming.site</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 997
                    [ViewsLastDateUpdated] => 2019-02-15 23:25:00
                    [Views1] => 679
                    [Views2] => 732
                    [Views3] => 801
                    [Views7] => 859
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [10323043] => stdClass Object
                (
                    [ID] => 10323043
                    [TgID] => 130
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-25 16:35:12
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/><br/>На следующей неделе (среда, 30 января, 20:00 по москве) будет стрим. Пока делаю страницу с календарем, чтобы посмотреть стримы заранее. <br/><br/>—————————————<br/><br/><a href=http://amp.gs/VqtA target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Analyzing RubyGems stats for 2018</a><br/>Уверен, статья появится в других рассылках, но это не значит, что ее стоит пропустить. Автор проанализировал экосистему языка за 2018 год. Немного результатов: количество новых гемов уменьшается (думаю это связано со зрелостью экосистемы), установки рельсы растут, а синатра и ханами без изменений. Виден резкий спайк по установкам <a href=http://amp.gs/Vqtu target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Passenger</a> в мае. Ну и как итог, рост экосистемы на 28% по сравнению с прошлым годом.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/Vqtr target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Launching your own Ruby gem - Part 2: Promote it</a><br/>Если спросят, что вызывает проблемы в создании библиотеки, я отвечу - это пиар и “продажа” другим людям. В статье описываются шаги, благодаря которым библиотека станет привлекательнее в глазах других разработчиков. В конце приводится список ресурсов, где можно рассказать о библиотеке. Если вы сделали библиотеку или опенсорсный продукт и хотите рассказать об этом, пишите, опубликую в рассылке.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/VqtU target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Good Engineering Practices while Working Solo</a><br/>Я люблю использовать &quotправильные&quot практики, в персональных проектах, даже когда работаю над ними один. Это помогает попробовать новые процессы без планирования и лишнего обсуждения. А в случае успеха и появления команды, не придется тратить время на изменение процессов и борьбу с людьми. В статье описывается, что можно и стоит использовать, когда работаете в одиночку над проектом.<br/><br/><a href=http://amp.gs/VqtD target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Русский перевод</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2019-02-21 15:48:46
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 1000
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [9814457] => stdClass Object
                (
                    [ID] => 9814457
                    [TgID] => 129
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-18 15:40:11
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/><br/>На этой неделе провел стрим, делал http клиент для pet проекта. Больше ссылок тут:<br/><a href=http://amp.gs/VeQM target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>http://amp.gs/VecI<br/><br/>В ближайшее время планирую сделать календарь со стримами, попробовать новые форматы и доделать пару постов.<br/><br/>—————————————<br/><br/>[Ruby 2.7 new feature: Method reference operator</a><br/>Не успел выйти 2.6, как уже появляются примеры новых методов в будущем 2.7. Первый в нашем списке - <code>42.:to&#092_s</code>. По сути, это  экспериментальный алиас для <code>42.method(:to&#092_s)</code>, который уже попал в транк ветку языка. В статье описывается подробнее что это, как этим пользоваться и что с этим делать. А также примеры где это применить и как попробовать сегодня.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/VeQa target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Rails Architect MasterClass: Bounded Contexts</a><br/>Мне фана польского руби комьюнити. Там часто обсуждаются DDD и архитектурные вопросы. Сегодня статья Mariusz Kapcia о том, что такое bounded context. В статье: что это такое, как найти и как взаимодействует с другими частями системы.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/VeQ5 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Scaling Ruby Apps to 1000 Requests per Minute</a><br/><a href=http://amp.gs/VeQ6 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Memory profiler tools for ruby</a><br/><a href=http://amp.gs/VeQo target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Fastest way to profile a method in Ruby</a><br/>Последнюю неделю занимаюсь проблемой перформанса на работе. Поэтому сегодня 3 ссылки, которые могут помочь.<br/><br/>В первой делается упор на реквесты. Рассказывается как реквесты проходят в руби приложениях, а также о том, какие веб сервера бывают в руби мире. Описывается в чем между ними отличие и в чем отличие между способами работы (треды против форков пумы, как пример). В конце приводится пару примеров как скейлиться и как правильно сконфигурировать сервер под текущие условия.<br/><br/>Вторую статью я написал 4 года назад. В тексте найдете описание трех способов профилирования памяти руби кода. Мой фаворит - Ruby Memory Profiler.<br/><br/>Третья статья о том, как сделать бенчмарк, чтобы определить насколько быстрее стал код. Секрет успеха прост - <code>benchmark/ips</code> и  скрипт с вариантами тестирования. В статье показываются примеры использования и как работать с бенчмарками и тредами.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2019-02-19 07:53:58
                    [Views1] => 
                    [Views2] => 521
                    [Views3] => 534
                    [Views7] => 601
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [9814456] => stdClass Object
                (
                    [ID] => 9814456
                    [TgID] => 128
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-16 22:03:38
                    [Text] => Спасибо всем кто пришел<br/><br/>Запись на ютубе<br/><a href=https://youtu.be/9lV3SwbJf-0 target=_blank rel=noopener>https://youtu.be/9lV3SwbJf-0</a> (аплоадится)<br/><br/>Запись на твитче<br/><a href=https://www.twitch.tv/videos/364871271 target=_blank rel=noopener>https://www.twitch.tv/videos/364871271</a><br/><br/>Ссылка на гитхаб репозиторий с кодом<br/><a href=https://github.com/safelylaunch/ruby-client target=_blank rel=noopener>https://github.com/safelylaunch/ruby-client</a><br/><br/>Буду рад идеям для следующих стримов, пожеланиям и что понравилось/не понравилось<br/><br/><i class=emoji style=background-image:url(//telegram.org/img/emoji/40/E29DA4.png)><b>❤️</b></i>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 905
                    [ViewsLastDateUpdated] => 2019-02-17 03:25:42
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 690
                    [Views30] => 902
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [9814455] => stdClass Object
                (
                    [ID] => 9814455
                    [TgID] => 127
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-16 20:00:12
                    [Text] => Начинаем первый стрим этого года<br/><a href=http://amp.gs/VG5L target=_blank rel=noopener>http://amp.gs/VG5L</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 876
                    [ViewsLastDateUpdated] => 2019-02-17 03:25:25
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 692
                    [Views30] => 829
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [9814454] => stdClass Object
                (
                    [ID] => 9814454
                    [TgID] => 126
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-16 14:56:02
                    [Text] => Привет&#33<br/><br/>Сегодня среда, а это значит, что в 20:00 по московскому времени начинаем стрим.<br/><br/>В этот раз решил считерить, поэтому буду делать клиентскую библиотеку для pet проекта, заодно и покажу чем занят последние пару недель. В программе: <a href=http://amp.gs/VGY9 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Readme Driven Development</a>, покажу, как последние пару лет делаю подобные библиотеки, а так же сделаем топорный in memory cache для того, что бы не досить сервер.<br/><br/>Стартуем в 20:00, ссылка на твич:<br/><a href=http://amp.gs/VGY4 target=_blank rel=noopener>http://amp.gs/VGY4</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2019-02-17 03:17:20
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 820
                    [Views30] => 953
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [9814453] => stdClass Object
                (
                    [ID] => 9814453
                    [TgID] => 125
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2019-01-11 15:25:05
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет, первые ссылки этого года уже приехали. Из-за усталости пропустил прошлый стрим, в следующую среду наверстаем.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/VTpf target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Exploring a critical Net::Protocol issue in Ruby 2.6.0p0 and how it can lead to a security problem</a><br/>Статья которая взрывает твиттер уже второй день. <a href=http://amp.gs/VTpA target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Maciej Mensfeld</a>, автор karafka, описал критический баг в 2.6 руби связанный с <code>Net::Protocol</code>. Проблема заключается в том, что <code>Net::HTTP</code> может “съесть” символы в http запросе. В лучшем случае получите ошибку, а в худшем формат данных (json тоже) обрезается так, что сервер получает не полную, но валидную информацию. <a href=http://amp.gs/VTp4 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Патч</a> уже замержили в язык + в статье приводятся патчи для <code>Net::HTTP</code> и <code>Faraday</code>.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/VTpO target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Ruby in AWS Lambda with PostgreSQL / Nokogiri</a><br/><a href=http://amp.gs/VTpP target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>CircleCI private Slack notifications with a Ruby AWS Lambda</a><br/><a href=http://amp.gs/VTpv target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Serverless Ruby Cron Jobs Tutorial: Route53 Backup</a><br/>В прошлом году амазон добавил руби в lambda, о чем уже писалось. За это время появились статьи с примерами использования этой технологии. Сегодня - список статей с примерами того, как использовать руби в лямбдах и зачем это может быть нужно. К сожалению у меня так и не дошли руки до лямбд, но если вы успели поиграть с ними, буду рад почитать или послушать отзывы.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/VTpN target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Function composition &gt&gt</a><br/>Кто работал (или изучал) функциональные языки, касался темы композиции функций. В руби 2.6 добавили оператор <code>&gt&gt</code>, который делает тоже самое. В статье описывается что это, сравнивается композиций функций с наследованием. Автор объясняет зачем это нужно и как использовать. А также дается не стандартный пример использования композиции функций для обработки http запросов.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1300
                    [ViewsLastDateUpdated] => 2019-02-14 10:00:20
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562153] => stdClass Object
                (
                    [ID] => 8562153
                    [TgID] => 124
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-28 17:52:02
                    [Text] => А так же, в течении года просили рассказать о понравившихся технических и нетехнических книгах. Поэтому расскажу о 7 книгах, которые прочитал и понравились в этом году.<br/><br/><b>Технические</b><br/><br/><a href=http://amp.gs/EuKS target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Designing Data-Intensive Applications (DDIA)</a><br/>Однозначный мастрид года среди технической литературы. Я рассказывал и разыгрывал эту книгу на RubyRussia в этом году и постоянно рекламирую. Из книги узнаете:<br/><br/>1.  Чем отличаются реляционные, документоориентированные и графовые базы данных<br/>2. В чем отличие json от протобафа и авро<br/>3. Зачем думать об эволюции данных и где это нужно<br/>4. Что такое репликации, как работать с секционированием и транзакциями<br/>5. Узнаете об проблемах распределенных систем, почему консенсус важен<br/>6. Как работать с массивами данных<br/><br/>Если этого мало, после каждой главы список из 50+ ссылок в библиографии. Также, существует перевод на русский.<br/><br/><a href=http://amp.gs/EuKR target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Domain Modeling Made Functional</a><br/>Книга разделена на 2 части: в первой объясняется что такое Domain Modeling, во второй, на примере F# показывается, как воплотить теорию из первой части в практику. Обратите внимание на книгу, если хотите разобраться в DDD и (или) посмотреть на F#.<br/><br/><a href=http://amp.gs/EuKd target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Building Microservices</a><br/>Еще одна книга справочник - создание микросервисов. Описывается моделирование, архитектура развития сервисов. Как тестировать, разбивать монолиты на части и интегрировать микросервисы в существующую экосистему. Также затрагивается тема безопасности, масштабирования и мониторинга. Если не хватает опыта сервисной архитектуры - книга поможет уменьшить количество ада.<br/><br/><b>Не технические</b><br/><br/><a href=http://amp.gs/EuK9 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Джедайские техники</a><br/>Главная книга этого года. Книга, которая заставила посмотреть иначе на планирование и работу с головой. Автор поможет научиться как работать и разгружать голову. Узнаете, как работает голова, почему задачи в TODO списке лежат вечно, а желание их сделать не появится. Перенял “спусковые крючки”, помогает разгружать голову в конце недели. Кроме того, советую послушать доклады автора, узнаете о теории ограничений.<br/><br/><a href=http://amp.gs/EuK4 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Преломление</a><br/>Нейрофизиолог пишет о том, как работает мозг, почему ошибается и почему одна и та же анимация воспринимается мозгом по разному. В книге хватает идей для размышления: как мозг представляет мир, почему решение, которое принимает разум, на самом деле уже было принято бессознательным и так далее.<br/><br/><a href=http://amp.gs/EuKr target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Юнг в комиксах. Биография, идеи, труды</a><br/><a href=http://amp.gs/EuKU target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Спустя два года терапии</a>, стало интересно разобраться с основами различных школ терапии. Читать талмуды было скучно, поэтому решил попробовать начать с комикса о Юнге. И не ошибся, читается легко, хватило одного вечера в поезде. Основных столба аналитики два: Юнг и Фрейд. Комикс рассказывает о жизни и идеях, которые предложил Юнг и почему это не нравилось Фрейду. Особенно понравились: архетипы, компенсирующие функции психики, самость и почему Юнг считал, что алхимики говорили о психике а не о физических предметах.<br/><br/><a href=http://amp.gs/EuKO target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Антихрупкость. Как извлечь выгоду из хаоса</a><br/>Долгая и сложная книга, которую не смог прочитать до конца. Вариант, который сработал -  читать 1 страницу в день, а потом переваривать что прочитал. В книге много критических вещей, везения и прочих странных вещей, но подумать об антониме хрупкости (твердость и прочность не являются противоположностью) интересно. К тому же, книгу стоит прочитать только ради примера с индейкой.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2019-02-10 11:17:32
                    [Views1] => 413
                    [Views2] => 492
                    [Views3] => 520
                    [Views7] => 606
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562151] => stdClass Object
                (
                    [ID] => 8562151
                    [TgID] => 123
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-28 17:23:00
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Сегодня последняя пятница этого года, а значит последние ссылки в этом году. Ссылки уходят в отпуск до 11 января, стрим устроим 2го января (готовьте оливье и мандарины). <br/><br/>—————————————<br/><br/><a href=http://amp.gs/Eui2 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>What are your programming goals for 2019?</a><br/>Поднимаем новогоднее настроение. Разработчики из Dev community делятся целями на следующий год. Было бы интересно увидеть статистику:<br/><br/>Чего ждут другие разработчики больше всего?<br/>Что в “трендах” ожидания в этом году, а что было в прошлых годах?<br/><br/>Если хотите поделиться целями или итогами года - с радостью опубликую в канале.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/Euiw target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Making maps connectable: stable, non-proprietary IDs and data standards for streets</a><br/>Описание стандарта описания улиц SharedStreets. Обожаю открывать новые стандарты. Сегодня в списке стандарт, который поможет работать с улицами, картами и графами.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/EuiH target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>A Brief Guide to Learning Faster (and Better)</a><br/>Знаю, что разработчики любят тратить выходные на проекты, обучение и иной отдых. Поэтому однозначный мастрид - статья 2011 года, которую стараюсь перечитывать каждый год. В статье найдете: советы эффективного обучения, как строить связи между идеями, 4 правила изучения чего угодно и россыпь идей и примеров.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 893
                    [ViewsLastDateUpdated] => 2019-02-10 12:08:21
                    [Views1] => 444
                    [Views2] => 500
                    [Views3] => 524
                    [Views7] => 573
                    [Views30] => 813
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562149] => stdClass Object
                (
                    [ID] => 8562149
                    [TgID] => 122
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-21 16:02:44
                    [Text] => &gt Теперь трепло пишет<br/><br/>опечатался, поправить сложно будет ибо полетят все ссылки <i class=emoji style=background-image:url(//telegram.org/img/emoji/40/F09F9981.png)><b>🙁</b></i>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 987
                    [ViewsLastDateUpdated] => 2019-02-01 18:05:05
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 749
                    [Views30] => 929
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562148] => stdClass Object
                (
                    [ID] => 8562148
                    [TgID] => 121
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-21 15:45:06
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/>На этой неделе провел стрим, следующий думаю будет на новогодних праздниках. Ссылки в посте выше:<br/><a href=http://amp.gs/EVZO target=_blank rel=noopener>http://amp.gs/EVZO</a><br/><br/>—————————————<br/><br/><a href=http://amp.gs/EVZR target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>From &#036erverless to Elixir – CoryODaniel – Medium</a><br/>Это не первая статья о серверлесс приложениях. До этого делился статьей о том, как сделать первое руби приложение на лямбдах. Сегодняшняя тема: а действительно ли это нужно и как дорого обойдется подобное решение.<br/>Статья понравилась не навязчивостью и реальным примером. А также тем, что задаются вопросы и не даются однозначные ответы. Нет характеристик что лучше и что правильнее. Даже когда выяснилось, что простой POST эндпоинт в лямбде стоит 30k&#036 в месяц, автор честно написал, что для кого-то это дешевле, чем команда опсов.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/EVZ4 target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Printing Over Previously Printed Characters and Lines - Steven Occhipinti</a><br/>CLI это конечно круто, но что бы сделать некоторые части интерфейса, нужно знать nix или целенаправленно искать ответ. Пример - динамическая отрисовка прогресс бара и другие динамически обновляющиеся части интерфейса. В статье выше собраны примеры работы с курсором и удалением текста в терминале с помощью руби. Будет полезно для инженеров, которые хотят сделать динамический CLI интерфейс, но не знает как. Для себя открыл управление курсором и <code>&#092b</code>.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/EVZU target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Why We Chose Kafka For The Trello Socket Architecture</a><br/>Еще одна статья о опыт. Теперь трепло пишет почему сервис переехал с RabbitMQ на Kafka. В статье найдете: проблемы, таблицу со сравнением сервисов для работы с сообщениями, обзор кафка библиотек и результаты (с метриками, ценой и простоем). Стоит отметить, что кроме кафки рассматривались еще SNS + SQS, SNS + FIFO SQS, Kinesis и <a href=http://amp.gs/EVZd target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Redis Streams</a>.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 979
                    [ViewsLastDateUpdated] => 2019-02-01 18:05:06
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 736
                    [Views30] => 858
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562146] => stdClass Object
                (
                    [ID] => 8562146
                    [TgID] => 120
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-19 21:04:31
                    [Text] => Спасибо всем кто пришел<br/><br/>Запись на ютубе<br/><a href=https://youtu.be/yWQjisIV5pw target=_blank rel=noopener>https://youtu.be/yWQjisIV5pw</a><br/><br/>Запись на твитче<br/><a href=https://www.twitch.tv/videos/351321379 target=_blank rel=noopener>https://www.twitch.tv/videos/351321379</a><br/><br/>Ссылка на гитхаб репозиторий с кодом и ссылками на ресурсы<br/><a href=https://github.com/davydovanton/pepegraming-stream/tree/master/credit_card_validator target=_blank rel=noopener>https://github.com/davydovanton/pepegraming-stream/tree/master/credit_card_validator</a><br/><br/>Буду рад идеям для следующих стримов, пожеланиям и что понравилось/не понравилось<br/><br/><i class=emoji style=background-image:url(//telegram.org/img/emoji/40/E29DA4.png)><b>❤️</b></i>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2019-02-01 17:37:04
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 956
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562145] => stdClass Object
                (
                    [ID] => 8562145
                    [TgID] => 119
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-19 20:00:11
                    [Text] => <a href=http://amp.gs/Eyll target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Начинаем стрим</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 880
                    [ViewsLastDateUpdated] => 2019-02-01 17:49:53
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 777
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562143] => stdClass Object
                (
                    [ID] => 8562143
                    [TgID] => 118
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-18 23:41:45
                    [Text] => Привет&#33<br/><br/>Завтра (19.12) будет очередной стрим на твиче. Следующая задача:<br/><a href=http://amp.gs/EeAm target=_blank rel=noopener>http://amp.gs/EeAm</a><br/><br/>Разберемся как валидировать банковские карты. А так же что нужно для того, что бы сгенерировать карту и как это делают банки. Только открытая информация со всеми ссылками.<br/><br/>Начало в 20:00 по москве, ссылка на твич:<br/><a href=http://amp.gs/EeAZ target=_blank rel=noopener>http://amp.gs/EeAZ</a>
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 878
                    [ViewsLastDateUpdated] => 2019-02-01 17:49:54
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 809
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [8562142] => stdClass Object
                (
                    [ID] => 8562142
                    [TgID] => 117
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-14 19:11:33
                    [Text] => <b>Пятничное чтиво</b><br/><br/>Привет&#33<br/><br/>Неделя оказалась сложнее чем рассчитывал, поэтому с рассылкой запоздал. Так же, планирую в следующую среду опять провести стрим, в этот раз будем делать валидатор для кредитных карт. Подробности на следующей неделе&#33<br/><br/><a href=http://amp.gs/El8v target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>CastlevaniaBot</a><br/>Я далек от нейронных сетей и дата сайнса. Но читать статьи о том, как сделать бота для культовой игры готов всегда.<br/><br/>Автор написал бота, который проходит castlevania на эмуляторе NES (nintendo entertainment system), которая больше известна в россии как денди. Описывается как находить врагов и взаимодействовать с миром. А так же описывается как проходятся отдельные части уровней (например последний босс - дракула).<br/><br/><a href=http://amp.gs/El8E target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Русский перевод</a><br/><br/>—————————————<br/><br/><br/><a href=http://amp.gs/El8h target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Ruby Sinatra on AWS Lambda</a><br/>AWS анонсировал ruby как еще один язык для lambda. Теперь появляются статьи о том, как с этим жить. В статье выше на примерах показывается как работает и зачем нужна лямбда. А также, что нужно знать для первого приложения и шаг за шагом описывается, как сделать приложение на руби и синатре.<br/><br/>Серверлесс архитектуры вызывают двоякое ощущение, с одной стороны - круто, что можно быстро и просто имплементировать эндпоинты. С другой, не понятно как лучше это делать, сколько это стоит и какие проблемы это принесет. К тому же, возникает вопрос, как быстро перестроить мышление на новую архитектуру.<br/><br/>—————————————<br/><br/><a href=http://amp.gs/El8g target=_blank rel=noopener onclick=return confirm(Open this link?\n\n+this.href)>Deep Work: How to Develop the Most Valuable Skill of the 21st Century -</a><br/>Состояние потока приятно и продуктивно, в статье описывается 5 шагов для того, чтобы попасть в это состояние. Скажу честно, не еще не успел попробовать, но мне помогает ритмичная музыка, ясное понимание задачи, отсутствие технических вопросов и дедлайн. Спустя время, все больше понимаю, что в моем случае ясное понимание задачи становится приоритетнее. При этом, потратив кучу времени на понимание задачи, можно просто расслабиться и делать дела.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1300
                    [ViewsLastDateUpdated] => 2019-01-25 18:03:48
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 1300
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [5402158] => stdClass Object
                (
                    [ID] => 5402158
                    [TgID] => 116
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-07 16:34:18
                    [Text] => Ссылка на ютуб канал со стримами (качество не очень вышло, постараюсь исправить)  https://www.youtube.com/playlist?list=PL6n1fvXhQN4kOm_HhBDJrynj6_dcl7VJP
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 965
                    [ViewsLastDateUpdated] => 2019-01-20 20:21:01
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 578
                    [Views30] => 890
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [5402157] => stdClass Object
                (
                    [ID] => 5402157
                    [TgID] => 115
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-12-07 16:30:13
                    [Text] => Пятничное чтиво

Привет&#33
На неделе провел первый стрим, объяснил и показал как написать простейший парсер математических формул и объяснил как обратная польская нотация может помочь в вычислении такси строк. Ссылка на видео.

Следующий стрим планирую сделать через неделю. Будем делать валидатор для банковских карт. Если у есть идеи для проектов - пишите.

Так как 12 декабря буду рассказывать о граблях,  на которые наступил за последние полгода в выковыривали сервиса из монолита. Много боли, слез и крови.

—————————————

Four things about Pry – Runtime Revolution
Так сложилось, что у меня натянутые отношения с pry.rb. Не смог использовать на постоянной основе, а сейчас уже сложно переучиться. Об этом даже упоминал на прошлом стриме. Но, статьи с tips&amptrics об инструментах люблю.

После прочтения прокачаете чуть больше pry skill, а после сможете удивлять коллег и быстрее проверять код в REPL.

—————————————

Markov Chains
Статья с реалтайм примерами в браузере, в которой рассказывается о цепях маркова, что это и как работают. Я не писал такие цепи до этого, возможно стоит добавить цепи в список проектов для стрима (если хотели бы видеть разбор и код цепей стриме - пишите об этом).

—————————————

Личный опыт: как не копить закладки и успевать всё читать
Давно не было статей в закладки. Добавить нечего. Скажу честно, эту ссылку я пытался прочитать 5 раз и так и не осилил. Было бы круто устроить интерактив и собрать других советов. Поэтому, расскажите, как справляетесь с тысячами вкладками и покетом на несколько сотен статей? Для затравки поделюсь статьей @vanadium23 о том, как держать покет в чистоте:

Держи кармашек в чистоте
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 974
                    [ViewsLastDateUpdated] => 2019-01-20 18:41:45
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 617
                    [Views30] => 894
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [5077012] => stdClass Object
                (
                    [ID] => 5077012
                    [TgID] => 107
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-11-16 16:45:14
                    [Text] => Пятничное чтиво

Functional architecture is Ports and Adapters
Статья пример того, как переплетаются функциональные подходы с архитектурными паттернами. Основная часть текста - рассуждение с примерами на тему того, как же использовать чистые и не чистые функции в хаскеле или F# и как это похоже на подход проектирования систем с помощью адаптеров и портов. Интересно будет для расширения кругозора и как пример взаимодействия и дополнения подходов в функциональных языках и архитектурах систем.

Русский перевод

—————————————

Cloud Diagrams &amp Notes

Список картинок о том, как работают сервисы AWS. Для меня это открытие недели, так как постоянно забываю что есть что или просто путаюсь в сервисах от амазона.

—————————————

How to teach yourself hard things

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

Добавлю, что кроме упора на продуктивность, стоит не забывать о перерывах для отдыха. Иногда перерыв длится пару часов, иногда недели. Важно в такие моменты не корить себя, а дать голове переварить информацию.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2018-12-28 23:22:18
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [5040383] => stdClass Object
                (
                    [ID] => 5040383
                    [TgID] => 106
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-11-14 14:44:22
                    [Text] => так же, подсказали важную мысль на счет самоутверждения и доверия, дополнил тексты
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2018-12-25 20:50:01
                    [Views1] => 470
                    [Views2] => 499
                    [Views3] => 696
                    [Views7] => 773
                    [Views30] => 991
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [5040382] => stdClass Object
                (
                    [ID] => 5040382
                    [TgID] => 105
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-11-14 14:15:05
                    [Text] => На работе попробовал новую для себя практику post review. Делюсь опытом.

Medium
Telegraph
MindNode
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2018-12-25 20:45:09
                    [Views1] => 496
                    [Views2] => 539
                    [Views3] => 707
                    [Views7] => 783
                    [Views30] => 984
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [5040381] => stdClass Object
                (
                    [ID] => 5040381
                    [TgID] => 104
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-11-09 15:40:06
                    [Text] => Пятничное чтиво

Maintaining 65k open connections in a single Ruby process
Соеденив вместе puma, rack и hijacking получим развлечение на вечер и статью, в которой автор подробно рассказывает как с помощью этих вещей добиться обработки 65523 открытых коннекшенов. В конце статьи - ссылка на гист с полным кодом (всего 55 строк кода с комментариями).
Из проблем: такой код съедает 350 мб памяти, что много (nginx для примера потребляет 2.5 мб), race conditions проблемы (поправились с помощью использования http://amp.gs/vXFN и http://amp.gs/vXFA).
Если хотите разобраться как подобные штуки работают и как еще можно ускорить приложение - маст рид.

—————————————

Architecture of a high performance GraphQL to SQL engine
В первый раз, когда увидел graphQL подумал, что было бы круто получить сервис с 1 в 1 доступом к базе. Спустя 3 года появилась статья, которая описывает как работает Hasura, сервер-прослойка между клиентами и постгресом. Стоит обратить внимание, что сервис написан на хаскеле, по бенчмаркам быстрее prisma и postgraphile. Надеюсь что подобные сервисы смогут в будущем элегантно решить проблему кастомной логики.

Русский перевод

—————————————

Six Great Reasons to Build Service Architectures in Ruby with Eventide
За eventide слежу давно. Даже упоминал этот проект пару раз в выступлениях. Для тех кто не в курсе, eventide - тулкит для построения ES систем на руби. Много фич, огромная и полная документация. В статье выше описываются 6 причин, почему eventide стоит попробовать. Для меня причины спорные, но для ознакомления стоит прочитать.

Рад, что таких проектов становится больше. Так же стоит посмотреть на sequent и RailsEventStore. Круто, что библиотеки не просто появляются, но и развиваются. А так же, появляется больше ES ориентированных конференций в мире руби.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1500
                    [ViewsLastDateUpdated] => 2018-12-22 15:28:51
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 1100
                    [Views30] => 1400
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [5040380] => stdClass Object
                (
                    [ID] => 5040380
                    [TgID] => 103
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-11-02 15:45:06
                    [Text] => Пятничное чтиво

Microservices Are Something You Grow Into, Not Begin With — Nick Janetakis
Давно задумываюсь о том, что микросервисы - архитектурный блокчейн. Считаю, что это кейворд, который усложняет стартапы и полезен только гигантам вроде гугла или в системах, где распределенная архитектура архи важна. На деле микросервисы приносят много новой, асинхронной боли (привет distributed мир), о которой больше говорят. Как пример, segment, который мы используем на работе, поделился историей не обдуманного использования микросервисной архитектуры.

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

Перевод на русский.

—————————————

Why You Should Never Use MongoDB
Люблю истории, особенно истории провалов. В статье выше, ребята из диаспоры рассказывают о том, как начинался проект, почему выбор пал на монгу и как потом перенесли данные в постгресс. В истории идеально все. Понравился опыт хранения социальных данных и способы работы с ними.

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

Перевод на русский.

—————————————

Concurrent Ruby with Tasks · software is fun
Асинхронный код - боль. Использование concurent-ruby в бизнес логике - двойная боль. В функциональных языках для подобных вещей используется Task монада, в js - promises. @flash_gordon сделал реализацию подобной монады в dry-monads, а в статье выше описано зачем Task нужен, как пользоваться и приводится примеры работы с Do нотацией.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-12-17 05:27:00
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4937544] => stdClass Object
                (
                    [ID] => 4937544
                    [TgID] => 102
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-10-26 15:45:02
                    [Text] => Пятничное чтиво

Seven Microservices Anti-patterns
В интернете слишком много информации о пользе микросервисов и почему это круто. Но лично мне не хватает информации об ошибках, которые совершаются в таких системах. Поэтому сегодня - 7 паттернов, которые помогут упростить создание и поддержку подобной архитектуры.

Совет о гейтвее (Building a gateway in every service) зарезонировал с внутренним архитектором. Причина в том, что в системах о которых читал или слышал, клиенты вызывали сервисы в рандомном порядке. Это приводит к сложности: один сервис  начинает вызывать неограниченное количество других сервисов, которые по цепочки вызывают друг друга. Сервисы начинают знать друг о друге, что может влиять на изоляцию и поддерживаемость кода. Элегантное решение проблемы - gateway прослойка, которая последовательно вызывает нужные сервисы и с которой обращаются другие клиенты. 

HTTP/2 for Ruby Web Development
Еще один “modern asynchronous HTTP/2 capable web server” для руби. Что понравилось: чистый руби, может в  http/2, поддерживает rack приложения. К тому же, ребята с ходу пишут, что продакшен код, использ хоть сейчас.
Но к сожалению к этой штуке хватает и вопросов: как быстро работает? Что с памятью? На сколько сервер готов к продакшену?

Поэтому будет интересно посмотреть, во что превратиться проект, а также, попробовать запустить Falcon в своих проектах.

Understanding user support systems in open source
Open source проект в первую очередь продукт, а не открытый код. Это значит, что у проектов есть пользователи. А где люди, там ответы на вопросы и решение проблем. В статье выше описывается как построить систему помощи пользователям.

Как мейнтейнер - круто, что таких статей становится больше, потому что, в мелких и средних OSS проектах не хватает людей, которые понимают, как улучшить жизнь проекта и людей вокруг него. Возможно в этом причина не оптимальных процессов релизов, работы и анбординга (если такие процессы есть). Или сложностей с получением помощи, а также неочевидные фичи, которые пытаются сделать мейнтейнеры. Так что, если хотите пойти в менеджеры, а на работе не пускают - попробуйте помочь open source проекту со внутренними процессами.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-12-01 11:41:09
                    [Views1] => 516
                    [Views2] => 540
                    [Views3] => 587
                    [Views7] => 686
                    [Views30] => 686
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4903067] => stdClass Object
                (
                    [ID] => 4903067
                    [TgID] => 101
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-10-19 15:20:11
                    [Text] => Пятничное чтиво

Целостность данных в микросервисной архитектуре 
Архитектурная статья из авито о том, как сохранить данные в микросервесной архитектуре с зоопарком баз данных.  Рассматривается ACID принцип в связке с микросервисами. Для обеспечения целостности предлагается использовать сага паттерн. Вообще, сага паттерн не заслуженно пропускается в мире руби разработчиков, хотя в некоторых моментах может сильно облегчить жизнь, когда приходится делать бизнес транзакции со сторонними сервисами. Ну и ссылка из ссылки о паттерне в придачу.

Am I doing it wrong?
Cервис объекты приходили в rails тяжело и вызывали много боли у людей привыкшим к rails way (исправте меня, если не прав). В гисте выше разработчик, которого уволили за сервис объект в проекте, спрашивает правильно ли он сделал и как с этим жить дальше. Из интересных комментаторов: Avdi Grimm, Mike Perham, Nick Sutterer, Piotr Solnica и DHH.

How to Read Source Code
Мне сложно читать чужой код. Это отнимает силы, время и мотивацию. К сожалению, заниматься этим приходиться часто, поэтому статьи с идеями, как упростить этот процесс - ❤️.

Добавлю два совета по чтению чужого кода:
- когда документация желает лучшего, смотрите в интеграционные тесты
- если нужно быстро разобраться что и как библиотека делает - дебаггер выручает. В руби открываем исходники (bundle open &ltgem name&gt) ставим дебагер и проходим, смотря что происходит
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-11-21 10:04:08
                    [Views1] => 543
                    [Views2] => 553
                    [Views3] => 599
                    [Views7] => 696
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4869949] => stdClass Object
                (
                    [ID] => 4869949
                    [TgID] => 100
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-10-12 15:20:11
                    [Text] => Пятничное чтиво

User-defined Order in SQL
Сортировка, заданная пользователем не тривиальная задача. На каждый случай в голову приходит тысячи вариантов решения проблемы. В тексте показано, как реализовать алгоритм пользовательской сортировки дешево, используя толкьо одно поле в базе. Если задумали сделать аналог трелло или понадобилась подобная сортировка - однозначный маст хев.

Что бы не спойлерить решение, предлагаю игру. Напишите на бумаге решение, а потом прочтите статью и сравните решения. Если решение кардинально отличается - присылайте ссылку на гист с описанием, опубликую.

Testing best practices
Обожаю гитлаб за открытость. Два года назад, забрал кучу полезных идей из плейбука, а после - сделал описание hanami-paybook по аналогии с гитлабовским. Сегодня - мануал о тестировании в рельсе. Зацепил fast&#092_spec&#092_helper.rb,  хочу попробовать использовать похожую практику в своих проектах. Так же, будет интересно тем, кто хочет узнать, как тестировать большие приложения и где можно срезать время выполнения тестов.

Why Funding Open Source is Hard
На RubyRussia в первый раз проводились круглые столы о сервисах, найме и OpenSource. При обсуждении OSS поднялась тема финансирования продуктов с открытым исходным кодом. Из-за этого, вспомнилась статья о том, почему так тяжело привлекать средства в опенсорс.

В статье подробно описываются возможные виды финансирования, приводится пример проекта Code Sponsor, а так же задаются вопросы, почему же это так сложно и что с этим делать.

Русский перевод на хабре.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1300
                    [ViewsLastDateUpdated] => 2018-11-18 00:53:23
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 784
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4869948] => stdClass Object
                (
                    [ID] => 4869948
                    [TgID] => 99
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-10-11 17:15:12
                    [Text] => После открытого стола об open source проектах на rubyrussia задался вопросом, а какие проблемы испытывают люди. Я нашел четыре разных группы лиц, проблемы которых сильно отличаются. Таким образом появился эта короткая форма. Буду рад  вашим ответам, а результаты опубликую в ближайшее время.

https://goo.gl/forms/LPHPIYWJzUUkjqF52
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2018-11-18 00:53:24
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 829
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4751488] => stdClass Object
                (
                    [ID] => 4751488
                    [TgID] => 96
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-10-05 15:10:14
                    [Text] => Пятничное чтиво

В прошлый раз пропустил из-за розыгрыша. Сегодня исправляюсь.

Software Architecture Patterns Book
Бесплатная книга о различных архитектурных паттернов систем. Подробно расскажет о пяти видах архитектур:

- Layered architecture
- Event-driven architecture
- Microkernel architecture
- Microservices architecture
- Space-based architecture

Хочу обратить внимание на вторую главу, в которой описывается построение Event-Driven архитектуры. Приводится в пример две топологии, mediator и broker. Идея в том, что в mediator топологии кастомер кладет инициирующий эвент в общую очередь эвентов, а медиатор уже организует события по определенным каналам. В broker топологии используется обратный подход: эвент обрабатывается распределенно и при каждой обработке могут добавляться новые события в очередь эвентов.

DDD for Rails Developers. Part 1: Layered Architecture
DDD набирает обороты в мире руби. Слоистые архитектуры покоряют умы разработчиков. В статье доступное описание зачем это нужно, как сделать и что это такое. Много очевидных, но полезных советов (изоляция AR и бизнес логики)

Soft Skills: The software developer’s life manual
Список софт скилов, которые могут помочь разработчику (и не только) улучшить качество жизни. Из списка, хотелось бы обратить внимание на “Marketing yourself”. По моему, это один из навыков, которому в россии, к сожалению, нигде не учат (если не прав - напишите пожалуйста). На эту тему есть статья из лайвхакера), читать на свой страх и риск.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-11-02 04:09:00
                    [Views1] => 689
                    [Views2] => 758
                    [Views3] => 810
                    [Views7] => 1400
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4718929] => stdClass Object
                (
                    [ID] => 4718929
                    [TgID] => 95
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-10-01 15:50:05
                    [Text] => Перед конференцией, хотелось бы добавить организационных моментов.

Мероприятия

4.10 - др Maciej Mensfeld (http://amp.gs/h7ia)), идем отмечать и пить пиво в RULE taproom в 20:00
5.10 - препати конференции, RULE taproom 20:00
6.10 - конференции и афтепати
7.10 - воркшопы (если найдутся силы - можем устроить афтепати для афтепати)

Нетворкинг
Хотелось бы организовать нетворкинг, чтобы людям проще было общаться на конференции. Если у вас есть идеи как это лучше сделать - пишите в личку @davydovanton

Доклады которые понравились
В этом году слушал прогоны некоторых докладов. Из того, что понравилось и что рекомендую к посещению

1. Эволюция rails архитектуры. Просто маст хев. Доклад не технический, но интересно послушать как github, cookpad и basecamp  живут с рельсой. Кроме того, на докладе будет розыгрыш (но это не точно)
2. Фичафлаги. Использую этот подход на работе и читал фаулера, но даже с таким багажом узнал много нового. Если испытываете проблемы с доставкой фич в прод - маст хев
3. Mruby, слежу за проектом уже 3 или 4 года. Искренне рад, что такие доклады появляются. Узнаете что это, зачем и где использовать
4. Мониторинг. Мониторинг не самая популярная тема в руби сообществе, узнаете на что смотреть в первую очередь, а так же будет анонс новой библиотеке марсиан

Что еще
Мой доклад будет сильно пересекаться с темами из Designing Data-Intensive Applications (DDIA). Поэтому хочу разыграть эту книгу. Подробности на докладе.

Стикеры&#33 С радостью возьму и раздам.

До встречи&#33
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-10-29 17:49:34
                    [Views1] => 484
                    [Views2] => 515
                    [Views3] => 536
                    [Views7] => 924
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4674033] => stdClass Object
                (
                    [ID] => 4674033
                    [TgID] => 92
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-28 14:24:14
                    [Text] => https://prnt.sc/kzrn0a
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 900
                    [ViewsLastDateUpdated] => 2018-10-21 05:51:47
                    [Views1] => 467
                    [Views2] => 502
                    [Views3] => 520
                    [Views7] => 687
                    [Views30] => 900
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4674034] => stdClass Object
                (
                    [ID] => 4674034
                    [TgID] => 93
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-28 14:24:14
                    [Text] => Всё куплено&#3311
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 911
                    [ViewsLastDateUpdated] => 2018-10-21 05:51:47
                    [Views1] => 463
                    [Views2] => 497
                    [Views3] => 515
                    [Views7] => 690
                    [Views30] => 911
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4674032] => stdClass Object
                (
                    [ID] => 4674032
                    [TgID] => 91
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-28 14:10:57
                    [Text] => Как и обещали, вместе с @wi11son разыграли 2 билета на конференцию. Наши победители: @hana1995 и @asmorozov. Организаторы напишут вам по поводу билетов.

Спасибо что поучаствовали и поделились тем, чего не хватает на конференции. Некоторые вещи уже добавлены (например воркшопы), а некоторые будут в следующем году&#33 

Полное видео с записью того, как и что делали тут:
https://youtu.be/FI7Fa55VrjQ
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2018-10-21 05:51:46
                    [Views1] => 607
                    [Views2] => 653
                    [Views3] => 684
                    [Views7] => 816
                    [Views30] => 1000
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4674031] => stdClass Object
                (
                    [ID] => 4674031
                    [TgID] => 90
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-25 16:38:02
                    [Text] => Hапомню, что в эту пятницу мы разыгрываем два билета  на предстоящую конференцию. Если не успели записаться - самое время&#33

Пока учавствуют 100 человек, а это значит, что шансы получить билет высоки

http://amp.gs/hthb
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-10-21 05:51:46
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 890
                    [Views7] => 989
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4629042] => stdClass Object
                (
                    [ID] => 4629042
                    [TgID] => 89
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-24 15:30:06
                    [Text] => У меня больше 30 репозиториев в гитхабе, за которыми надо следить и оперативно закрывать ишю (или отвечать на них). Так как эти репозитории в разных организациях, то постоянно бегать между ними - гиблое дело. Могли бы спасти нотификации, но к сожалению с ними не увидить картину целиком.

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

Сам проект

Доска с моими прокетами и ишю, которые хотелось бы закрыть (можно с этим помочь)

Гитхаб - davydovanton/cookie&#092_box. В гитхабе примеры того как hanami дружит с dry-system и как работают do-notation на практике. А так же пример представления поддерживаемой архитектуры и пример использования веб хуков гитхаба.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1400
                    [ViewsLastDateUpdated] => 2018-10-17 03:09:38
                    [Views1] => 483
                    [Views2] => 921
                    [Views3] => 970
                    [Views7] => 1200
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4629041] => stdClass Object
                (
                    [ID] => 4629041
                    [TgID] => 88
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-21 15:40:07
                    [Text] => Пятничное чтиво


A guide to logging in Java
Полноценный гайд о том, как использовать логгер в приложении. В качестве примера используется java и разные виды логгеров. Меняем  java на Any Lang - получаем маст хев чтиво.

Operations For Developers
Я плохо разбираюсь в том, как администрировать и деплоить приложения. Если испытываете похожие проблемы - Operations For Developers расскажет о том, что такое контейнеры, как мониторить приложения, логгировать, обеспечить безопасность и другие полезные вещи.

Learning SQL Resources
Список ссылок для того, что бы изучить SQL, а так же PostgreSQL и MySQL. Добавлю, что PostgreSQL Exercises сильно помог разобраться в сложных запросах и на него стоит потратить время.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1600
                    [ViewsLastDateUpdated] => 2018-10-17 03:09:52
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 1100
                    [Views7] => 1300
                    [Views30] => 1600
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4629040] => stdClass Object
                (
                    [ID] => 4629040
                    [TgID] => 87
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-18 15:34:50
                    [Text] => Благодаря ребятам из Saint P Ruby User Group (https://t.me/saintprug) количество билетов увеличивается в 2 раза (2 вместо одного). Что это значит? шансы на победу увеличиваются в 2 раза&#33
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1600
                    [ViewsLastDateUpdated] => 2018-10-17 03:09:37
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 1300
                    [Views30] => 1600
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4629039] => stdClass Object
                (
                    [ID] => 4629039
                    [TgID] => 86
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-18 15:24:20
                    [Text] => Pepegramming второй год подряд является информационным партнером конференции http://amp.gs/yXWI (ex railsclub). Это значит, что в этом году опять разыгрываем билеты.

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

Хочется, что бы в этом году участников было больше, а условия — одинаковые для каждого. Поэтому в этом году нужно просто заполнить форму и я случайным образом выберу победителя (с пруфами в виде видео).

Условия:

- Заполнить форму
- Рассказать друзьям
- 28 сентября в 18:00, с помощью рандома выберу победителя
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1900
                    [ViewsLastDateUpdated] => 2018-10-17 03:09:38
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 1500
                    [Views30] => 1900
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4536629] => stdClass Object
                (
                    [ID] => 4536629
                    [TgID] => 81
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-14 12:21:57
                    [Text] => Ну а для тех, кто хочет поучиться на чужих ошибках - гитхаб репозиторий со списоком post-mortems разных компаний:

https://github.com/danluu/post-mortems
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1600
                    [ViewsLastDateUpdated] => 2018-10-09 20:04:59
                    [Views1] => 
                    [Views2] => 526
                    [Views3] => 542
                    [Views7] => 1200
                    [Views30] => 1600
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4536628] => stdClass Object
                (
                    [ID] => 4536628
                    [TgID] => 80
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-14 12:13:12
                    [Text] => Пятничное чтиво.

В далеком 2015 году, грезил дочитать SICP до конца, но к сожалению, с 3 раза дочитал только до главы об environments, frames и bindings. (3.2, если правильно помню). Для того что бы хоть как-то понять что это и зачем - решил написать интерпретатор scheme. В интернете нашел аналог на питоне и сделал подобное на руби.

В итоге получилось страшное, но рабочее решение, которое помогло лучше понять главу и работу языков программирования.

Если вы застряли там же - надеюсь пост с примером реализации интерпретатора scheme сможет помочь понять тему лучше.

Write simple scheme interpreter on ruby
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-10-09 20:04:41
                    [Views1] => 
                    [Views2] => 456
                    [Views3] => 467
                    [Views7] => 897
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4536627] => stdClass Object
                (
                    [ID] => 4536627
                    [TgID] => 79
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-13 11:21:56
                    [Text] => Люблю открытые компании. Чем больше опыта получишь не работая в компании - тем лучше. Политика открытости (даже если говорить только о техническую часть) помогает инженерам получить бесплатный опыт, а это сразу вес в комьюнити и хорошее отношение к компании со стороны. В этом плане gitlab персональный фаворит, так как плейбук натолкнул на кучу идей, а код  платформы позволил найти решения  собственных проблем.

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

Стабильность Dodo IS

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

О том, как устроено IT в Додо Пицца

Понравилась диаграмма сервисов с описанием основного стека и напоминание, что компания - продуктовая и продукт можно и нужно потрогать:

&gt Надоело писать код – можешь сходить в пиццерию, покрутить додстеры или постоять на кассе.

Ну а если интересно посмотреть на процессы работы в ресторанном бизнесе (заказ пиццы) стоит почитать серию статей о работе информационной системы в додо:

Dodo IS. Часть III. Всё о заказе - Сила ума
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2018-10-09 20:04:42
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 761
                    [Views7] => 932
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [4536626] => stdClass Object
                (
                    [ID] => 4536626
                    [TgID] => 78
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-09-10 11:02:49
                    [Text] => В одной статье обратил внимание на упоминание the knowledge loop . Если кратко, то петля состоит из 3 элементов:

изучить -&gt создать -&gt поделиться

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

Пишу это к тому, что я не пропал, просто учусь новому и делаю рабочие и личные проекты. Качество понижать не хотелось, но теперь попробую иначе.

Из текущей работы:

* Data intensive applications и все что касается данных в продуктах. Год назад пришло осознание, что код это не важно, а бизнес логика - важно. Теперь пришел к тому, что данные и работа с данными &gt бизнес логика. Из-за этого, интересно как работать с данными, а так же  как хранить и как обеспечить оптимальную эволюцию в проекте
* По работе отковыриваю сервис из монолита. Это первый шаг к сервисной архитектуре, в котором хочется получить как можно больше шишек. В планах написать статьи в блог как документацию к проекту
* Из-за полного контроля отковыривая сервиса нашел у себя много пробелов не технических умениях. Из-за этого приходится читать много книг связанных с soft skills, бизнесом и головой
* В качестве опыта, решил попробовать написать реальный продукт. Хочу начать глубже понимать тех, на кого работаю. Планирую закончить mvp и сделать приватную бету на https://rubyrussia.club. Об этом тоже напишу, но позже
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2018-10-09 20:04:40
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 807
                    [Views30] => 1000
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3800026] => stdClass Object
                (
                    [ID] => 3800026
                    [TgID] => 77
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-06-08 19:23:24
                    [Text] => В последние время очень много путешествий (26 часов из японии в москву чего стоят), поэтому пишу мало. Зато, если вы 10 числа будете в питере на конференции (https://www.meetup.com/saintprug/events/249120635/) - говорите привет. К тому же у меня есть ограниченное количество крутых наклеек :)
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 754
                    [ViewsLastDateUpdated] => 2018-07-23 13:18:49
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 525
                    [Views30] => 673
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3609736] => stdClass Object
                (
                    [ID] => 3609736
                    [TgID] => 76
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-05-21 12:06:21
                    [Text] => Написал о еще одном способе создания callable objects - Do notations из dry-monads. А так же, почему dry-transactions не вытягивают.

Medium
Telegraph
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-07-04 18:50:30
                    [Views1] => 434
                    [Views2] => 442
                    [Views3] => 474
                    [Views7] => 516
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3557737] => stdClass Object
                (
                    [ID] => 3557737
                    [TgID] => 75
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-05-11 11:36:44
                    [Text] => Хорошие статьи - редкость, а хорошие статьи по тестированию - двойная редкость.

13 антипаттернов тестирования. Сложно выделить один антипаттерн, который понравился. Поэтому советую прочитать о каждом отдельно.

http://blog.codepipes.com/testing/software-testing-antipatterns.html

Русский перевод: https://habr.com/post/358178/
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1500
                    [ViewsLastDateUpdated] => 2018-06-05 00:36:54
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 610
                    [Views30] => 1500
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3557736] => stdClass Object
                (
                    [ID] => 3557736
                    [TgID] => 74
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-05-08 13:19:04
                    [Text] => Тут ребята из @saintprug выложили запись hanami воркшопа. Пара причин почему стоит посмотреть (советую на 1.25-1.5):
- посмотреть на то, как работает фулстек ханами
- реальные примермы DI и почему это работает
- в конце второй части были вопросы на большое количество тем (эвенты, dry, архитектура)
- можно написать на почту и получить ссылки 😉

Код на то, что вышло в итоге: https://github.com/saintprug/spb_link_shortener

А по вопросам - пишите в личку или в @saintprug

Первая часть: https://youtu.be/KnSPR-F2nag
Вторая часть: https://youtu.be/DCMTyddUvio
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-06-21 22:31:18
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 1100
                    [Views30] => 1600
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3557735] => stdClass Object
                (
                    [ID] => 3557735
                    [TgID] => 73
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-05-07 13:38:54
                    [Text] => йо&#33 
По поводу последнего поста и планирования задач. У меня тоже адовый перегруз по задачам, поэтому я решил делать как делает Шон Бланк: 3 задачи которые сдеалют мой день успешным, 3 задачи которые сделают неделю успелшной + записываю мотивацию почему мне надо сделать именно эти задачи и что они принесут. 3 неделя пошла, в привычку ещё не вошло, но уже результаты есть небольше: проще стало немношк

http://macshifford.me/all-the-things-pro/ - тут чёта тоже написывал про это
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-06-18 14:23:12
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3557734] => stdClass Object
                (
                    [ID] => 3557734
                    [TgID] => 72
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-05-07 12:21:46
                    [Text] => Новая неделя (месяц) - новый текст, сегодня о не техническом но важном.

А что вы обычно делайте когда не прет?

Медиум
Телеграф
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 789
                    [ViewsLastDateUpdated] => 2018-06-18 14:23:12
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 738
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3193515] => stdClass Object
                (
                    [ID] => 3193515
                    [TgID] => 71
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-04-12 15:05:02
                    [Text] => Решил собрать немного статистики, поэтому, если вам не сложно - пройдите пожалуйста опрос, 11 вопросов, которые помогут лучше понять на что обращать внимание в следующем проекте 🙂

https://goo.gl/forms/weQbVYOJGKpMmqG73
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-05-23 22:28:21
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 534
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3193514] => stdClass Object
                (
                    [ID] => 3193514
                    [TgID] => 70
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-04-12 12:05:55
                    [Text] => Стоит ли использовать еще одну платформу для текстов, кроме медиума?

Да, телеграф – 90
👍👍👍👍👍👍👍 49%

Нет, медиума хватит – 86
👍👍👍👍👍👍👍 47%

Да, свое (напишу @davydovanton лично) – 5
▫️ 3%

Да, яндекс дзен – 3
▫️ 2%

👥 184 people voted so far.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-05-23 22:33:04
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 578
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3193513] => stdClass Object
                (
                    [ID] => 3193513
                    [TgID] => 69
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-04-10 12:35:55
                    [Text] => На прошлой неделе провел вокшоп в питере, спасибо ребятам из @saintprug за теплый прием. Поэтому сегодня - мысли и советы, как сделать что-то подобное. Хочется верить, что в будущем в россии будет все чаще и чаще встречаться такой формат (организаторы конференций - это ваш шанс 😉).

https://medium.com/pepegramming/workshop-adbe753f2df4
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1200
                    [ViewsLastDateUpdated] => 2018-05-23 22:33:04
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 1100
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [3193512] => stdClass Object
                (
                    [ID] => 3193512
                    [TgID] => 68
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-04-10 12:32:25
                    [Text] => Привет, на улице наконец-то стало тепло, поэтому радостные новости. Я наконец-то переехал на medium. Теперь все посты будут выходить там.
В течении ближайшего времени я перевезу все тексты туда, так что подписывайтесь и рассказывайте друзям:
https://medium.com/pepegramming
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 904
                    [ViewsLastDateUpdated] => 2018-05-23 22:33:05
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 835
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2874123] => stdClass Object
                (
                    [ID] => 2874123
                    [TgID] => 66
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-26 13:07:03
                    [Text] => #quality

Backlog Grooming - понятие из scrum, смысл которого в том, что команда собирается и решает что будет делать дальше и ставит эстимейты задачам. Проводится 1-2 раза в спринт в назначенное время. Но к сожалению, у нас, в какой-то момент возникли проблемы с PR:

- Эстимейты задач ставились на угад и бизнесу было сложно планировать спринты
- Стали появляться большие RP. Сложность ревьювинга возрастала, а качество проекта падало
- Возникали ситуации, когда разработчик написал код, а потом оказалось, что алгоритм не верный и (или) есть решение проще. В результате чего код переписывался, а время шло
- Время выполнения задачи возрастало, а так же (лично у меня) появляется фрустрация и прокрастинация при работе над  большими и сложными задачами

Решение проблем оказалось банальным, появились “technical groomings” (название взято из головы, если вы знаете как этот процесс называется официально - пишите в личку).  Смысл в том, чтобы позволить технической стороне обсудить формальный алгоритм задачи, разбить задачи на атомарные задачи и заэстимейтить каждую из задач.

Формальный алгоритм

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

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

- 1 задача == 1 RP
- Работающий код, потом рефакторинг

Также, планируйте рефакторинг и закрытие технических долгов либо перед началом работы, либо после. Если одна задача из списка блокирует другую - стоит задуматься и попробовать вынести то, что блокирует - в отдельную задачу. Яркий пример такой задачи: добавить эндпоинт для фронтенда. Минимум два варианта, так решить проблему:
- 1 большой PR в котором будет и логика и эндпоинт. Много кода и сложно ревьювить
- 2 PR-а. быстро сделать “пустой” эндпоинт для фронтенда, а потом потратить время на логику. Так разработчик разблокирует коллег, потом сделает остальную работу
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 886
                    [ViewsLastDateUpdated] => 2018-05-05 01:18:09
                    [Views1] => 500
                    [Views2] => 505
                    [Views3] => 505
                    [Views7] => 577
                    [Views30] => 866
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2874124] => stdClass Object
                (
                    [ID] => 2874124
                    [TgID] => 67
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-26 13:07:03
                    [Text] => Плюсы

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

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

Минусы

Главная проблема - трата времени на обсуждение задачи. Этого могут не понять менеджеры, которые считают “нет кода - нет работы”. Старайтесь говорить с менеджерами и объяснять смысл таких обсуждений. 

Такой подход не работает в команде из одного человека. А сам процесс груминга энергоемок, поэтому не ждите, что сможете загрумить все за один день.

И  главное - груминг требует командной дисциплины.

Советы

- Ведите записи. А в конце задачи выделяйте время на обновление документации. Это поможет в поддержке документации к проекту
- Начните с культуры и помощи коллегам. Не везде практикуются подобные обсуждения. Хотите исправить это - подойдите и предложите поговорить о задаче коллеги. После чего попросите помощи сами
- Один груминг - одна тема. Также, желательно ограничивать обсуждения по времени и количеству участников. Не тащите команду, хватит только тех, кто будет работать над задачей
- Делайте груминги по необходимости. Не тратьте время коллег в пустую

Запомнить

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

Ссылки
- MindNode со всеми идеями
- Product Backlog Grooming Best Practices
- Версия для покета
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1300
                    [ViewsLastDateUpdated] => 2018-05-05 01:18:02
                    [Views1] => 475
                    [Views2] => 483
                    [Views3] => 483
                    [Views7] => 579
                    [Views30] => 1200
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2742969] => stdClass Object
                (
                    [ID] => 2742969
                    [TgID] => 65
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-19 12:29:56
                    [Text] => и ссылкой в браузер
https://my.mindnode.com/SfeToxQtx9dv2b2n8scQq6N7HqxWPAhzSTJweLBW
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 939
                    [ViewsLastDateUpdated] => 2018-04-29 19:06:53
                    [Views1] => 315
                    [Views2] => 357
                    [Views3] => 383
                    [Views7] => 474
                    [Views30] => 896
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2742968] => stdClass Object
                (
                    [ID] => 2742968
                    [TgID] => 64
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-19 12:26:47
                    [Text] => и майдмап для лучшего запоминания
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 881
                    [ViewsLastDateUpdated] => 2018-04-29 19:27:45
                    [Views1] => 327
                    [Views2] => 369
                    [Views3] => 396
                    [Views7] => 481
                    [Views30] => 836
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2742967] => stdClass Object
                (
                    [ID] => 2742967
                    [TgID] => 63
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-19 12:23:50
                    [Text] => ссылка для покета:
https://gist.github.com/davydovanton/bb504c423e958470ca639dbc086ad2dc
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 794
                    [ViewsLastDateUpdated] => 2018-04-29 19:27:47
                    [Views1] => 328
                    [Views2] => 367
                    [Views3] => 393
                    [Views7] => 476
                    [Views30] => 751
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2742965] => stdClass Object
                (
                    [ID] => 2742965
                    [TgID] => 60
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-19 12:23:06
                    [Text] => В программировании много абстракций, которые кажутся сложными на первый взгляд, но после практики становятся понятнее. Например - монады.

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

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

Поэтому, цель текста - не объяснить что такое монада, а показать, как и где начать ее использовать . Не ждите функторов, аппликативных функторов, математических выкладок и подробного объяснения зачем каждая монада нужна. Только практика и императивное объяснение. Статьи для любопытных:

* Объяснение функторов и монад в картинках
* Объяснение в HaskellWiki
* A Fistful of Monads - Learn You a Haskell for Great Good&#33


Код

Встречаются места когда приходится работать с данными и состояниями, например валидны данные или нет, вернула бд данные и если да - какие это данные, etc. Например:

response = http.get(url, params)
if response[:status] == :success
  user_repository.create(response[:body])
end


Пример не выглядит сложным, но с бизнес логикой - вложенность выходит из под контроля:

response = http.get(url, params)
if response[:status] == :success
  validation_result = validator.call(response[:body])

  if validation_result.valid?
    if user = user_repository.create(response[:body])
      NotificationWorker.perform_async(user.id)
    end
  else
    validation_result.errors
  end
else
  response
end


Вариант с гардами мне показался сложнее для восприятия

Вспоминая railway programming, было бы здорово переписать наш пример с использованием последовательных шагов:

step :get_response # returns response or Failed result
step :validate # returns payload or error message
step :persist # returns user or nothing
step :notify # calls worker with user id


В случаях, когда данные из прошлого шага влияют на последовательность логики, приходят на помощь монады. Важно запомнить, что монада - объект с общим интерфейсом, в котором лежит значение. Ближайшая абстракция - коробка. В коробке лежит все, что поместиться. При этом, не открыв коробку - значение не получить. Коробки - разные, большие, маленькие, цветные, но каждая коробка открывается одинаково - просто подними крышку и посмотри что там.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 781
                    [ViewsLastDateUpdated] => 2018-04-29 19:27:51
                    [Views1] => 387
                    [Views2] => 419
                    [Views3] => 438
                    [Views7] => 515
                    [Views30] => 746
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2742966] => stdClass Object
                (
                    [ID] => 2742966
                    [TgID] => 61
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-19 12:23:06
                    [Text] => Монада - инструмент, который позволяет создавать цепочки вызовов функций или методов без лишних проверок данных, которые возвращаются в предыдущем шаге. Монад много, но рассмотрим только популярные - Maybe, Result и Try.

* Maybe - оборачивает значение в Some или возвращает None объект без значения. 

* Result - оборачивает значение в Success или Failure.

* Try - оборачивает вызов кода в Result если не было эксепшенов и в Error, если код упал с ошибкой (которая ловится)

У каждой из монад есть 3 главных функции, fmap, bind и способ получить данные, которые содержит в себе монада.

* fmap - выполняет блок, если значение монады соответствует Success варианту, а результат выполнения блока оборачивает в ту же монаду, у которой он вызвался. Например: 

Some(1).fmap(&amp:to_s) # =&gt Some(1)
None().fmap(&amp:to_s) # =&gt Nothing


* bind - аналогичен fmap, только возвращается результат выполнения блока:

Some(1).bind(&amp:to_s) # =&gt 1
Some(1).bind { |value| Success(value) } # =&gt Success(1)
None().bind(&amp:to_s) # =&gt Nothing


В руби нет монад из коробки, но существуют гемы, которые реализуют монады:

* dry-monads
* kleisli
* tomstuart/monads

Советую dry, как единственную поддерживаемую. К тому же, при использовании dry-validation можно легко конвертировать результат валидации в монаду, воспользовавшись экстеншеном:

Dry::Validation.load_extensions(:monads)


Это минимум, который нужен, чтобы начать использовать монады в руби приложении. Для закрепления - перепишем изначальный пример с использованием монад:

http.get(url, params) # теперь клиент возвращается Result Monad
  # валидация возвращает Result, который используется для следующих вызовов
  .bind { |body| validator.call(body).to_result }
  # сохраняем в базу, если валидация вернула Success
  .bind { |payload| Maybe(user_repository.create(payload)) }
  # вызываем воркер, если сохранение вернет Some
  .fmap { |user| NotificationWorker.perform_async(user.id) }


Кроме использования монад в бизнес логике, попробуйте эту абстракцию для обработки результата, который возвращается из бизнес логики. Как пример - вызов operation из экшена и последующая обработка результата в этом же экшене: cookie_box/show.rb

Что делать с результатом

При использовании dry-monads можно:
- вызывать на прямую success?, failed? или value_or
- использовать "dry-matcher"
- мой любимый вариант, использовать "case"

Минусы

1. В отличии от условий (if, unless, etc) нельзя просто взять и использовать монаду. Если не знать в чем смысл абстракции и что значат bind и fmap - будет сложно понять код, который написан
2. Использование монад может сильно усложнить код. Спасает опыт, а опыт получается в практике
3.  Если хотите начать использовать монады в проекте, придется прорваться через ужас в глазах коллег (причина почему я написал этот текст)

Запомнить

* Монады - абстракция для чейна вызовов функций и следованию railway programming
* Для использования монад не нужно математическое образование. Главное понять, что монада оборачивает данные в объекты с единым интерфейсом
* Советую начать с  - Maybe, Result и Try
* fmap и bind - методы для чейна вызовов функций
* Чрезмерное использование монад усложняет код, будьте осторожны и подходите к написанию кода с умом

Полезное

* Как рефакторить руби код с монадами
* Algebraic Data Types &amp Monads in Ruby
* Monads and Ruby
* Railway Oriented Programming
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 877
                    [ViewsLastDateUpdated] => 2018-04-29 19:27:47
                    [Views1] => 379
                    [Views2] => 426
                    [Views3] => 452
                    [Views7] => 553
                    [Views30] => 831
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2742964] => stdClass Object
                (
                    [ID] => 2742964
                    [TgID] => 59
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-18 16:09:40
                    [Text] => @shiroginne поделился подробной воскресной статьей о вещах, которые стоит помнить во время ревью:
https://medium.com/@palantir/code-review-best-practices-19e02780015f

А @alexsubbotin поделился CONTRIBUTING.md файлом, дополненым после текста выше:
https://gist.github.com/KELiON/45cae7ac0eeeaa2a097116396c94b610
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 968
                    [ViewsLastDateUpdated] => 2018-04-24 13:13:07
                    [Views1] => 521
                    [Views2] => 565
                    [Views3] => 594
                    [Views7] => 642
                    [Views30] => 943
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2676509] => stdClass Object
                (
                    [ID] => 2676509
                    [TgID] => 58
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-12 13:23:33
                    [Text] => А каких правил вы придерживаетесь в ревью и на что смотрите в первую очередь? (обратная связь тут - @davydovanton)
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2018-04-23 20:56:47
                    [Views1] => 
                    [Views2] => 454
                    [Views3] => 457
                    [Views7] => 823
                    [Views30] => 1000
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2676508] => stdClass Object
                (
                    [ID] => 2676508
                    [TgID] => 57
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-12 12:43:05
                    [Text] => А так же, версия для покета: https://medium.com/@anton_davydov/pepegramming-ревью-кода-e82794a8f05e
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1100
                    [ViewsLastDateUpdated] => 2018-04-23 20:56:47
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 477
                    [Views7] => 784
                    [Views30] => 994
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2676507] => stdClass Object
                (
                    [ID] => 2676507
                    [TgID] => 56
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-12 12:18:05
                    [Text] => Персональные выводы

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

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

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

Сложность ревью пропорциональна количеству кода. Чтобы справляться с этим, разбивайте работу на &quotатомарные&quot пулл реквесты, которые не превышают N строк (например - 200 для кода без тестов). Например, в опен сорс проектах, я стал просить людей разбивать работу над задачей на отдельные пулл реквесты

Для последнего шага ревью необходима внимательность, но с этим возникают проблемы у отдельных людей (ADHD напрмиер). При этом, базовые проверки, таких как стиль, грамматика и опечатки автоматизируются с помощью код стайла с rubocop, danger и codeclimate, который показывает, какие части пулл реквеста не покрыты тестами.

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

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

# Запомнить

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

# Полезное

- 11 советов, как улучшить ревью от IBM
- Еще советы, на этот раз от asana
- И еще советы
- Посмотрите, как Лука пишет описания к ПР-ам в ханами, у него есть чему научиться
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2018-04-23 20:56:48
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 554
                    [Views7] => 751
                    [Views30] => 955
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [2676506] => stdClass Object
                (
                    [ID] => 2676506
                    [TgID] => 55
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2018-03-12 12:18:04
                    [Text] => #quality

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

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

Понимание задачи

Начните с главного, понимания задачи, которую пытается решить разработчик. Важно: поймите бизнес требование, а не текущую реализацию. Проверьте, разбиваются изменения на 2 и больше пулл реквеста или нет. Если сложно - попросите коллегу о помощи или подробном описании того, зачем изменения нужны. На этом этапе определяется насколько сложную и значимую задачу решал разработчик, а ревьюверы погружается в контекст проблемы. Правило, которого стараюсь придерживаться: 1 пулл реквест == 1 атомарная задача, которую просто понять и просто объяснить на каждом из уровней абстракции.

Проверка, что задача выполнена

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

Проверка архитектуры и способа решения

Когда появилась уверенность, что бизнес задача решена, стоит опуститься на абстракцию ниже и посмотреть, как реализован код. Места куда стоит смотреть: изоляция функций между собой, где лежит логика, мешается логика между собой или нет. Также стоит проверить наличие юнит тестов для каждого класса и метода. Здорово, если юнит тесты покрывают граничные случаи и неправильное использование кода (не тот тип данных, как пример)

Проверка кода и грамматики

Последний шаг - скрупулезная проверка кода. Тут проверяется нейминг, стилистические особенности, проверяется перформанс. 

Подитожив, можно увидеть такую последовательность:


Понимание задачи -&gt проверка, что задача выполнена -&gt проверка архитектуры и способа решения -&gt проверка кода и грамматики
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1000
                    [ViewsLastDateUpdated] => 2018-04-23 20:56:48
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 586
                    [Views7] => 665
                    [Views30] => 958
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267670] => stdClass Object
                (
                    [ID] => 1267670
                    [TgID] => 54
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-09-19 12:30:05
                    [Text] => Конкурс завершен&#33 
В течение недели вы писали свои истории о проблемах, с которыми приходится сталкиваться в работе https://github.com/moscowrb/organisation/issues/3. Спасибо всем, кто поделился наболевшим и рассказал о своей проблеме.
Наибольшее количество лайков собрал рассказ Nikolay Shebanov (https://github.com/killthekitten). Николай получает бесплатный билет на RailsClub 2017. Поздравляем&#33
На 2 и 3 месте соответственно оказались Кирилл (https://github.com/mephody-bro) и domenic99 (https://github.com/domenic99). Пожалуйста, напишите мне в личку @davydovanton, чтобы забрать свой сувенир из Японии.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 2400
                    [ViewsLastDateUpdated] => 2018-12-25 21:04:40
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267669] => stdClass Object
                (
                    [ID] => 1267669
                    [TgID] => 53
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-09-11 13:51:44
                    [Text] => Ребята из RailsClub из года в год делают самую крупную Ruby-конференцию в России с иностранными спикерами. В этом году ожидаются выступления авторов dry, rom, Hanami и Trailblaizer, а также крутых разработчиков со всей страны.

Мне предложили разыграть один бесплатный билет на конференцию. Чтобы розыгрыш был справедливым, надо будет выполнить небольшое задание.

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

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

Награда
Человек с наибольшим количеством 👍 получит бесплатный входной билет на конференцию RailsClub 2017, которая состоится 23 сентября в Москве.
Обладателям второго и третьего мест я привезу сувениры из Японии.

Условия
Конкурс завершается 18 сентября. Каждый участник может отправить неограниченное количество историй. Флуд и спам будут удаляться.

Полезное
- Напишите вашу историю как можно быстрее — так у вас будет больше шансов собрать максимальное количество голосов
- Почитайте пост о том, почему конференции — это круто и что вы можете получить от них помимо докладов
- И еще один старый пост — про то, что делать до, во время и после конференциии
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 2600
                    [ViewsLastDateUpdated] => 2018-12-25 21:04:38
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267668] => stdClass Object
                (
                    [ID] => 1267668
                    [TgID] => 52
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-28 20:02:11
                    [Text] => Благодаря трекингу времени, проведенного за компьютером, обнаружил, что в последний месяц, трачу половину дня на соцсети и месенджеры. Из-за этого я захотел провести экспиремент и не пользоваться меcсенджерами (кроме рабочего слака) и социальными сетями на 7 дней.

Поэтому, к сожалению, в канале будет перерыв на эту неделю. А пока можно вспомнить старые сообщения или задать вопросы. А также прочитать пост Андрея Ситника о цифровом шаббате.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1800
                    [ViewsLastDateUpdated] => 2018-12-25 21:04:37
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267667] => stdClass Object
                (
                    [ID] => 1267667
                    [TgID] => 50
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-25 18:25:57
                    [Text] => #закладки №1

Статьи

* www.blackbytes.info/2017/08/how-does-sinatra-work
Статья о том, как работает Sinatra и что происходит, когда в коде появляется require sinatra. Если хотите прокачаться, в процессе чтения попробуйте написать свою собственную реализацию этого фреймворка с таким же синтаксисом.

* jakeyesbeck.com/2016/03/13/the-power-of-arel
Arel — библиотека, которая вызывает либо отвращение, либо отвращение. Я не знаю ни одного человека, которому бы нравился код, написанный на ней. Так как Arel — low level библиотека для работы Active Record, в коде иногда приходится использовать этот гем. Обычно найти нормальную документацию на эту библиотеку сложно, но статья по ссылке хороша тем, что содержит примеры селектов, джойнов и сложных выборок.

* nicksda.apotomo.de/2011/07/are-class-methods-evil/
* andrzejonsoftware.blogspot.ru/2011/07/yes-nick-class-methods-are-evil.html
Я не фанат методов класса. В коде стараюсь использовать такие методы только по необходимости, либо для создания фабрик и других инициализаторов. В этих двух статьях на примерах рассказано о том, почему не стоит использовать методы классов. Советую также почитать комментарии — там много интересной информации.

* robots.thoughtbot.com/rebuilding-git-in-ruby
Лонгрид о том, как написать git на чистом Ruby. Постарайтесь не просто прочитать статью, но и написать код самостоятельно, без копипаста. Потом запустите программу и проверьте, что всё работает корректно.

* stillflowing.net/2014/12/21/an-experience-in-contributing-to-open-source
Автор рассказывает, почему не надо заниматься опенсорсом ради опенсорса. Ключевая идея: лучше просто пишите код, и во время этого процесса вы найдете проблему, которую можно решить с помощью Open Source.


Репозитории

* reqres-api/reqres_rspec
Интересное решение для того, чтобы генерировать документацию из тестов. Я не использовал эту библиотеку, но планирую испытать ее в деле с Hanami и dry-web приложениями. К сожалению, у библиотеки нет тестов и непонятно, будет ли гем работать с нерельсовыми проектами. Поэтому, если у вас есть время и желание помочь, велкам.

* donnemartin/system-design-primer
Материал о том, как работают разные части веб-приложений. Это популярный текст, который не раз попадал в рассылки или подкасты. У репозитория с этим текстом — 16 тысяч звезд, хотя в нём лежит довольно разрозненная информация. Есть ссылка на русский перевод, который можно дополнить, если есть желание. Вот вам готовая идея для PR: просто дополните гайд и помогите другим разработчикам.

* muan/dashboard
Расширение для Chrome, которое фильтрует информацию на главной странице Github. Скажу честно, мне не нравится Github feed и я раздумывал написать приложение, которое исправило бы эту ситуацию. Но плагин решает проблему: отфильтрованный фид выглядит намного информативнее.


Опенсорс

* slim-template/language-slim/issues/25
Автор Slim ищет помощников. Хотите помочь 10 миллионам человек (на самом деле это количество скачиваний гема)? Есть свободные пара часов в неделю? Напишите автору и предложите помощь. А если сомневаетесь — я уже писал, почему Open Source — это круто (https://t.me/pepegramming/43).

* hanami/events/issues
Если знаете, почему важен event sourcing, хотите прокачаться в асинхронщине и работе с Kafka, Postgres, Redis и другими крутыми штуками — велкам. По ссылке — много открытых ишью, которые ждут своих героев.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1900
                    [ViewsLastDateUpdated] => 2018-12-25 21:48:36
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267666] => stdClass Object
                (
                    [ID] => 1267666
                    [TgID] => 49
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-24 18:30:22
                    [Text] => Недавно нашел статью (https://m.habrahabr.ru/post/158011/, оригинал: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/) про паттерны для моделей в Rails от 2012 года.  Подскажи, насколько эти паттерны актуальны и часто ли их приходится применять на практике. Заранее спасибо&#33

Я считаю, что эти паттерны актуальны даже сейчас. Если присмотреться, они об одном и том же: разделяй логику на изолированные объекты и радуйся жизни. Конечно, можно не следовать паттернам, но необходимо задавать самому себе вопрос: «А действительно ли код, который я написал, должен быть в этом месте, или нет?».

Получается, рельсовые параметры нам всё равно нужно постоянно пермитить? (вопрос по последнему примеру)

Мне не приходилось таким заниматься, но думаю, ответ легко найти в интернете. Например, на SO описывается один из вариантов, как отключить параметры:
https://stackoverflow.com/questions/18092475/in-rails-4-disable-strong-parameters-by-default

Думал, что "Dry::Validation.Schema" на выходе будет выкидывать все параметры, которые не описаны в схеме, это возможно? Просто получается, что если в запросе будет куча лишнего хлама, и описанные параметры проходят валидацию, то лишние параметры тоже остаются, и приходится их самому подчищать, иначе при попытке сохранить запись будет эксепшен, что переданы дополнительные параметры, о которых модель не в курсе, и запись не сохранится.

Я допустил ошибку в примере. Используйте form-валидацию. Эта валидация обрезает неуказанные параметры, что решает проблему.


schema = Dry::Validation.Form do
  required(:email).filled(:str?)
  required(:age).maybe(:int?, gt?: 18)
end

schema.call(email =&gt jane@doe.org, age =&gt )
# =&gt #&ltDry::Validation::Result output={:email=&gt&quotjane@doe.org&quot, :age=&gtnil} errors={}&gt

schema.call(email =&gt jane@doe.org, age =&gt , firstname =&gt anton)
# =&gt #&ltDry::Validation::Result output={:email=&gt&quotjane@doe.org&quot, :age=&gtnil} errors={}&gt
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1500
                    [ViewsLastDateUpdated] => 2018-12-25 21:48:32
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267664] => stdClass Object
                (
                    [ID] => 1267664
                    [TgID] => 47
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-21 20:22:59
                    [Text] => Я люблю экшены в Hanami и сегодня расскажу, почему.

После рельсы и синатры разработчики привыкли, что экшены являются методом класса или чем-то похожим. Главное, что они — в одном классе.

У такого подхода есть плюсы:
- каждый экшен в одном месте, не надо «прыгать» между файлами
- легко представить экшен как один класс и инкапсулировать его в голове.

Но существуют и минусы:
- если экшены большие, то куча кода в одном месте превращается в хаос
- появится код, который будет общим для 1+ экшена (например, callback), что увеличивает связанность экшенов между собой
- такие экшены сложно тестировать. Нельзя просто взять и явно вызвать метод, для этого нужны интеграционные тесты
- permit params из Rails шарится на каждый экшен в классе. Это доставляет трудности, если нужно предоставлять разные параметры.

Тут в игру врывается Hanami, который переворачивает такой подход с ног на голову. Этот фреймворк утверждает обратное: каждый экшен — изолированный класс с единственным публичным методом #call. Но если задуматься, то получается, что мы работаем не с контроллером, а с отдельным экшеном. Поэтому логично изолировать не контроллеры между собой, а экшены.

Выглядит это следующим образом:

<br/>module Web::Controllers::Home<br/>  class Index<br/>    include Web::Action<br/><br/>    def call(params)<br/>      # your action code here<br/>    end<br/>  end<br/>end<br/>

Если у нас есть изолированный экшен, то тестировать его становится проще. Потому что мы можем вызвать его явно и передать нужные параметры:

<br/>Web::Controllers::Home::Index.new.call({ ... })<br/>

Этот подход добавляет гибкости при тестировании. Теперь можно писать не только интеграционные, но и юнит-тесты. А если у экшена есть сложная для тестирования зависимость в коде, то Hanami позволяет использовать DI вместо моков:

<br/>module Web::Controllers::Home<br/>  class Index<br/>    include Web::Action<br/><br/>    def initialize(repo: UserRepository.new)<br/>      @repo = repo<br/>    end<br/><br/>    def call(params)<br/>      # your action code here<br/>    end<br/>  end<br/>end<br/><br/>action = Web::Controllers::Home::Index.new(repo: EmptyRepository.new)<br/>

Кроме того, экшен предоставляет валидацию для работы с параметрами. Валидация основана на dry-validation, что позволяет вынести логику из модели. В результате модель получается «тоньше». Условные валидации пропадают как костыль, потому что валидируются только указанные в каждом экшене параметры.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1400
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:50
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267665] => stdClass Object
                (
                    [ID] => 1267665
                    [TgID] => 48
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-21 20:22:59
                    [Text] => Но и как у любой технологии, у экшенов Hanami есть минусы.

Код экшена под капотом — магия
Сделать действительно удобный для использования другими людьми код — непростая задача. Поэтому приходится сидеть на двух стульях. На эту тему можно найти отличный пост (советую также прочитать комментарии, там много ценной информации). От себя скажу, что эта магия не мешает во время разработки, но порой задаешься вопросом, почему иногда явный вызов возвращает неявные вещи.

Много файлов
Это палка о двух концах. Пока в системе маленькие экшены на 1-3 строчки кода, легче смотреть весь контроллер целиком — и тут будет удобен подход из Rails. Но когда экшены растут и сложность увеличивается, помогут идеи, заложенные в Hanami. Изолированный экшен позволяет разработчику сфокусироваться только над ним одним, а не над контроллером в целом. Поэтому если у вас будет приложение с простым CRUD без излишеств, рассчитывайте, что разом на весь контроллер вы вряд ли посмотрите.

Чем это полезно разработчикам, которые не будут использовать Hanami

Как я неоднократно говорил, Hanami интересен идеями, которые лежат в его основе. Например, фреймворк помогает задуматься, правильно ли валидировать данные в модели и создавать огромные контроллер-классы.

Запомнить
- В мире Ruby существует устоявшееся «правило», как должны выглядеть контроллеры.
- Hanami предлагает концептуально новый подход к написанию экшенов.
- Этот подход не является «серебряной пулей». Он решает только определенные проблемы.
- Если вы не планируете использовать Hanami, можете просто вдохновиться идеями из этого фреймворка.

Ссылки
- Документация на экшены в hanami
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1400
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:51
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267663] => stdClass Object
                (
                    [ID] => 1267663
                    [TgID] => 46
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-21 12:30:20
                    [Text] => Доброго времени, читаю канал, но интересно, почему не используется телеграф(telegraph.ph) для хранения статей? Интересно узнать ваше мнение

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

Оргвопросы

Обновил форму вопросов. Теперь можно задать вопрос или поделиться проблемой, и мы разберем её в канале. Пожалуйста, не воспринимайте это как SO или место, где можно получить ответ на любой вопрос. Придерживайтесь тематики.

Также появилась идея раз в неделю делиться ссылками на интересные посты. Что думаете?
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1400
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:48
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267662] => stdClass Object
                (
                    [ID] => 1267662
                    [TgID] => 45
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-15 00:19:34
                    [Text] => Я уже писал о dry-transaction. На работе мы начали использовать эту библиотеку в оперейшенах. Это такие сервис объекты, которые вызываются из транспорта (http, stream) и выполняют код завязанный на бизнес логику. Это может быть как просто манипуляция с бд (достать данные, сохранить данные), так и действительно сложная логика. Например процессинг платежа. Текущее решение содержит в себе  много магии и поэтому было решено начать использовать dry-transactions как основной каркас для построения оперейшенов.

Поэтому сегодня две ссылки.

Пример использования такого оперейшена в rails экшене:
https://gist.github.com/davydovanton/ec99546c3eb512599b65e5b27fe78bb0

Старая ссылка с примером в ханами:
https://gist.github.com/davydovanton/0a9e9dcaef75582e3c2fe9b4392b61d9
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1600
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:47
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267661] => stdClass Object
                (
                    [ID] => 1267661
                    [TgID] => 44
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-10 17:54:34
                    [Text] => Как найти задачи
Я знаю четыре способа, которые могут помочь:

1. Использовать технологию, в которую хотите начать писать. Самый простой вариант.
Вы пишете проект на hanami, dry-web, rails или используете любую другую технологию. Видите проблемы, на решение которых нужно потратить время, и исправляете их, обновляете документацию или пишете новую библиотеку. Как пример: работая с rom, мне было сложно понять ассоциации между таблицами, поэтому я написал простой инструмент, который генерирует картинку с этой информацией.

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

3. Воспользоваться агрегаторами тасков. В интернете можно найти много сервисов со списком осс-задач (1, 2). Я сам написал такой. Проблема в том, что вам как новичку сложно будет понять, что и как нужно сделать. Поэтому я не фанат такого варианта.

4. Найти баг или фичу самому. Самый сложный и далеко не практичный вариант. Открываете код проекта, долго изучаете его и находите, как и что можно исправить. Советую не доходить до такого, ибо способ сильно убивает мотивацию.

Что можно делать, кроме кода

Опенсорс — это не только код. Важны документация, экосистема, ответы на вопросы и многое другое. Если чувствуете, что код писать сложно, но можете обновить документацию — не стесняйтесь. Это невероятно полезно для любого проекта. Рассказать на митапе про проект, который вам понравился — еще один отличный способ помочь. Не зацикливайтесь на коде, не думайте, что обновляя документацию, вы станете посмешищем в глазах других. Много крутых разработчиков начинали с документации, например, ...имена...

Советы

1. Лучше час каждый день, чем 5 часов один раз в неделю. За час можно многое успеть и получить много ❤️  от других людей. Регулярность важнее количества.
2. Не идеализируйте. Опенсорс — это прежде всего помощь другим, а не хардкорные таски. Порой важнее поправить сайт проекта, чем написать невероятно сложную и быструю систему.
3. Не отчаивайтесь. Все мы люди, все мы ошибаемся. У меня был пулл-реквест в Rails с 80 комментариями, который я не смог закончить. Такие ситуации нормальны. Не сдавайтесь, потому что все сообщество готово вам помочь.
4. Отдыхайте и не делайте через силу. Если чувствуете, что не идет — забейте. Хуже от этого никому не будет. Если чувствуете, что не можете доделать задачу — скажите это другим людям. Вам помогут и никто не обидится. Например, не так давно я попросил помощи у Луки (Luca...) с тестами, потому что я не знал, как их поправить, и он мне помог. 

Запомнить

- Опенсорс — такая же работа, с такими же людьми. Не думайте, что она для избранных или исключительно для профи. Это под силу каждому.
- Опенсорс — это не только про код, но и про общение. Не обязательно писать код, чтобы помочь.
- Не заставляйте себя, пользы от этого никому не будет.
- Не нервничайте и не сдавайтесь. Будьте вежливы и дружелюбны, и вам понравится&#33
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1900
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:47
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267660] => stdClass Object
                (
                    [ID] => 1267660
                    [TgID] => 43
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-10 17:54:34
                    [Text] => «Как начать писать в opensource?»
Кажется, такой вопрос задавал себе каждый разработчик, в том числе и я сам. Сегодня мне хотелось бы поделиться опытом и советами для всем, кому интересна эта тема.

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

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

Прокачивайтесь как разработчик
Опенсорс-проектов много. Это значит, что найти задачу по душе не составит труда. Понравился elixir — найдите проект на нем и попробуйте помочь. Хотите прокачаться в асинхронном программировании — откройте гитхаб и найдите интересный репозиторий.

Занимаясь опенсорсом, можно лучше понять, как работают технологии, или узнать новые подходы. Например, можно помочь в работе над ORM — и понимание того, как функционируют базы и как лучше работать с ними, обеспечено. Есть проекты, в которых придерживаются кодстайла и пишут красивый код. Работая над популярными осс-проектами, можно получить фидбэк крутых разработчиков и перенять их опыт.

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

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

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

Я уже говорил, что опенсорс — такая же работа, как и та, за которую платят деньги. На нее нужны силы и время. Поэтому первое, что нужно сделать, чтобы начать писать в опенсорс — ответить самому себе на вопрос, зачем это нужно лично вам. Не стесняйтесь себя и отвечайте честно, потому что причин может быть несколько, и они могут быть даже эгоистичными. Подумайте, действительно ли вы готовы пожертвовать своим временем и силами ради этого, и если да, то ищите задачи.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1500
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:46
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267659] => stdClass Object
                (
                    [ID] => 1267659
                    [TgID] => 41
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-07 14:37:37
                    [Text] => и немного опыта моего коллеги, который будет полезен, если вы захотите использовать контейнеры
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1500
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:45
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267658] => stdClass Object
                (
                    [ID] => 1267658
                    [TgID] => 40
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-07 14:01:08
                    [Text] => Ребята из dry-org подумали о разработчиках и сделали две библиотеки, которые решают эти проблемы: dry-auto_inject и dry-system).

dry-auto_inject нужен для того, чтобы легко и просто инжектить зависимости в объекты:
* Библиотека предоставляет сахар для инжектинга зависимостей из контейнера.
* Заинжекченные зависимости также инжектятся через классический DI.
* Работает с любыми контейнерами. Я проверял с ханами-контейнером и с обычным руби хешем.

dry-system предоставляет простой способ инициализации контейнеров. Достаточно описать, какие файлы и как резолвить в контейнере, и библиотека магически работает. К сожалению, пока библиотека функционирует нестабильно, поэтому используйте на свой страх и риск.

Примеры:

* Все части ханами загружаются в DI контейнер, который уже резолвит что и как загружать.
* Пост из icelab о том, как правильно использовать DI.
* Пример блога на dry-web, можно посмотреть на DI containers в деле 

Tips:
Контейнер хорошо подходит для реализации фабрик. Можно создать класс, который будет загружать в память и возвращать только указанный объект. Именно так работает выбор адаптеров в hanami-events.

Links:
* Пост великолепного Jim Weirich, который поможет разобраться в теме
* Не путайте IoC и DI containers. Это разные вещи
* Статья, которая описывает когда лучше использовать DI containers
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1500
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:44
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267656] => stdClass Object
                (
                    [ID] => 1267656
                    [TgID] => 38
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-07 14:01:08
                    [Text] => Я уже писал об использовании dependency injection в ruby. Но как и у всех подходов, у DI существуют свои минусы. 

Сложно управлять зависимостями
Например, есть папка с сервис-объектами. Для каждого из них нужен логгер. Также логгеры нужны для интеракторов, воркеров, репозиториев и экшенов.
 
Используя DI, придется каждый раз прокидывать один и тот же инстанс логгера в каждый объект. Это утомительно и заставляет писать много кода.

Сложная и дорогостоящая инициализация
Например: для инициализации клиента Amazon приходится писать много кода.

В случае с DI понадобится каждый раз создавать ресурсозатратный инстанс или использовать константу, которая объявленна где-то в коде.

Много кода
Например: сервис, которому нужен твиттер-клиент, логгер, репозиторий и еще пара зависимостей. Создается инициализатор с кучей переменных, а это уже code smell.
<br/>class MyObject<br/>  def initialize(repo:, twitter:, logger:, mailer: ,...)<br/>  end<br/>end<br/>

Конфигурирование зависимостей в одном месте
Конфиги зависимостей хранятся в одном месте, из-за чего такой файл сложно поддерживать.

Перечисленные проблемы заставляют задуматься об использовании DI в проекте. Но есть решение, которое позволяет контролировать зависимости.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1400
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:30
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267657] => stdClass Object
                (
                    [ID] => 1267657
                    [TgID] => 39
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-07 14:01:08
                    [Text] => DI containers

Представьте объект, который знает о зависимостях в приложении (или части приложения). Такой объект знает об инициализации и конфигурации каждой зависимости. Этим занимается DI containers.

Какие проблемы решает DI container:

* Зависимости находятся в одном месте. Не нужно писать пачку файлов в config/initializes/*, а потом пытаться контролировать флоу загрузки зависимостей.
* Каждую зависимость достаточно инициализировать один раз. Если нужна динамическая инициализация — не проблема, библиотеки это поддерживают.
* Не нужно держать конфигурации зависимостей в одно месте. Можно легко выделять конфиги в разные части приложения.

В руби есть библиотеки, которые реализуют подобный функционал:

* dry-containers
* micon
* encase
* dim
* hanami-components

Если ничего не понравилось — велосипед займет меньше 100 строк кода. Но я отдаю предпочтение dry-containers, и вот почему:

* Можно использовать класс или инстанс контейнер.
* Легко пишется кастомный регистратор и резолвер зависимостей контейнера.
* Register options.
* Поддерживаются стабы.

Но у контейнеров можно найти минусы:
* Появляется глобальная переменная, которая ведет себя как синглтон. Это создает глобал стейт, поэтому будьте аккуратны.
* Может возникнуть соблазн создать мега-контейнер с множеством излишних зависимостей. Это принесет много проблем и негативно отразится на производительности.
* Придется писать конструктор в каждом сервисе/объекте, в который будет передаваться DI container.
* Если есть куча сервисов, которые резолвятся в контейнере, придется писать много кода.
* Что делать, если понадобится использовать DI и DI containers сразу в одном коде?

Хочется обратить внимание на последние 3 пункта. Это проблемы, которые не решаются через контейнер. Поэтому придется говнокодить. Например, так:
<br/>class Service<br/>  def initialize(twitter: Container[twitter])<br/>    @twitter = twitter<br/>  end<br/>end<br/>

А для автоматической регистрации сервисов придется писать сложный код с require в интеракторе.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1400
                    [ViewsLastDateUpdated] => 2018-12-25 21:47:44
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267655] => stdClass Object
                (
                    [ID] => 1267655
                    [TgID] => 37
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-04 13:17:13
                    [Text] => Простите, ссылка на использование AR::Validation вне модели вела не на тот пост, вот правильный:
https://blog.ragnarson.com/2016/10/26/validation-outside-activemodel.html
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1600
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:30
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267654] => stdClass Object
                (
                    [ID] => 1267654
                    [TgID] => 36
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-03 20:10:58
                    [Text] => Запомнить
- Rails way не панацея. Старайтесь думать, когда полезно его придерживаться, а когда — нет.
- Валидации и модель — разные вещи. Вынос валидаций в контроллер может сильно облегчить жизнь и процесс тестирования.
- У выноса валидаций есть минусы, выбирайте осознанно.

Интересное
- Валидация разных параметров в пользовательском приложении и в приложеини администрирования на примере hanami
- Пример большой валидации в моделе гитлаба

Почитать
- Hanami — отличный пример, когда вынос валидации из модели работает как надо.
- Такой же подход пропагандирует трейлблейзер.
- Облегчаем жизнь монадами.
- Как использовать AR::Validation вне модели.
- Используем dry-validation в rails приложении.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:30
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267653] => stdClass Object
                (
                    [ID] => 1267653
                    [TgID] => 35
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-08-03 20:10:23
                    [Text] => Сегодня поговорим про валидации. Я не фанат rails way подхода, и вот почему.

На мой взгляд, главные проблемы заключаются в следующем:

1. Модель вмещает в себя много логики. Это мешает в тестах, а также увеличивает связанность между частями системы.
2. В одном файле описывается схема для всех возможных вызовов в коде. Получается гибрид с кучей кондишен-условий (привет if: :paidwithcard?)
3. Если говорить о rails, то заметно дублирование логики. Контроллер проверяет ключи (permit params), а модель проверяет значение ключей при сохранении.

Это ведет к сложностям и затратам усилий на борьбу с фреймворком вместо решения бизнес-задач.

Как с этим жить?

Вариант первый: забить и писать условные валидации в модели. Это будет просто, не наплодит лишних абстракций и соответствует rails way. Но такой вариант приведет к проблемам, о которых я писал выше:
- сложность в тестировании
- сложность в валидировании частей приложения. Например, валидация данных в админке для модели Post и в юзер-контроллере
- логика мешает, а модель растет. Это приводит к 1000-строчным моделям, что увеличивает сложность понимания кода.

Второй вариант: валидации происходят на транспортном уровне приложения. Получая данные от клиента, нужно быть уверенным, что они валидны и ничего не ломают. Только после этого данные сохраняются в базу. Схематически это выглядит так:
<br/>Получить данные → Провалидировать → Сохранить валидные данные в базу<br/>

Путь, который я предлагаю — вынести валидацию в отдельную абстракцию и использовать ее там, где это нужно. Это могут быть контроллеры, сервис-объекты или любые другие варианты.

Плюсы такого подхода:
- Схемы валидаций специфичны только для конкретного случая, поэтому не нужно думать о реализации, которая покроет все случаи.
- Легко тестировать. Тестируется только схема, а с помощью DI она пробрасывается в код. Такой подход позволит проще тестировать объекты, так как не нужно заморачиваться по поводу валидных данных в тестах.
- Модель не реализует логику валидирования, следовательно, уменьшается в размерах. Так проще найти нужную валидацию для определенного случая, не нужно разбираться, в каком случае кондишен валидации сработает, а в каком — нет.

Минусы:
- Неканоничный rails way. Новым разработчиками придется понимать, почему было сделано так, а не иначе.
- Появляется новая абстракция. Не имею ничего против этого, но абстракции текут.

Как это сделать в Ruby?

Я знаю три библиотеки, которые предоставляют валидированию данных:
- dry-validation
- ActiveModel::Validations
- hash_validator gem

Используйте любую, но я отдаю предпочтение dry-validation. Это гибкая библиотека, которая предоставляет удобный DSL для кастомных матчеров и проверяет опциональные поля. У нее также есть гайд о сравнении с AR::Validatoin. Эта библиотека используется в hanami, trailblazer и других гемах. Чтобы начать с ней работать, достаточно прочитать гайды.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1600
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:29
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267652] => stdClass Object
                (
                    [ID] => 1267652
                    [TgID] => 34
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-31 15:35:08
                    [Text] => Я сделал простой проект, который поможет легко и быстро найти застаренный гитхаб-репозиторий. Поиск похож на таковой по полям в гитхабе.

Задача

Вместо множества полей и перегрузки интерфейса было решено сделать единственное поле для поиска. Такой поиск сделал гитхаб. Строка is:open is:issue позволяет получить список открытых issue. Мне захотелось сделать подобное и в своем проекте.

Реализация

Так как проект тестовый, усложнять и делать поиск с эластиком было бы странным. Поэтому я использовал постгресовский ILIKE. Вся логика состоит из трех частей:

1. Поиск в базе по ключам
2. Парсинг строки для созданием ключей поиска
3. Валидация ключей

Поиск по ключам

Поиск по ключам состоит из главного релейшена, который пробрасывается через методы для поиска. Каждый метод принимает query в виде релейшена и значение ключа для поиска и возвращает новый query-объект. В виде кода это выглядит следующим образом:
<br/>def find_by_account(account_id, search = {}, limit = 100)<br/>  query = projects.where(account_id: account_id)<br/>  query = text_search(query, search[:text])<br/>  # ...<br/><br/>  query.order{ starred_at.desc }.limit(limit).as(Project).to_a<br/>end<br/><br/>def text_search(query, text)<br/>  return query if text.nil?<br/><br/>  text = pattern(text)<br/>  query.where { name.ilike(text) | description.ilike(text) }<br/>end<br/>

Парсинг строки

Мне не хотелось заморачиваться с парсерами, поэтому выбор пал на стандартную библиотеку strscan. StringScanner посимвольно проходит по строке. Результатом выполнения метода будет либо совпадение, либо nil. В документации много подробных примеров. Хотелось бы добавить, что создание токенов в виде регулярных выражений и сканирование строки по этим токенам может сильно упростить логику и повысить читаемость кода:
<br/>require strscan<br/>OPTION_TOKEN = /&#092w+:&#092w+/<br/><br/>StringScanner.new(command:test).scan(OPTION_TOKEN)<br/># =&gt &quotcommand:test&quot<br/>StringScanner.new(other text).scan(OPTION_TOKEN)<br/># =&gt nil<br/>

Полный код доступен в репозитории. Парсер возвращает хеш вида { search_key =&gt value }, который валидируется, а потом передается в репозиторий.

Валидация ключей

Следующая проблема: как провалидировать параметры поиска? Хочется закрыть xss-уязвимость, а также для улучшения UX показать, что пользователь ввел неправильные данные. Для этого я написал сервис валидации и проверки параметров. Сервис знает допустимые ключи поиска и удаляет невалидные символы.

Что можно имправить

1. Главный экшен. Стоит вынести валидацию в отдельный сервис, а поиск в интерактор, который будет вызывать валидацию и метод репозитория.
2. Поиск в репозитории. Метод содержит много логики. Вынос логики в отдельный класс  упростит логику и поможет в тестировании.
3. Поиск в postgresql. Я люблю постгрес, в нем отличный поиск. Но возможно, вариант с эластиком будет проще и быстрее.

Запомнить

1. Если нужен простой поиск, а за SaaS платить не хочется — стоит подумать, может, проще написать велосипед.
2. StringScanner — рабочая библиотека, которая поможет сохранить силы и время.
3. Использование больше одного поля для поиска усложняет UX и код.

Ссылки

* Блог пост о том, как парсить текст в руби
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:29
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267651] => stdClass Object
                (
                    [ID] => 1267651
                    [TgID] => 33
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-31 01:21:03
                    [Text] => Спасибо всем за вопросы&#33 Приятно видеть ваш интерес к постам. Надеюсь, что в будущем фидбека будет еще больше :)

&gt Привет&#33 Вижу, ты часто пишешь про Dependency Inversion, и поэтому хотел бы спросить: в чем для тебя принципиальная разница между di и паттерном strategy? Спрашиваю, т.к., на мой взгляд, разница между определениями в Ruby несколько размыта.

Мне нравится ответ SO на такой же вопрос.

Если в двух словах — strategy и DI работают одинаково. Однако различия тоже есть. В случае с DI изменение зависимости во время работы программы — редкий случай. Например, если используете DI с hanami экшенами, то в экшен пробрасывается интерактор или репозиторий. Вероятность того, что в рантайме экшен будет использовать другой репозиторий или интерактор, крайне мала.

В случае паттерна strategy вероятность передачи разных объектов выше. Например, использование разных форматов данных (http, pdf, xml, etc) в одном рантайме. 

&gt А как ты для себя решаешь, когда использовать service object, а когда interactor?

Функциональные объекты похожи между собой. Различие в деталях — и иногда эти детали важны, а иногда — легко опускаются. 

Немного теории: сервисы — объекты, которые принимают и возвращают данные. У таких объектов нет возвращаемого стейта, а для разработчика это выглядит как функция y = f(x).  Неважно, вернется success или failed, главное — получить результат. 

Интерактор — другое. Это тот же сервис, но вместо данных возвращается еще и стейт кода. Можно легко сделать «интерактор» из ~~говна и палок~~ подручных средств. Для этого  достаточно просто возвращать хеш со статусом кода и данными:
<br/>class Service<br/>  def call(payload)<br/>    validation = UserSchema.call(payload)<br/><br/>    if validation.success?<br/>      user = UserRepository.new.create(payload)<br/>      { success?: ture, user: user }<br/>    else<br/>      { success?: false, errors: validation.errors }<br/>    end<br/>  end<br/>end<br/><br/>result = Service.new.call(name: Anton)<br/>result[:success?] # =&gt true<br/>result[:user] # =&gt #&ltUser:xxx &gt<br/><br/>result = Service.new.call(name: nil)<br/>result[:success?] # =&gt false<br/>result[:errors] # =&gt { name: [should be not empty] }<br/>

Код выше идеологически не отличается от использования hanami-interactor или interactor gem. Но для себя я выработал правило: если стейт не важен, использую сервис. Если стейт важен — интерактор или оперейшен с монадой, хешем.

Возникает логичный вопрос: в чем различие между оперейшеном, интерактором и сервисом? Об этом поговорим в следующий раз :)
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:27
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267650] => stdClass Object
                (
                    [ID] => 1267650
                    [TgID] => 31
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-28 14:18:33
                    [Text] => Организационные моменты

1. Чтобы было проще искать конкретные сообщения и понимать взаимосвязь некоторых тем, я добавил оглавление. Там же есть ссылка на mindmap по функциональным объектам.
http://telegra.ph/Pepegramming-Contents-07-16

2. Появилась форма обратной связи. Ответы на вопрсы — хороший способ глубже понять тему как вам, так и мне. Я считаю, что не бывает глупых вопросов — они все важны. Поэтому на любой фидбек я отвечу в течение пары дней.  Если вам хочется что-то спросить или посоветовать, воспользуйтесь анонимной формой или просто напишите мне в личку (@davydovanton).
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:26
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267649] => stdClass Object
                (
                    [ID] => 1267649
                    [TgID] => 30
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-28 01:30:22
                    [Text] => Сегодня я расскажу о фиче ханами, над которой работаю сейчас и которую хотел бы видеть в следующей версии (1.1).

Для начала — теория. В ханами контейнерная архитектура. Это значит, что проект на ханами состоит из набора приложений. Разработчик волен выбирать сам, как называть приложения. Например: web, api, admin. Или доменные приложения (account, cart, posts, etc). Каждое из них — набор контроллеров и средств представления данных. Например, вью объекты + темплейты, или же сериализаторы для API. Эти приложения полностью изолированы и загружаются в память при старте сервера.

Теперь о самой фиче. Идея простая: если у есть изолированные приложения, при старте ханами-сервера было бы логично запускать только некоторые из них. Я вижу четыре кейса применения этой идеи:

1. Запуск бэкграунд-процессинга, например, sidekiq, без приложений. Это нужно, чтобы не загружать в память ненужный код, который не будет выполняться.
2. Если существует web-приложение, на которое приходится большая часть нагрузки, можно легко заскейлиться. Поднимите кластер серверов только с web-приложением, опять же, не загружая в память лишнего.
3. Если необходимо защитить админки, это можно легко сделать, запустив конкретное приложение в приватной сети. При этом саму админку в открытой сети можно не запускать. В этом случае злоумышленник не сможет взломать auth и узнать эндпоинты админских приложений.
4. Кейс повышенной сложности: если есть главное приложение и куча админок или внутренних приложений, не нужно дублировать бизнес логику или модель данных. Просто поднимите внутренние сервера и на каждом запустите сервер с нужным приложением.

Последний пункт объясню подробнее. Много раз видел, как создают больше одного приложения с общей базой. На предыдущей работе было 3 приложения с одной базой и одинаковыми моделями, которые надо было как-то поддерживать. Каждый раз возникали одни и те же проблемы: начиная от копирования модели и кучи логики, связанной с доменной областью, заканчивая одинаковыми патчами 2+ проектов, которые надо сделать и проверить.  Конечно, один API-сервер решает часть проблем, но в моем случае это не работало.

Аналогичный функционал существует в dry-web. Его я использую в своей работе. К сожалению, я не знаю других руби-фреймворков, которые позволяют делать подобные вещи. Если вы знаете другие примеры — расскажите об этом. Для заинтересовавшихся — ишью на гитхабе: https://github.com/hanami/hanami/issues/778
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:26
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267648] => stdClass Object
                (
                    [ID] => 1267648
                    [TgID] => 29
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-26 00:47:03
                    [Text] => Я работаю в американском healthcare стартапе. Медицина в Штатах отличается тем, что там много проверенных решений.

Каждый житель, имеющий страховку, приписан к определенной аптеке. Большинство лекарств доступно только по рецепту, и покупать их можно только в указанной в рецепте аптеке. Если владелец страховки захочет сменить аптеку, нужно предупредить новую аптеку, чтобы та получила его данные. Туда должен быть отправлен факс вида: «One of our members would like to transfer a prescription to your pharmacy» с полными данными этого пользователя.

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

Во-первых, для факсов существует специальный API у twilio. Есть и другие API, но twilio уже используется в нашем приложении. В документации говорится — чтобы послать факс, необходимо знать 3 вещи:
* телефон получателя
* телефон отправителя
* ссылку на *.pdf файл, который будет отправлен по факсу

Итого, чтобы послать факс, нужно:
Собрать данные → Сгенерировать pdf → Разместить файл в облачном сторадже → Передать телефоны и ссылку на файл в API.

Собрать данные
Стучим в базу и собираем данные. В моем случае это ROM repository, через который вытаскиваются данные об аккаунте из BD.

Сгенерировать pdf
Из всех гемов мне понравился prawn, который легко создает *.pdf файлы. Из плюсоов:
* нативный
* понятная документация с множеством примеров
* можно создать изолированный класс для генерации .pdf

Разместить файл в облачном сторадже
Тут мало подробностей. Я использовал s3, но если у вас не сервис от aws — проблем быть не должно. Главное — получить ссылку.

Передать телефоны и ссылку на файл в API
В документации к twilio указан пример отправки факса. Делаем POST-запрос на twilio URL и передаем параметры.

Собираем шаги вместе
Каждый из этих шагов написан в виде функциональных объектов (оперейшенов). А потом я объединил все объекты в одной транзакции:
<br/>class TransferMedicationToPharmasy<br/>  include Dry::Transaction(container: Application)<br/><br/>  step :read_user, with: operations.read_user<br/>  step :generate, with: operations.generate_pdf<br/>  step :send_to_s3, with: operations.send_to_s3<br/>  step :send_fax, with: operations.send_fax<br/>end<br/>

На выходе получил класс, который вызывается в бэкграунд-процессинге: TransferMedicationToPharmasy.new.call(account_id).

Выводы
* Отправлять факсы проще, чем кажется.
* Старые технологии, о которых забыли модные ребята, могут приносить деньги.
* Не все задачи, которые кажутся сложными на первый взгляд, на самом деле таковыми являются.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1700
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:24
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267647] => stdClass Object
                (
                    [ID] => 1267647
                    [TgID] => 28
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-19 23:57:53
                    [Text] => Завтра состоится митап в москве. Последние пару дней мы слушали доклады спикеров: задавали ребятам вопросы и давали рекомендации по поводу слайдов. Расскажу здесь о правилах, которые, на мой взгляд, помогут сделать презентацию качественной.

Что узнает пользователь
Это вопрос, который необходимо себе задать с самого начала: «Что полезного узнает слушатель»? Именно с этого я сам начинаю работу над презентацией.
Мотивация спикера — это очень важно. Если вы идете выступать только из-за того, что заставило начальство, или чтобы показать себя, то качество вашего выступления и всего мероприятия может пострадать.

Расскажите историю
Это правило самое сложное для меня. Интересная презентация — опыт, а излагать этот опыт проще всего в виде истории. У любой истории есть начало, завязка, кульминация и ценность. Не рассказывайте личные истории, если не хотите. Важно, чтобы у доклада сохранялась последовательность и смысловые переходы между частями.
Под этот пункт подходит и другая проблема. Часто выступающие грешат тем, что пересказывают документацию или же рассказывают о совершенно абстрактных вещах.
Это тяжело для слушателя. Во-первых, зачем слушать такой доклад, если можно просто почитать документацию? Отнимать у слушателей 30 минут времени — некрасиво. Во-вторых, если люди не разбираются в практической области применения, им будет сложно понять абстрактную штуку.

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

Меньше текста на слайдах
Часто замечаю, что люди пишут много текста на слайдах. Такие слайды выглядят перегруженно, отвлекают от речи докладчика. Возможно, это удобно для спикера: часть текста можно просто прочитать со слайда, а не запоминать. Но доклад — для слушателей, а не для спикеров. Разбейте текст на слайды (1 слайд — 1 термин), попробовать заменить текст картинками или же просто выкинуть лишнее.

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

Оценивайте доклад честно
И напоследок — совет, который пару раз выручал. За пару дней до выступления запишите свою речь на видео. Обязательно со слайдами. Потом посмотрите и ответьте себе честно: было вам интересно на месте слушателя или нет? Также это отличная тренировка и способ отшлифовать свою речь.

Запомнить

- Сделайте доклад полезным для слушателя, а не для себя.
- Рассказывайте связанную историю вместо рандомных фактов.
- Рассказать о проблемах — способ поделиться опытом.
- Много текста на слайде — мало внимания к слайду.
- Подготовьтесь заранее и сделайте собственный прогон доклада с записью и последующим разбором.

Ссылки
- Советы от Scott Hanselman
- Советы от Zach Holman
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1800
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:24
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267646] => stdClass Object
                (
                    [ID] => 1267646
                    [TgID] => 27
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-16 23:10:17
                    [Text] => Тут подсказали, что про railway programming в elixir есть лучше статья:
http://www.scottmessinger.com/2016/03/25/railway-development-in-elixir-using-with/
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1900
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:23
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267644] => stdClass Object
                (
                    [ID] => 1267644
                    [TgID] => 25
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-16 22:45:19
                    [Text] => Вынести логику

Первое,что приходит в голову — создать еще одну абстракцию. Выносим туда условия и вызовы наших функциональных объектов. Например, вот так:
<br/>class UserOperation<br/>  def call(payload)<br/>    result = ValidateUser.new.call( ... )<br/>    result = result.success? ? CreateUser.new.call( ... ) : result<br/>    result<br/>  end<br/>end<br/><br/>if UserOperation.new.call({ ... }).success?<br/>  ...<br/>end<br/>
Плюсы:
  - процесс создания user находится в одном месте
  - легко переиспользовать объект

Минусы:
  - решение не решает проблему нескольких условий, а просто размазывает логику


Railway Oriented Programming

Не думайте, что это связано с Ruby on Rails, потому что это подход из мира функционального программирования, который исправляет ситуацию с условиями.

Создается цепочка функциональных объектов, в которые передаются данные. Дальше есть только 2 пути, по которому эти данные будут идти. Либо по success-пути, что будет значить, что объекты вернули положительное значение. Либо, зафейлившись на одном из объектов, возвращают значение failed. В конце можно просто обработать значение, как в интеракторе, и выполнить необходимую логику.

Схематично это выглядит следующим образом.

Допустим, есть объект, который принимает данные и возвращает два разных вида данных — success и failed:
<br/>success data → first function object → success data<br/> failed data → first function object → failed data<br/><br/>success data → second function object → success data<br/>failed data → second function object → failed data<br/>
В таком случае можно сделать цепочку объектов:

success data → first function object → second function object → success data
failed data → first function object → second function object → failed data
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 1900
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:22
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267645] => stdClass Object
                (
                    [ID] => 1267645
                    [TgID] => 26
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-16 22:45:19
                    [Text] => Я знаю 2 способа применения Railway Oriented Programming в Ruby:

Waterfall

Гем, который чейнит функциональные объекты и работает с возвращаемым значением. Выглядит это так:

<br/>Wf.new<br/>  .chain(user1: :user) { FetchUser.new(1) }<br/>  .chain(user2: :user) { FetchUser.new(2) }<br/>  .chain  {|outflow| puts(outflow.user1, outflow.user2)  } # report success<br/>  .on_dam {|error|   puts(error)      }                    # report error<br/>

Использование бизнес-транзакций

Бизнес-транзакции выполняют заданную логику шаг за шагом. Вам нужно просто создать класс, объявить шаги, вызвать этот класс с нужными данными — и дело в шляпе.

Учтите, что придется использовать объект, который будет хранить в себе success/failed состояние и значение. Это нужно для передачи состояния между шагами транзакции. Выбирайте сами — подойдет все, что угодно, например, собственный класс, хеш или Either монада (о монадах в следующий раз).

В Ruby есть 3 библиотеки, которые реализуют транзакции:

* operation из trailblazer
* solid use case gem
* dry-transaction

Я фанат dry-transaction, так как библиотека позволяет:
* использовать матчер для возвращаемого значения
* работать с контейнерами (о контейнерах тоже поговорим позже)
* использовать DI в виде инжектинга операций
* использовать один из трех видов шагов (возвращать любой результат как успешный, возвращать failed при exception и передавать данные и не думать о возвращаемом результате)
* создавать кастомные адаптеры для шагов
* многое другое

Использование библиотеки выглядит следующим образом:

<br/>class CreateUser<br/> include Dry::Transaction<br/><br/>  step :validate<br/>  step :persist<br/><br/>  def validate(input)<br/>    # ...<br/>  end<br/><br/>  def persist(input)<br/>    # ...<br/>  end<br/>end<br/><br/>CreateUser.new.call(name: &quotJane&quot, email: &quotjane@doe.com&quot) do |m|<br/>  m.success do |value|<br/>    # ...<br/>  end<br/><br/>  m.failure do |error|<br/>    # ...<br/>  end<br/>end<br/>

Пример рефакторинга знакомого класса с использованием транзакций.

## Запомнить

* Проблема с чейнингом логики возникает чаще, чем кажется.
* Только лишь вынос логики не поможет справиться с хаосом условий.
* Railway Oriented Programming позволяет забыть о проблеме хаоса условий, а также использовать функциональный подход обработки данных в приложении.
* Места применения Railway Oriented Programming — экшены и любые другие места, где у вас есть «поток» данных.
* Забудьте о велосипедах, возьмите одну из готовых библиотек для работы с бизнес-транзакциями.
* dry-transactions — самая навороченная и гибкая из этих библиотек.

## Ссылки

* Главная страница railway programming где можно найти кучу ссылок и примеров
* Описание того, как чейнить объекты &quotправильно&quot
* Практическое руководство функционального программирования в rails
* Пример railway programming в elexir
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 2000
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:22
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

            [1267643] => stdClass Object
                (
                    [ID] => 1267643
                    [TgID] => 24
                    [TgUserID] => 
                    [TgChatID] => -1001106477565
                    [DateAdded] => 2017-07-16 22:45:18
                    [Text] => #functional_objects

В прошлый раз мы говорили о функциональных объектах и интеракторах. Сегодня рассмотрим случай, когда больше одного функционального объекта выполняют код последовательно в одном месте. Простой пример: экшен, который валидирует данные, сохраняет объект, вызывает нотификации и обрабатывает результат для нужного http-ответа. Например:
<br/>result = ValidateUser.new.call( ... )<br/>result = result.success? ? CreateUser.new.call( ... ) : result<br/><br/>if result2.success?<br/> redirect_to<br/>else<br/>  render<br/>end<br/>
Или просто код, который валидирует две разные сущности:
<br/>validation_post_result = ValidatePost.new.call( ... )<br/>validation_comments_result = ValidateComments.new.call( ... )<br/><br/>if validation_post_result.success? &amp&amp validation_comments_result.success?<br/>  ...<br/>end<br/>
Или же код, который запускает цепочку сервис объектов:
<br/>UserCreator.call(...) &amp&amp CommentCreator.call(...) &amp&amp ...<br/>
В этих примерах много лишних условий, которые приводятся к общему правилу: выполни пачку действий и верни общий статус. Выглядит такое решение сложным для понимания и будущей отладки, поэтому давайте попробуем упростить код.
                    [IsVisible] => 1
                    [DateEdited] => 
                    [Views] => 2000
                    [ViewsLastDateUpdated] => 2018-12-25 22:07:20
                    [Views1] => 
                    [Views2] => 
                    [Views3] => 
                    [Views7] => 
                    [Views30] => 
                    [IsViewsAvailable] => 1
                    [Photo] => 
                    [Firstname] => 
                    [Lastname] => 
                    [Title] => 2pegramming
                    [PhotoSmall] => https://barzha.top/data/photos/AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg.jpg
                    [PhotoBig] => https://barzha.top/data/photos/AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg.jpg
                    [ChanPhotoSmall] => AQADAgATD-S3DgAE3VTcp3WuDXYG4gACAg
                    [ChanPhotoBig] => AQADAgATD-S3DgAE-LXX1PXu7OsI4gACAg
                    [Link] => pepegramming
                )

        )

    [StatsDaily] => Array
        (
            [0] => stdClass Object
                (
                    [DateTarget] => 2018-02-02
                    [Members] => 457
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [1] => stdClass Object
                (
                    [DateTarget] => 2018-02-03
                    [Members] => 456
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [2] => stdClass Object
                (
                    [DateTarget] => 2018-02-04
                    [Members] => 456
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [3] => stdClass Object
                (
                    [DateTarget] => 2018-02-05
                    [Members] => 457
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [4] => stdClass Object
                (
                    [DateTarget] => 2018-02-06
                    [Members] => 457
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [5] => stdClass Object
                (
                    [DateTarget] => 2018-02-07
                    [Members] => 457
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [6] => stdClass Object
                (
                    [DateTarget] => 2018-02-08
                    [Members] => 457
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [7] => stdClass Object
                (
                    [DateTarget] => 2018-02-09
                    [Members] => 457
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [8] => stdClass Object
                (
                    [DateTarget] => 2018-02-10
                    [Members] => 456
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [9] => stdClass Object
                (
                    [DateTarget] => 2018-02-11
                    [Members] => 458
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [10] => stdClass Object
                (
                    [DateTarget] => 2018-02-12
                    [Members] => 464
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [11] => stdClass Object
                (
                    [DateTarget] => 2018-02-13
                    [Members] => 465
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [12] => stdClass Object
                (
                    [DateTarget] => 2018-02-14
                    [Members] => 465
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [13] => stdClass Object
                (
                    [DateTarget] => 2018-02-15
                    [Members] => 464
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [14] => stdClass Object
                (
                    [DateTarget] => 2018-02-16
                    [Members] => 464
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [15] => stdClass Object
                (
                    [DateTarget] => 2018-02-17
                    [Members] => 464
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [16] => stdClass Object
                (
                    [DateTarget] => 2018-02-18
                    [Members] => 464
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [17] => stdClass Object
                (
                    [DateTarget] => 2018-02-19
                    [Members] => 463
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [18] => stdClass Object
                (
                    [DateTarget] => 2018-02-20
                    [Members] => 466
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [19] => stdClass Object
                (
                    [DateTarget] => 2018-02-21
                    [Members] => 466
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [20] => stdClass Object
                (
                    [DateTarget] => 2018-02-22
                    [Members] => 466
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [21] => stdClass Object
                (
                    [DateTarget] => 2018-02-23
                    [Members] => 466
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [22] => stdClass Object
                (
                    [DateTarget] => 2018-02-24
                    [Members] => 471
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [23] => stdClass Object
                (
                    [DateTarget] => 2018-02-25
                    [Members] => 471
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [24] => stdClass Object
                (
                    [DateTarget] => 2018-02-26
                    [Members] => 471
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [25] => stdClass Object
                (
                    [DateTarget] => 2018-02-27
                    [Members] => 471
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [26] => stdClass Object
                (
                    [DateTarget] => 2018-02-28
                    [Members] => 472
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [27] => stdClass Object
                (
                    [DateTarget] => 2018-03-01
                    [Members] => 472
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [28] => stdClass Object
                (
                    [DateTarget] => 2018-03-02
                    [Members] => 473
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [29] => stdClass Object
                (
                    [DateTarget] => 2018-03-03
                    [Members] => 470
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [30] => stdClass Object
                (
                    [DateTarget] => 2018-03-04
                    [Members] => 470
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [31] => stdClass Object
                (
                    [DateTarget] => 2018-03-05
                    [Members] => 471
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [32] => stdClass Object
                (
                    [DateTarget] => 2018-03-06
                    [Members] => 471
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [33] => stdClass Object
                (
                    [DateTarget] => 2018-03-07
                    [Members] => 472
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [34] => stdClass Object
                (
                    [DateTarget] => 2018-03-08
                    [Members] => 472
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [35] => stdClass Object
                (
                    [DateTarget] => 2018-03-09
                    [Members] => 472
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [36] => stdClass Object
                (
                    [DateTarget] => 2018-03-10
                    [Members] => 474
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [37] => stdClass Object
                (
                    [DateTarget] => 2018-03-11
                    [Members] => 473
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [38] => stdClass Object
                (
                    [DateTarget] => 2018-03-12
                    [Members] => 477
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [39] => stdClass Object
                (
                    [DateTarget] => 2018-03-13
                    [Members] => 481
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [40] => stdClass Object
                (
                    [DateTarget] => 2018-03-14
                    [Members] => 482
                    [Cost] => 0
                    [Messages] => 44
                    [Views] => 
                )

            [41] => stdClass Object
                (
                    [DateTarget] => 2018-03-15
                    [Members] => 482
                    [Cost] => 0
                    [Messages] => 48
                    [Views] => 
                )

            [42] => stdClass Object
                (
                    [DateTarget] => 2018-03-16
                    [Members] => 482
                    [Cost] => 0
                    [Messages] => 48
                    [Views] => 
                )

            [43] => stdClass Object
                (
                    [DateTarget] => 2018-03-17
                    [Members] => 482
                    [Cost] => 0
                    [Messages] => 48
                    [Views] => 
                )

            [44] => stdClass Object
                (
                    [DateTarget] => 2018-03-18
                    [Members] => 482
                    [Cost] => 0
                    [Messages] => 48
                    [Views] => 
                )

            [45] => stdClass Object
                (
                    [DateTarget] => 2018-03-19
                    [Members] => 488
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [46] => stdClass Object
                (
                    [DateTarget] => 2018-03-20
                    [Members] => 492
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [47] => stdClass Object
                (
                    [DateTarget] => 2018-03-21
                    [Members] => 494
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [48] => stdClass Object
                (
                    [DateTarget] => 2018-03-22
                    [Members] => 498
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [49] => stdClass Object
                (
                    [DateTarget] => 2018-03-23
                    [Members] => 499
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [50] => stdClass Object
                (
                    [DateTarget] => 2018-03-24
                    [Members] => 500
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [51] => stdClass Object
                (
                    [DateTarget] => 2018-03-25
                    [Members] => 507
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [52] => stdClass Object
                (
                    [DateTarget] => 2018-03-26
                    [Members] => 508
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [53] => stdClass Object
                (
                    [DateTarget] => 2018-03-27
                    [Members] => 508
                    [Cost] => 0
                    [Messages] => 54
                    [Views] => 
                )

            [54] => stdClass Object
                (
                    [DateTarget] => 2018-03-28
                    [Members] => 508
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [55] => stdClass Object
                (
                    [DateTarget] => 2018-03-29
                    [Members] => 509
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [56] => stdClass Object
                (
                    [DateTarget] => 2018-03-30
                    [Members] => 510
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [57] => stdClass Object
                (
                    [DateTarget] => 2018-03-31
                    [Members] => 517
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [58] => stdClass Object
                (
                    [DateTarget] => 2018-04-01
                    [Members] => 519
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [59] => stdClass Object
                (
                    [DateTarget] => 2018-04-02
                    [Members] => 522
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [60] => stdClass Object
                (
                    [DateTarget] => 2018-04-03
                    [Members] => 523
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [61] => stdClass Object
                (
                    [DateTarget] => 2018-04-04
                    [Members] => 524
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [62] => stdClass Object
                (
                    [DateTarget] => 2018-04-05
                    [Members] => 525
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [63] => stdClass Object
                (
                    [DateTarget] => 2018-04-06
                    [Members] => 526
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [64] => stdClass Object
                (
                    [DateTarget] => 2018-04-07
                    [Members] => 529
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [65] => stdClass Object
                (
                    [DateTarget] => 2018-04-08
                    [Members] => 529
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [66] => stdClass Object
                (
                    [DateTarget] => 2018-04-09
                    [Members] => 529
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [67] => stdClass Object
                (
                    [DateTarget] => 2018-04-10
                    [Members] => 531
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [68] => stdClass Object
                (
                    [DateTarget] => 2018-04-11
                    [Members] => 533
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [69] => stdClass Object
                (
                    [DateTarget] => 2018-04-12
                    [Members] => 534
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [70] => stdClass Object
                (
                    [DateTarget] => 2018-04-13
                    [Members] => 535
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [71] => stdClass Object
                (
                    [DateTarget] => 2018-04-14
                    [Members] => 536
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [72] => stdClass Object
                (
                    [DateTarget] => 2018-04-15
                    [Members] => 536
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [73] => stdClass Object
                (
                    [DateTarget] => 2018-04-16
                    [Members] => 538
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [74] => stdClass Object
                (
                    [DateTarget] => 2018-04-17
                    [Members] => 539
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [75] => stdClass Object
                (
                    [DateTarget] => 2018-04-18
                    [Members] => 539
                    [Cost] => 0
                    [Messages] => 56
                    [Views] => 
                )

            [76] => stdClass Object
                (
                    [DateTarget] => 2018-04-19
                    [Members] => 551
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [77] => stdClass Object
                (
                    [DateTarget] => 2018-04-20
                    [Members] => 556
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [78] => stdClass Object
                (
                    [DateTarget] => 2018-04-21
                    [Members] => 558
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [79] => stdClass Object
                (
                    [DateTarget] => 2018-04-22
                    [Members] => 561
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [80] => stdClass Object
                (
                    [DateTarget] => 2018-04-23
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [81] => stdClass Object
                (
                    [DateTarget] => 2018-04-24
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [82] => stdClass Object
                (
                    [DateTarget] => 2018-04-25
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [83] => stdClass Object
                (
                    [DateTarget] => 2018-04-26
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [84] => stdClass Object
                (
                    [DateTarget] => 2018-04-27
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [85] => stdClass Object
                (
                    [DateTarget] => 2018-04-28
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [86] => stdClass Object
                (
                    [DateTarget] => 2018-04-29
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [87] => stdClass Object
                (
                    [DateTarget] => 2018-04-30
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [88] => stdClass Object
                (
                    [DateTarget] => 2018-05-01
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [89] => stdClass Object
                (
                    [DateTarget] => 2018-05-02
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [90] => stdClass Object
                (
                    [DateTarget] => 2018-05-03
                    [Members] => 560
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [91] => stdClass Object
                (
                    [DateTarget] => 2018-05-04
                    [Members] => 561
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [92] => stdClass Object
                (
                    [DateTarget] => 2018-05-05
                    [Members] => 561
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [93] => stdClass Object
                (
                    [DateTarget] => 2018-05-06
                    [Members] => 561
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [94] => stdClass Object
                (
                    [DateTarget] => 2018-05-07
                    [Members] => 561
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [95] => stdClass Object
                (
                    [DateTarget] => 2018-05-08
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [96] => stdClass Object
                (
                    [DateTarget] => 2018-05-09
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [97] => stdClass Object
                (
                    [DateTarget] => 2018-05-10
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [98] => stdClass Object
                (
                    [DateTarget] => 2018-05-11
                    [Members] => 564
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [99] => stdClass Object
                (
                    [DateTarget] => 2018-05-12
                    [Members] => 564
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [100] => stdClass Object
                (
                    [DateTarget] => 2018-05-13
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [101] => stdClass Object
                (
                    [DateTarget] => 2018-05-14
                    [Members] => 564
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [102] => stdClass Object
                (
                    [DateTarget] => 2018-05-15
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 60
                    [Views] => 
                )

            [103] => stdClass Object
                (
                    [DateTarget] => 2018-05-16
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 64
                    [Views] => 
                )

            [104] => stdClass Object
                (
                    [DateTarget] => 2018-05-17
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 64
                    [Views] => 
                )

            [105] => stdClass Object
                (
                    [DateTarget] => 2018-05-18
                    [Members] => 564
                    [Cost] => 0
                    [Messages] => 64
                    [Views] => 
                )

            [106] => stdClass Object
                (
                    [DateTarget] => 2018-05-19
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 64
                    [Views] => 
                )

            [107] => stdClass Object
                (
                    [DateTarget] => 2018-05-20
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 64
                    [Views] => 
                )

            [108] => stdClass Object
                (
                    [DateTarget] => 2018-05-21
                    [Members] => 566
                    [Cost] => 0
                    [Messages] => 64
                    [Views] => 
                )

            [109] => stdClass Object
                (
                    [DateTarget] => 2018-05-22
                    [Members] => 567
                    [Cost] => 0
                    [Messages] => 64
                    [Views] => 
                )

            [110] => stdClass Object
                (
                    [DateTarget] => 2018-05-23
                    [Members] => 568
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [111] => stdClass Object
                (
                    [DateTarget] => 2018-05-24
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [112] => stdClass Object
                (
                    [DateTarget] => 2018-05-25
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [113] => stdClass Object
                (
                    [DateTarget] => 2018-05-26
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [114] => stdClass Object
                (
                    [DateTarget] => 2018-05-27
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [115] => stdClass Object
                (
                    [DateTarget] => 2018-05-28
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [116] => stdClass Object
                (
                    [DateTarget] => 2018-05-29
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [117] => stdClass Object
                (
                    [DateTarget] => 2018-05-30
                    [Members] => 562
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [118] => stdClass Object
                (
                    [DateTarget] => 2018-05-31
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [119] => stdClass Object
                (
                    [DateTarget] => 2018-06-01
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [120] => stdClass Object
                (
                    [DateTarget] => 2018-06-02
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [121] => stdClass Object
                (
                    [DateTarget] => 2018-06-03
                    [Members] => 564
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [122] => stdClass Object
                (
                    [DateTarget] => 2018-06-04
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [123] => stdClass Object
                (
                    [DateTarget] => 2018-06-05
                    [Members] => 562
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [124] => stdClass Object
                (
                    [DateTarget] => 2018-06-06
                    [Members] => 562
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [125] => stdClass Object
                (
                    [DateTarget] => 2018-06-07
                    [Members] => 563
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [126] => stdClass Object
                (
                    [DateTarget] => 2018-06-08
                    [Members] => 565
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [127] => stdClass Object
                (
                    [DateTarget] => 2018-06-09
                    [Members] => 564
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [128] => stdClass Object
                (
                    [DateTarget] => 2018-06-10
                    [Members] => 568
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [129] => stdClass Object
                (
                    [DateTarget] => 2018-06-11
                    [Members] => 569
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [130] => stdClass Object
                (
                    [DateTarget] => 2018-06-12
                    [Members] => 568
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [131] => stdClass Object
                (
                    [DateTarget] => 2018-06-13
                    [Members] => 568
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [132] => stdClass Object
                (
                    [DateTarget] => 2018-06-14
                    [Members] => 570
                    [Cost] => 0
                    [Messages] => 65
                    [Views] => 
                )

            [133] => stdClass Object
                (
                    [DateTarget] => 2018-06-15
                    [Members] => 571
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [134] => stdClass Object
                (
                    [DateTarget] => 2018-06-16
                    [Members] => 571
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [135] => stdClass Object
                (
                    [DateTarget] => 2018-06-17
                    [Members] => 572
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [136] => stdClass Object
                (
                    [DateTarget] => 2018-06-18
                    [Members] => 571
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [137] => stdClass Object
                (
                    [DateTarget] => 2018-06-19
                    [Members] => 572
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [138] => stdClass Object
                (
                    [DateTarget] => 2018-06-20
                    [Members] => 573
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [139] => stdClass Object
                (
                    [DateTarget] => 2018-06-21
                    [Members] => 573
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [140] => stdClass Object
                (
                    [DateTarget] => 2018-06-22
                    [Members] => 573
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [141] => stdClass Object
                (
                    [DateTarget] => 2018-06-23
                    [Members] => 573
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [142] => stdClass Object
                (
                    [DateTarget] => 2018-06-24
                    [Members] => 573
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [143] => stdClass Object
                (
                    [DateTarget] => 2018-06-25
                    [Members] => 574
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [144] => stdClass Object
                (
                    [DateTarget] => 2018-06-26
                    [Members] => 574
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [145] => stdClass Object
                (
                    [DateTarget] => 2018-06-27
                    [Members] => 574
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [146] => stdClass Object
                (
                    [DateTarget] => 2018-06-28
                    [Members] => 574
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [147] => stdClass Object
                (
                    [DateTarget] => 2018-06-29
                    [Members] => 576
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [148] => stdClass Object
                (
                    [DateTarget] => 2018-06-30
                    [Members] => 577
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [149] => stdClass Object
                (
                    [DateTarget] => 2018-07-01
                    [Members] => 577
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [150] => stdClass Object
                (
                    [DateTarget] => 2018-07-02
                    [Members] => 577
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [151] => stdClass Object
                (
                    [DateTarget] => 2018-07-03
                    [Members] => 578
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [152] => stdClass Object
                (
                    [DateTarget] => 2018-07-04
                    [Members] => 578
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [153] => stdClass Object
                (
                    [DateTarget] => 2018-07-05
                    [Members] => 581
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [154] => stdClass Object
                (
                    [DateTarget] => 2018-07-06
                    [Members] => 582
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [155] => stdClass Object
                (
                    [DateTarget] => 2018-07-07
                    [Members] => 582
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [156] => stdClass Object
                (
                    [DateTarget] => 2018-07-08
                    [Members] => 582
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [157] => stdClass Object
                (
                    [DateTarget] => 2018-07-09
                    [Members] => 583
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [158] => stdClass Object
                (
                    [DateTarget] => 2018-07-10
                    [Members] => 584
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [159] => stdClass Object
                (
                    [DateTarget] => 2018-07-11
                    [Members] => 584
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [160] => stdClass Object
                (
                    [DateTarget] => 2018-07-12
                    [Members] => 583
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [161] => stdClass Object
                (
                    [DateTarget] => 2018-07-13
                    [Members] => 583
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [162] => stdClass Object
                (
                    [DateTarget] => 2018-07-14
                    [Members] => 587
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [163] => stdClass Object
                (
                    [DateTarget] => 2018-07-15
                    [Members] => 589
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [164] => stdClass Object
                (
                    [DateTarget] => 2018-07-16
                    [Members] => 589
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [165] => stdClass Object
                (
                    [DateTarget] => 2018-07-17
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [166] => stdClass Object
                (
                    [DateTarget] => 2018-07-18
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [167] => stdClass Object
                (
                    [DateTarget] => 2018-07-19
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [168] => stdClass Object
                (
                    [DateTarget] => 2018-07-20
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [169] => stdClass Object
                (
                    [DateTarget] => 2018-07-21
                    [Members] => 587
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [170] => stdClass Object
                (
                    [DateTarget] => 2018-07-22
                    [Members] => 587
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [171] => stdClass Object
                (
                    [DateTarget] => 2018-07-23
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [172] => stdClass Object
                (
                    [DateTarget] => 2018-07-24
                    [Members] => 589
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [173] => stdClass Object
                (
                    [DateTarget] => 2018-07-25
                    [Members] => 589
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [174] => stdClass Object
                (
                    [DateTarget] => 2018-07-26
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [175] => stdClass Object
                (
                    [DateTarget] => 2018-07-27
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [176] => stdClass Object
                (
                    [DateTarget] => 2018-07-28
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [177] => stdClass Object
                (
                    [DateTarget] => 2018-07-29
                    [Members] => 587
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [178] => stdClass Object
                (
                    [DateTarget] => 2018-07-30
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [179] => stdClass Object
                (
                    [DateTarget] => 2018-07-31
                    [Members] => 587
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [180] => stdClass Object
                (
                    [DateTarget] => 2018-08-01
                    [Members] => 593
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [181] => stdClass Object
                (
                    [DateTarget] => 2018-08-02
                    [Members] => 593
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [182] => stdClass Object
                (
                    [DateTarget] => 2018-08-03
                    [Members] => 593
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [183] => stdClass Object
                (
                    [DateTarget] => 2018-08-04
                    [Members] => 593
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [184] => stdClass Object
                (
                    [DateTarget] => 2018-08-05
                    [Members] => 593
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [185] => stdClass Object
                (
                    [DateTarget] => 2018-08-06
                    [Members] => 594
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [186] => stdClass Object
                (
                    [DateTarget] => 2018-08-07
                    [Members] => 595
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [187] => stdClass Object
                (
                    [DateTarget] => 2018-08-08
                    [Members] => 596
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [188] => stdClass Object
                (
                    [DateTarget] => 2018-08-09
                    [Members] => 599
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [189] => stdClass Object
                (
                    [DateTarget] => 2018-08-10
                    [Members] => 599
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [190] => stdClass Object
                (
                    [DateTarget] => 2018-08-11
                    [Members] => 599
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [191] => stdClass Object
                (
                    [DateTarget] => 2018-08-12
                    [Members] => 599
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [192] => stdClass Object
                (
                    [DateTarget] => 2018-08-13
                    [Members] => 600
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [193] => stdClass Object
                (
                    [DateTarget] => 2018-08-14
                    [Members] => 601
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [194] => stdClass Object
                (
                    [DateTarget] => 2018-08-15
                    [Members] => 600
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [195] => stdClass Object
                (
                    [DateTarget] => 2018-08-16
                    [Members] => 600
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [196] => stdClass Object
                (
                    [DateTarget] => 2018-08-17
                    [Members] => 600
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [197] => stdClass Object
                (
                    [DateTarget] => 2018-08-18
                    [Members] => 600
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [198] => stdClass Object
                (
                    [DateTarget] => 2018-08-19
                    [Members] => 599
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [199] => stdClass Object
                (
                    [DateTarget] => 2018-08-20
                    [Members] => 599
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [200] => stdClass Object
                (
                    [DateTarget] => 2018-08-21
                    [Members] => 598
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [201] => stdClass Object
                (
                    [DateTarget] => 2018-08-22
                    [Members] => 598
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [202] => stdClass Object
                (
                    [DateTarget] => 2018-08-23
                    [Members] => 599
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [203] => stdClass Object
                (
                    [DateTarget] => 2018-08-24
                    [Members] => 597
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [204] => stdClass Object
                (
                    [DateTarget] => 2018-08-25
                    [Members] => 595
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [205] => stdClass Object
                (
                    [DateTarget] => 2018-08-26
                    [Members] => 595
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [206] => stdClass Object
                (
                    [DateTarget] => 2018-08-27
                    [Members] => 593
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [207] => stdClass Object
                (
                    [DateTarget] => 2018-08-28
                    [Members] => 593
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [208] => stdClass Object
                (
                    [DateTarget] => 2018-08-29
                    [Members] => 591
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [209] => stdClass Object
                (
                    [DateTarget] => 2018-08-30
                    [Members] => 592
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [210] => stdClass Object
                (
                    [DateTarget] => 2018-08-31
                    [Members] => 591
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [211] => stdClass Object
                (
                    [DateTarget] => 2018-09-01
                    [Members] => 591
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [212] => stdClass Object
                (
                    [DateTarget] => 2018-09-02
                    [Members] => 591
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [213] => stdClass Object
                (
                    [DateTarget] => 2018-09-03
                    [Members] => 591
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [214] => stdClass Object
                (
                    [DateTarget] => 2018-09-04
                    [Members] => 590
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [215] => stdClass Object
                (
                    [DateTarget] => 2018-09-05
                    [Members] => 590
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [216] => stdClass Object
                (
                    [DateTarget] => 2018-09-06
                    [Members] => 590
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [217] => stdClass Object
                (
                    [DateTarget] => 2018-09-07
                    [Members] => 590
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [218] => stdClass Object
                (
                    [DateTarget] => 2018-09-08
                    [Members] => 590
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [219] => stdClass Object
                (
                    [DateTarget] => 2018-09-09
                    [Members] => 590
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [220] => stdClass Object
                (
                    [DateTarget] => 2018-09-10
                    [Members] => 589
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [221] => stdClass Object
                (
                    [DateTarget] => 2018-09-11
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [222] => stdClass Object
                (
                    [DateTarget] => 2018-09-12
                    [Members] => 588
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [223] => stdClass Object
                (
                    [DateTarget] => 2018-09-13
                    [Members] => 589
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [224] => stdClass Object
                (
                    [DateTarget] => 2018-09-14
                    [Members] => 592
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [225] => stdClass Object
                (
                    [DateTarget] => 2018-09-15
                    [Members] => 592
                    [Cost] => 0
                    [Messages] => 66
                    [Views] => 
                )

            [226] => stdClass Object
                (
                    [DateTarget] => 2018-09-16
                    [Members] => 591
                    [Cost] => 0
                    [Messages] => 70
                    [Views] => 
                )

            [227] => stdClass Object
                (
                    [DateTarget] => 2018-09-17
                    [Members] => 590
                    [Cost] => 0
                    [Messages] => 70
                    [Views] => 
                )

            [228] => stdClass Object
                (
                    [DateTarget] => 2018-09-20
                    [Members] => 615
                    [Cost] => 0
                    [Messages] => 70
                    [Views] => 
                )

            [229] => stdClass Object
                (
                    [DateTarget] => 2018-09-21
                    [Members] => 618
                    [Cost] => 0
                    [Messages] => 70
                    [Views] => 
                )

            [230] => stdClass Object
                (
                    [DateTarget] => 2018-09-22
                    [Members] => 619
                    [Cost] => 0
                    [Messages] => 70
                    [Views] => 
                )

            [231] => stdClass Object
                (
                    [DateTarget] => 2018-09-23
                    [Members] => 619
                    [Cost] => 0
                    [Messages] => 70
                    [Views] => 
                )

            [232] => stdClass Object
                (
                    [DateTarget] => 2018-09-24
                    [Members] => 625
                    [Cost] => 0
                    [Messages] => 70
                    [Views] => 
                )

            [233] => stdClass Object
                (
                    [DateTarget] => 2018-09-25
                    [Members] => 635
                    [Cost] => 0
                    [Messages] => 74
                    [Views] => 
                )

            [234] => stdClass Object
                (
                    [DateTarget] => 2018-09-26
                    [Members] => 636
                    [Cost] => 0
                    [Messages] => 74
                    [Views] => 
                )

            [235] => stdClass Object
                (
                    [DateTarget] => 2018-09-27
                    [Members] => 643
                    [Cost] => 0
                    [Messages] => 74
                    [Views] => 
                )

            [236] => stdClass Object
                (
                    [DateTarget] => 2018-09-28
                    [Members] => 644
                    [Cost] => 0
                    [Messages] => 74
                    [Views] => 
                )

            [237] => stdClass Object
                (
                    [DateTarget] => 2018-09-29
                    [Members] => 642
                    [Cost] => 0
                    [Messages] => 78
                    [Views] => 
                )

            [238] => stdClass Object
                (
                    [DateTarget] => 2018-09-30
                    [Members] => 643
                    [Cost] => 0
                    [Messages] => 78
                    [Views] => 
                )

            [239] => stdClass Object
                (
                    [DateTarget] => 2018-10-01
                    [Members] => 646
                    [Cost] => 0
                    [Messages] => 78
                    [Views] => 
                )

            [240] => stdClass Object
                (
                    [DateTarget] => 2018-10-02
                    [Members] => 647
                    [Cost] => 0
                    [Messages] => 79
                    [Views] => 
                )

            [241] => stdClass Object
                (
                    [DateTarget] => 2018-10-03
                    [Members] => 647
                    [Cost] => 0
                    [Messages] => 79
                    [Views] => 
                )

            [242] => stdClass Object
                (
                    [DateTarget] => 2018-10-04
                    [Members] => 647
                    [Cost] => 0
                    [Messages] => 79
                    [Views] => 
                )

            [243] => stdClass Object
                (
                    [DateTarget] => 2018-10-05
                    [Members] => 648
                    [Cost] => 0
                    [Messages] => 79
                    [Views] => 
                )

            [244] => stdClass Object
                (
                    [DateTarget] => 2018-10-06
                    [Members] => 671
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [245] => stdClass Object
                (
                    [DateTarget] => 2018-10-07
                    [Members] => 672
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [246] => stdClass Object
                (
                    [DateTarget] => 2018-10-08
                    [Members] => 653
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [247] => stdClass Object
                (
                    [DateTarget] => 2018-10-09
                    [Members] => 654
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [248] => stdClass Object
                (
                    [DateTarget] => 2018-10-10
                    [Members] => 659
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [249] => stdClass Object
                (
                    [DateTarget] => 2018-10-11
                    [Members] => 661
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [250] => stdClass Object
                (
                    [DateTarget] => 2018-10-12
                    [Members] => 663
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [251] => stdClass Object
                (
                    [DateTarget] => 2018-10-13
                    [Members] => 663
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [252] => stdClass Object
                (
                    [DateTarget] => 2018-10-14
                    [Members] => 663
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [253] => stdClass Object
                (
                    [DateTarget] => 2018-10-15
                    [Members] => 663
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [254] => stdClass Object
                (
                    [DateTarget] => 2018-10-16
                    [Members] => 663
                    [Cost] => 0
                    [Messages] => 80
                    [Views] => 
                )

            [255] => stdClass Object
                (
                    [DateTarget] => 2018-10-17
                    [Members] => 663
                    [Cost] => 0
                    [Messages] => 82
                    [Views] => 
                )

            [256] => stdClass Object
                (
                    [DateTarget] => 2018-10-18
                    [Members] => 663
                    [Cost] => 0
                    [Messages] => 82
                    [Views] => 
                )

            [257] => stdClass Object
                (
                    [DateTarget] => 2018-10-19
                    [Members] => 666
                    [Cost] => 0
                    [Messages] => 82
                    [Views] => 
                )

            [258] => stdClass Object
                (
                    [DateTarget] => 2018-10-20
                    [Members] => 667
                    [Cost] => 0
                    [Messages] => 82
                    [Views] => 
                )

            [259] => stdClass Object
                (
                    [DateTarget] => 2018-10-21
                    [Members] => 668
                    [Cost] => 0
                    [Messages] => 83
                    [Views] => 
                )

            [260] => stdClass Object
                (
                    [DateTarget] => 2018-10-22
                    [Members] => 669
                    [Cost] => 0
                    [Messages] => 83
                    [Views] => 
                )

            [261] => stdClass Object
                (
                    [DateTarget] => 2018-10-23
                    [Members] => 669
                    [Cost] => 0
                    [Messages] => 83
                    [Views] => 
                )

            [262] => stdClass Object
                (
                    [DateTarget] => 2018-10-24
                    [Members] => 669
                    [Cost] => 0
                    [Messages] => 83
                    [Views] => 
                )

            [263] => stdClass Object
                (
                    [DateTarget] => 2018-10-25
                    [Members] => 669
                    [Cost] => 0
                    [Messages] => 83
                    [Views] =&