<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<link href="https://rust.code-maven.com/atom" rel="self" />
<title>Demo</title>
<id>https://rust.code-maven.com</id>
<updated>2016-04-03T19:19:01</updated>

  <entry>
    <title>Сайты с публичным API с CORS - Cross-Origin Resource Sharing</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-04-03T19:19:01Z</updated>
    <pubDate>2016-04-03T19:19:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/cors" />
    <id>https://rust.code-maven.com/cors</id>
    <content type="html"><![CDATA[<p>Изучая <a href="/angularjs">AngularJS</a> или какие-то другие <a href="/javascript">JavaScript</a>-фреймворки
для создания &quot;Single Page&quot; веб-приложений, не имея бекенда, вы можете добраться не слишком далеко.</p>
<p>Есть множество веб-сайтов с публичным API, который мы можем использовать, но большинство из них имеют
настройку безопасности CORS по умолчанию (не выставляя <b>Access-Control-Allow-Origin</b>), это значит, что
мы можем работать с их API из командной строки или с сервера, но не из браузера.</p>
<p>На этой странице вы найдете подборку веб-сайтов, предоставляющих API с настройкой Access-Control-Allow-Origin.
Вы можете использовать их для получения данных через Ajax-запросы.</p>
<script src="/javascripts/angular.min.js"></script>
<script>
angular.module('CORSApp', [])
    .controller('CORSController', function($scope, $http) {
        //var url = '';
        // XMLHttpRequest cannot load http://www.imdb.com/xml/find?json=1&nr=1&nm=on&q=jeniffer+garner.
        // No 'Access-Control-Allow-Origin' header is present on the requested resource.
        //var url = 'https://en.wikipedia.org/w/api.php?action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=json';
        //var url = 'https://api.smartsheet.com/2.0/sheets';
        //var url = 'http://public-api.wordpress.com/rest/v1/sites';
        $scope.clear = function() {
            console.log('clear');
            $scope.data = '';
            $scope.error = 0;
        }
        $scope.try = function() {
            $http.get($scope.url).then(
                function(response) {
                    console.log(response);
                    $scope.data = response.data;
                },
                function(response) {
                    console.log("error");
                    console.log(response);
                    $scope.error = 1;
                }
            );
        }
    });
</script>
<div ng-app="CORSApp" ng-controller="CORSController">
    <select ng-model="url" ng-change="clear()">
        <option value="http://www.imdb.com/xml/find?json=1&nr=1&nm=on&q=jeniffer+garner">IMDB (не работает)</option>
        <option value="https://api.github.com">GitHub</option>
        <option value="http://api.metacpan.org/v0/release/_search?size=10">MetaCPAN</option>
        <option value="http://api.openweathermap.org/data/2.5/weather?q=Budapest">OpenWeatherMap</option>
        <option value="https://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&format=json&api_key=6f93d9bd5fef5831ec592f0b527fdeff&user_id=9395899@N08">Flickr</option>
    <select>
    <button ng-click="try()">Try</button>
    URL: {{url}}
    <hr>
    Result: {{ data }}
    <div ng-show="error" id="error">Failed</div>
</div>
<p>Пример для Flickr <a href="https://api.flickr.com/services/rest/?&amp;method=flickr.people.getPublicPhotos&amp;format=json&amp;api_key=API_KEY&amp;user_id=USER_ID">https://api.flickr.com/services/rest/?&amp;method=flickr.people.getPublicPhotos&amp;format=json&amp;api_key=API_KEY&amp;user_id=USER_ID</a>
Вы можете получить ключ для API здесь: <a href="https://www.flickr.com/services/">App Garden</a>,
а найти user_id по username вот здесь: <a href="https://www.flickr.com/services/api/explore/flickr.people.findByUsername">Flickr username finder</a>.</p>
<p>Здесь много <a href="http://www.programmableweb.com/apis/directory">сайтов с публичным API</a>, но большинство из них
не будут работать при попытке доступа из браузера. (Они не устанавливают Access-Control-Allow-Origin)</p>
<p>Прим. переводчика: здесь немного подробнее описана технология CORS <a href="https://ru.wikipedia.org/wiki/Cross-origin_resource_sharing">https://ru.wikipedia.org/wiki/Cross-origin_resource_sharing</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Code Maven category</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-04-03T12:00:02Z</updated>
    <pubDate>2016-04-03T12:00:02Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/category" />
    <id>https://rust.code-maven.com/category</id>
    <content type="html"><![CDATA[]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Конвертация строк в числа в Ruby</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-03-27T21:02:01Z</updated>
    <pubDate>2016-03-27T21:02:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/convert-string-to-number-in-ruby" />
    <id>https://rust.code-maven.com/convert-string-to-number-in-ruby</id>
    <content type="html"><![CDATA[<p>При чтении данных из файла или другого внешнего ресурса данные всегда приходят в Ruby как
объекты <a href="http://ruby-doc.org/core-2.2.0/String.html">String (Строка)</a>.</p>
<p>Если мы хотим использовать их как числа, сначала их нужно сконвертировать в числа.</p>
<p>Но в какие и как?</p>
<p>Объект <a href="http://ruby-doc.org/core-2.2.0/String.html">String</a> в Ruby имеет несколько методов
конверации в число.</p>
<ul>
<li>
<p><code>to_i</code> сконвертирует String в <a href="http://ruby-doc.org/core-2.2.0/Integer.html">Integer</a>.</p>
</li>
<li>
<p><code>to_f</code> сконвертирует String во <a href="http://ruby-doc.org/core-2.2.0/Float.html">Float</a> (с плавающей точкой)</p>
</li>
<li>
<p><code>to_r</code> сконвертирует String в <a href="http://ruby-doc.org/core-2.2.0/Rational.html">Rational</a> number (рациональное число).</p>
</li>
<li>
<p><code>to_c</code> сконвертирует String в <a href="http://ruby-doc.org/core-2.2.0/Complex.html">Complex</a> number (комплексное число).</p>
</li>
</ul>
<h2 class="title is-4">Конкатенация</h2>
<p>Если для двух числовых значений, которые на самом деле объекты <code>String</code> (из-за обрамляющих кавычек), использовать оператор <code>+</code>,
то он будет работать как конкатенация.</p>
<pre><code>a = &quot;2&quot;
b = &quot;3&quot;
puts a+b  # 23
</code></pre>
<h2 class="title is-4">no implicit conversion of Fixnum into String (TypeError)</h2>
<p>Если одно из значений это объект <code>String</code>, а другое - число (без кавычек), и мы попробуем сложить их друг с другом, как в примере:</p>
<pre><code>puts &quot;2&quot;+3 
</code></pre>
<p>мы получим исключение: <code>no implicit conversion of Fixnum into String (TypeError)</code></p>
<h2 class="title is-4">String, которые выглядят как integer</h2>
<p><code>String</code>, содержащие целое число (integer) могут быть сконвертированы в Integer, Float, Rational number, или Complex number:</p>
<pre><code>puts a.to_i # 2
puts a.to_f # 2.0
puts a.to_r # 2/1
puts a.to_c # 2+0i
</code></pre>
<h2 class="title is-4">Как задать основание: конвертация двоичных, восьмеричных, шестнадцатеричных значений в десятичные</h2>
<p>По умолчанию <code>to_i</code> предполагает, что наш объект String представлен в десятичной системе (основание 10), но что если вы хотите это изменить?</p>
<p>Что если вы хотите рассматривать String как двоичное число, восьмеричное или шестнадцатеричное? Тогда нужно просто передать аргумент <code>base=</code>
с подходящим числом в метод <code>to_i</code>:</p>
<pre><code>puts &quot;11&quot;.to_i            # 11
puts &quot;11&quot;.to_i(base=2)    # 3
puts &quot;11&quot;.to_i(base=16)   # 17
</code></pre>
<p>Конечно шестнадцатеричные числа могут также содержать символы a-f. Функция <code>to_i</code> умеет с ними обращаться.</p>
<pre><code>puts &quot;aB&quot;.to_i(base=16)   # 171
</code></pre>
<p>Возникает вопрос, что случится, если мы используем <code>to_i</code> без указания основания для строки с шестнадцатеричным числом,
или с основанием, которое не предусматривает таких символов? Тогда просто вернется 0 (без какой-либо ошибки).</p>
<pre><code>puts &quot;aB&quot;.to_i            # 0
puts &quot;9&quot;.to_i(base=8)     # 0
</code></pre>
<p>Это подводит нас к вопросу: <b>Что случится, если не все символы могут быть сконвертированы в число?</b>
Ответ прост.
<code>to_i</code> сконвертирует все 'digits' от начала до того места, где уже не будет понятно, что делать.
Оставшаяся часть строки будет отброшена. Даже если там есть еще понимаемые значения.</p>
<pre><code>puts &quot;2x3&quot;.to_i           # 2
puts &quot;2 3&quot;.to_i           # 2
</code></pre>
<h2 class="title is-4">Конвертация в число с плавающей точкой или рациональное число</h2>
<p>Мы можем использовать остальные методы для конвертации во Floating point (число с плавающей точкой), Rational number (рациональное число), и даже в Complex number (комплексное число):
Некоторые из них понимают точку в десятичной дроби в <code>String</code></p>
<pre><code>c = &quot;14.6&quot;
puts c.to_i    # 14
puts c.to_f    # 14.6
puts c.to_r    # 73/5
puts c.to_c    # 14.6+0i
</code></pre>
<p>Некоторые даже понимают символ <code>e</code>, обозначающий экспоненту в String:</p>
<pre><code>e = &quot;2.3e4x5&quot;
puts e         # 2.3e4x5
puts e.to_i    # 2
puts e.to_f    # 23000.0
puts e.to_r    # 23000/1
puts e.to_c    # 23000.0+0i
</code></pre>
<h2 class="title is-4">Полный пример</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/string_to_number.rb">examples/ruby/string_to_number.rb</a></strong></p>
<pre><code class="language-ruby">
a = &quot;2&quot;
b = &quot;3&quot;
puts a+b  # 23
puts '-------'

# puts &quot;2&quot;+3   # no implicit conversion of Fixnum into String (TypeError)

puts a.to_i # 2
puts a.to_f # 2.0
puts a.to_r # 2/1
puts a.to_c # 2+0i
puts '-------'

puts &quot;11&quot;.to_i            # 11
puts &quot;11&quot;.to_i(base=2)    # 3
puts &quot;11&quot;.to_i(base=8)    # 9
puts &quot;11&quot;.to_i(base=16)   # 17
puts '-------'

puts &quot;aB&quot;.to_i(base=16)   # 171
puts &quot;aB&quot;.to_i            # 0
puts &quot;9&quot;.to_i(base=8)     # 0
puts '-------'

puts &quot;2x3&quot;.to_i           # 2
puts &quot;2 3&quot;.to_i           # 2
puts '-------'

c = &quot;14.6&quot;
puts c.to_i    # 14
puts c.to_f    # 14.6
puts c.to_r    # 73/5
puts c.to_c    # 14.6+0i
puts '-------'


e = &quot;2.3e4x5&quot;
puts e         # 2.3e4x5
puts e.to_i    # 2
puts e.to_f    # 23000.0
puts e.to_r    # 23000/1
puts e.to_c    # 23000.0+0i
puts '-------'



</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Условный оператор в Ruby</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-03-27T18:35:23Z</updated>
    <pubDate>2016-03-27T18:35:23Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/conditional-operator-in-ruby" />
    <id>https://rust.code-maven.com/conditional-operator-in-ruby</id>
    <content type="html"><![CDATA[<p>Официальное название оператора <code>? :</code> это <a href="https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%80%D0%BD%D0%B0%D1%80%D0%BD%D0%B0%D1%8F_%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D0%B0%D1%8F_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F">условный оператор</a>,
хотя большинство людей знают его как <b>тернарный оператор</b>, указывая на количество его операндов.</p>
<p>Есть несколько <b>унарных операторов</b> (unary), которые работают с одним операндом. Например <code>-</code> может быть унарным оператором.</p>
<p>Большинство операторов бинарные (binary) и работают с двумя операндами. Например <code>*</code> всегда требует два операнда для работы,
но в большинстве случаев <code>-</code> также работает как бинарный.</p>
<p>Есть всего один <b>тернарный оператор</b>, который имеет 3 операнда. Он называется <b>условный оператор</b>, но так как есть всего один такой,
большинство людей называют его <b>тернарный оператор</b>.</p>
<h2 class="title is-4">Условный оператор в Ruby</h2>
<p>В целом это выглядит так:</p>
<pre><code>CONDITION ? EVALUATE_IF_CONDITION_WAS_TRUE : EVALUATE_IF_CONDITION_WAS_FALSE
</code></pre>
<p>Выражение проверяет <code>CONDITION</code> (условие). Если оно <code>true</code>(истина), тогда работает код между <code>?</code> и <code>:</code>, и возвращается результат.
Если <code>CONDITION</code> (условие) ложно, тогда средняя часть пропускается и выполняется 3я часть, возвращая результат.</p>
<h2 class="title is-4">Пример с puts</h2>
<p>В этом примере возвращаемое значение условного оператора передается в <code>puts</code></p>
<pre><code>filename = ARGV.shift
puts filename ? filename : 'No file given'
</code></pre>
<h2 class="title is-4">Пример с меньшим значением</h2>
<p>В этом примере мы проверяем, какое из двух случайных значений меньше, и возвращаем его:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/smaller_ternary.rb">examples/ruby/smaller_ternary.rb</a></strong></p>
<pre><code class="language-ruby">
x = rand()
y = rand()
puts x
puts y
 
smaller = x &lt; y ? x : y;
puts smaller

</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Упражнение: Сравнение переводов Wikipedia</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-03-27T18:12:01Z</updated>
    <pubDate>2016-03-27T18:12:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/compare-wikipedia-translations" />
    <id>https://rust.code-maven.com/compare-wikipedia-translations</id>
    <content type="html"><![CDATA[<p>Выбрав статью на <a href="https://en.wikipedia.org/">English Wikipedia</a>, например про <a href="https://en.wikipedia.org/wiki/Perl">Perl</a>,
<a href="https://en.wikipedia.org/wiki/Python_%28programming_language%29">Python</a>,
<a href="https://en.wikipedia.org/wiki/Ruby_%28programming_language%29">Ruby</a>,
<a href="https://en.wikipedia.org/wiki/PHP">PHP</a>, или <a href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a>,
сделайте программу, которая получит размер каждой переведенной версии этой статьи на
все языки на Википедии.</p>
<p>В зависимости от степени исследования, которое вы захотите провести, вы можете приступить сразу или посмотреть <b>подсказки</b>.</p>
<h2 class="title is-4">Подсказки</h2>
<p>Wikipedia предоставляет <a href="https://www.mediawiki.org/wiki/API:Main_page">API для получения содержимого страницы</a> в некотором формает.
Так же есть более подробная документация об <a href="https://www.mediawiki.org/wiki/Wikibase/API">API</a>,
включая информацию о <a href="https://www.mediawiki.org/wiki/API:Properties">API::Properties</a>.</p>
<p>Ссылки на языки есть тут - <a href="https://www.wikidata.org/">Wikidata</a>.</p>
<h2 class="title is-4">Подсказки</h2>
<p>Этот URL вернет содержимое страницы 'Perl' с английской версии Википедии в формате JSON:</p>
<pre><code>https://en.wikipedia.org/w/api.php?action=query&amp;prop=revisions&amp;rvprop=content&amp;format=json&amp;titles=Perl
</code></pre>
<p>Этот адрес вернет список всех переводов для страницы с Q-id = Q42:</p>
<pre><code>https://www.wikidata.org/w/api.php?action=wbgetentities&amp;format=json&amp;props=sitelinks&amp;ids=Q42
</code></pre>
<p>Имея title (в нашем случае PHP), следующий URL вернет Q-id страницы:</p>
<pre><code>https://en.wikipedia.org/w/api.php?action=query&amp;prop=pageprops&amp;format=json&amp;titles=PHP
</code></pre>
<h2 class="title is-4">Подсказки</h2>
<p>Похоже, что есть 4 типа ссылок на языки, возвращаемые от <a href="https://www.wikidata.org/">Wikidata</a>:</p>
<p>Простые ссылки на Википедии, которые заканчивается словами <code>itwiki</code>, <code>newwiki</code>, ил <code>pdcwiki</code>.
Там может быть 2 или более символа. Реальный адрес URL это то же самое, но без последних 4 символов.</p>
<p>Ссылки с подчеркиванием типа <code>zh_yuewiki</code>, <code>bat_smgwiki</code>, или <code>zh_min_nanwiki</code>
примерно такие же, но нужно заменить <code>_</code> на <code>-</code>.</p>
<p>Ссылки <a href="https://en.wikiquote.org/">Wikiquote</a>. Например <code>enwikiquote</code>, которая значит <a href="https://en.wikiquote.org/">https://en.wikiquote.org/</a>.</p>
<p>Ссылки <a href="https://fr.wikibooks.org/">Wikibook</a>, типа <code>frwikibook</code> которые значат <a href="https://fr.wikibooks.org/">https://fr.wikibooks.org/</a>.</p>
<h2 class="title is-4">Инструменты</h2>
<h2 class="title is-4">Решение</h2>
<p><a href="https://github.com/szabgab/wikipedia-stats">wikipedia stats in GitHub</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Функция vs Генератор в Python</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-03-19T10:57:01Z</updated>
    <pubDate>2016-03-19T10:57:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/function-vs-generator-in-python" />
    <id>https://rust.code-maven.com/function-vs-generator-in-python</id>
    <content type="html"><![CDATA[<p>Мы посмотрели как сделать <a href="/function-or-callback-in-python">простую функцию и использовать колбек</a>, чтобы сделать функцию более универсальной.
Мы так же посмотрели как <a href="/callback-or-iterator-in-python">создать итератор</a> для упрощения кода.
В этот раз мы собираемся посмотреть как конвертация функции в генератор (после изучения, как это работает)
становится наиболее очевидным решением.</p>
<h2 class="title is-4">Простая функция</h2>
<p>В качестве напоминания давайте посмотрим исходную функцию Fibonacci, с которой мы начали,
когда мы должны были жестко описать условие, или в более гибком случае использовать колбек.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_function.py">examples/python/fibonacci_function.py</a></strong></p>
<pre><code class="language-python">#!/usr/bin/env python
from __future__ import print_function

def fibonacci():
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

if __name__ == '__main__':
    fibonacci()

</code></pre>
<h2 class="title is-4">Генератор</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_generator.py">examples/python/fibonacci_generator.py</a></strong></p>
<pre><code class="language-python">#!/usr/bin/env python
from __future__ import print_function

def fibonacci():
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = (values[-1], values[-1] + values[-2])
        yield values[-1]

for f in fibonacci():
    if f % 17 == 0:
        print(f)
        break
    if f &gt; 10000:
        break

</code></pre>
<p>Этот пример с генератором почти такой же, как и простая функция, и мы можем его
использовать точно также, как использовали <a href="/callback-or-iterator-in-python">итератор</a>.</p>
<p>Единственное добавление в реализации функции <code>fibonacci</code>
это вызов <code>yield</code> каждый раз, когда вычислено новое значение.
Этот вызов приостанавливает выполнение функции <code>fibonacci</code>
и возвращает управление вызывающей сущности вместе со значением, переданным в оператор <code>yield</code>.</p>
<p>В первой итерации цикла <code>for</code> функция <code>fibonacci</code> начнет работу
со своего первого оператора создания пустого массива значений <code>values</code>.</p>
<p>Когда она встретит оператор <code>yield</code>, она вернет значение <code>values[-1]</code>, которое
будет присвоено переменной <code>f</code> в цикле <code>for</code>, дальше цикл <code>for</code> продолжит выполнение.
Здесь мы описываем наше условие по прерыванию цикла.</p>
<p>Если мы не прервем выполнение на первой итерации, тогда в последующих итерациях
цикла <code>for</code> функция <code>fibonacci</code> продолжит выполнение точно с того места,
где она была приостановлена. Имеется в виду, что содержимое <code>values</code>
будет таким же, каким мы его и оставили, а первый оператор, который будет выполнен после вызова <code>yield</code>,
это проверка на <code>True</code> в операторе <code>while(True):</code>.</p>
<p>Таким образом функция <code>fibonacci</code> ведет себя точно также, как и <a href="/callback-or-iterator-in-python">итератор Fibonacci</a>,
делая наш код проще.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Простая функция или функция обратного вызова (колбек) - пример для Python</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-03-19T09:26:01Z</updated>
    <pubDate>2016-03-19T09:26:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/function-or-callback-in-python" />
    <id>https://rust.code-maven.com/function-or-callback-in-python</id>
    <content type="html"><![CDATA[<p>Что если для ответа на вопрос вам нужно обработать последовательность значений,
которую вы не можете хранить в памяти как список?</p>
<p>Например, когда вы читаете огромный файл. Или когда вы вычисляете следующее значение
на основании предыдущих значений и какой-то информации, появляющейся в процессе вычисления.
Или случайные последовательности. Или бесконечные последовательности, когда вы не знаете,
как далеко нужно зайти, чтобы найти ответ.</p>
<p>В этой статье мы посмотрим два решения:</p>
<ul>
<li>Простая функция.</li>
<li>Функция с колбеком (функцией обратного вызова).</li>
</ul>
<p>Затем можете посмотреть решение с помощью <a href="/callback-or-iterator-in-python">итераторов</a>
и другое решение с помощью <a href="/function-vs-generator-in-python">генераторов</a>.</p>
<p>Чтобы избежать объяснения сложного алгоритма, мы будем использовать
хорошо известную последовательность Фибоначчи, а нашим вопрос, на который нужно будет ответить,
будет &quot;Какое первое число последовательности делится на 17.&quot;</p>
<p>Гораздо более сложный случай типа такого, это если вам нужно обойти цепочки ДНК в базе данных,
постоянно улучшая свой запрос для выбора следующей цепочки, пока не будет найдено то, что удовлетворяет вашим требованиям.</p>
<p>В случае последовательности Фибоначчи мы можем заранее посчитать несколько элементов,
но в общем случае это не поможет.</p>
<p>Даже в случае последовательности Фибоначчи ни одна заранее посчитанная последовательность
не сможет дать ответ на любой произвольный вопрос, и в случае ДНК-цепочек совершенно понятно, что у нас даже не хватит
памяти для размещения заранее подготовленного списка.</p>
<h2 class="title is-4">Простая функция Fibonacci</h2>
<p>Давайте посмотрим простую реализацию последовательности Фибоначчи, а затем подправим решение.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_function.py">examples/python/fibonacci_function.py</a></strong></p>
<pre><code class="language-python">#!/usr/bin/env python
from __future__ import print_function

def fibonacci():
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

if __name__ == '__main__':
    fibonacci()

</code></pre>
<p>Нет ничего необычного в этой реализации, но я не советую запускать этот код,
так как он ничего не выводит и не останавливается.
Так что если вы его запустите, то будет выглядеть, как будто он завис.</p>
<p>Вы можете добавить:</p>
<pre><code class="language-python">print(values[-1])
</code></pre>
<p>в цикл, чтобы видеть происходящее, а также можете добавить что-то вроде этого:</p>
<pre><code class="language-python">if (values[-1] &gt; 100):
    break;
</code></pre>
<p>для ограничения последовательности.</p>
<h2 class="title is-4">Наш &quot;вопрос&quot; - деление на 17</h2>
<p>Напомню, что наша задача - &quot;изучение последовательности Фибоначчи&quot;,
и первый вопрос, на который нужно ответить, это &quot;Какой первый элемент последовательности
Фибоначчи делится на 17?&quot;</p>
<p>Так что мы улучшим функцию, чтобы она возвращала первый элемент, который может делится на 17:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_function_mod_17.py">examples/python/fibonacci_function_mod_17.py</a></strong></p>
<pre><code class="language-python">#!/usr/bin/env python
from __future__ import print_function

def fibonacci():
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

        if values[-1] % 17 == 0:
            return(values[-1])

if __name__ == '__main__':
    res = fibonacci()
    print(res)

</code></pre>
<p>Мы просто добавили следующий код, который проверяет, может ли
текущее значение последовательности делится без остатка на 17:</p>
<pre><code class="language-python">if values[-1] % 17 == 0:
    return(values[-1])
```оо

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

Запущенная программа остановится на 34.

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

## Меры безопасности - ограничение цикла

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

```python
if values[-1] &gt; 10000:
    return
</code></pre>
<p>Конечно, мы можем использовать значительно большее число для этого, или можем основываться на
количестве элементов для проверки.</p>
<p>Вот полный код:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_function_with_safety.py">examples/python/fibonacci_function_with_safety.py</a></strong></p>
<pre><code class="language-python">from __future__ import print_function

def fibonacci():
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

        if values[-1] % 17 == 0:
            return(values[-1])

        if values[-1] &gt; 10000:
            return

if __name__ == '__main__':
    res = fibonacci()
    if (res != None):
        print(res)

</code></pre>
<h2 class="title is-4">В чем проблема?</h2>
<p>У нас есть функция, которая проверяет какое-то особое условие и возвращает первое значение,
подходящее под условие. Если завтра мне нужно будет ответить на вопрос
&quot;Какое первое число Фибоначчи делится на 19?&quot;,
или
&quot;Какое первое число Фибоначчи, которое является квадратом другого числа?&quot;,
я могу просто скопировать код и изменить условие.</p>
<p>Звучит просто, но это значит, что у нас будет множество копий кода, реализующего функцию fibonacci.
Что если алгоритм будет намного сложнее? Мы все еще хотим копировать тот код снова и снова?</p>
<p>Что если мы найдем ошибку в нашем алгоритме (или просто способ реализации лучше)
после 20 копирований для ответов на разные вопросы?</p>
<p>Это явно не очень хороший путь.</p>
<p>Давайте попробуем другой подход.
Изменим функцию Fibonacci так, чтобы она принимала функцию как параметр и вызывала эту функцию
для каждого элемента последовательности Фибоначчи.</p>
<h2 class="title is-4">Функция обратного вызова (колбек)</h2>
<p>Функция <code>fibonacci</code> теперь выглядит вот так:
она принимает параметр <code>cb</code>, который должен быть функцией,
как только мы вычислили новый элемент последовательности,
вызываем эту колбек-функцию, передавая ей последний элемент: <code>cb(values[-1])</code>.</p>
<p>Ожидается, что возвращаемый элемент будет списком или кортежем (tuple), в котором
первый элемент будет иметь значение <code>True</code> или <code>False</code> и показывать,
нашли мы ответ на вопрос (True) или еще нет (False).
Если значение будет True, мы возвращает второй элемент в качестве результата.</p>
<pre><code class="language-python">def fibonacci(cb):
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

        r = cb(values[-1])
        if (r[0]):
            return(r[1])
</code></pre>
<p>Таким образом, колбек должен принимать одиночное значение и возвращать
кортеж (tuple), в котором первый элемент будет True/False, а второй - нужное нам значение последовательности.</p>
<p>Функция обратного вызова выглядит вот так:
Она принимает значение <code>v</code> - текущее значение последовательности.
И возвращает <code>True</code> и найденное значение, если оно может делится на 17.</p>
<p>Она возвращает <code>True</code> и <code>None</code>, если достигнут предел, который мы установили.
Значение True будет указывать функции fibonacci, что поиск завершен,
а None - что ответа не найдено.</p>
<p>Наконец, мы возвращаем кортеж с одним значением <code>False</code>, указывающим функции
fibonacci, что искомое значение еще не нашлось и нужно проверить следующее.</p>
<pre><code class="language-python">def check_17(v):
    if v % 17 == 0:
        return (True, v)

    if v &gt; 10000:
        return (True, None)

    return (False,)
</code></pre>
<p>Полная реализация выглядит вот так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_function_callback.py">examples/python/fibonacci_function_callback.py</a></strong></p>
<pre><code class="language-python">#!/usr/bin/env python
from __future__ import print_function

def fibonacci(cb):
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

        r = cb(values[-1])
        if (r[0]):
            return(r[1])

def check_17(v):
    if v % 17 == 0:
        return (True, v)

    if v &gt; 10000:
        return (True, None)

    return (False,)


if __name__ == '__main__':
    res = fibonacci(check_17)
    if (res != None):
        print(res)

</code></pre>
<p>Решение значительно лучше предыдущего. Теперь нам не нужно менять
функцию fibonacci, в зависимости от условий.
Мы можем переместить функцию fibonacci в модуль, импортировать ее и использовать как внешний ресурс.
Если нужно будет ее поправить, то это нужно будет делать в одном месте,
и все потребители этой функции будут в выигрыше.</p>
<p>Даже еще лучше, функция, которую мы создали как колбек, может быть переиспользована
для передачи в другие функции-генераторы последовательностей.</p>
<h2 class="title is-4">Итераторы и генераторы</h2>
<p>Есть два других решения этой проблемы.
Одно это создание <a href="/callback-or-iterator-in-python">итератора</a>,
а второе - создание <a href="/function-vs-generator-in-python">генератора</a>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Функция обратного вызова (callback) или итератор в Python</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-03-19T08:56:01Z</updated>
    <pubDate>2016-03-19T08:56:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/callback-or-iterator-in-python" />
    <id>https://rust.code-maven.com/callback-or-iterator-in-python</id>
    <content type="html"><![CDATA[<p>Раньше мы видели, как <a href="/function-or-callback-in-python">функции обратного вызова (колбеки) могут быть лучше простых функций</a>,
но есть и другие варианты. Мы можем создать, вероятно, неограниченный итератор, который будет
обходить элементы нашей последовательности, делая код еще более понятным, чем даже решение с колбеками.</p>
<h2 class="title is-4">Решение с колбеком</h2>
<p>Просто для напоминания - вот наше решение с колбеком. У нас есть функция fibonacci, которая проходит элементы последовательности,
и для каждого элемента вызывает переданную функцию <code>check_17</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_function_callback.py">examples/python/fibonacci_function_callback.py</a></strong></p>
<pre><code class="language-python">#!/usr/bin/env python
from __future__ import print_function

def fibonacci(cb):
    values = []
    while(True):
        if len(values) &lt; 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

        r = cb(values[-1])
        if (r[0]):
            return(r[1])

def check_17(v):
    if v % 17 == 0:
        return (True, v)

    if v &gt; 10000:
        return (True, None)

    return (False,)


if __name__ == '__main__':
    res = fibonacci(check_17)
    if (res != None):
        print(res)

</code></pre>
<p>Тот факт, что мы должны иметь возможность передать функции <code>fibonacci</code>
сигнал, когда остановиться, делает наш код несколько сложнее, чем мы надеялись.
Мы должны возвращать массив, в котором первый элемент выполняет роль индикатора (True/False).</p>
<h2 class="title is-4">Создание Fibonacci-итератора</h2>
<p>Давайте сделаем все наоборот и позволим пользователю вернуть контроль над циклом.
Мы создаем класс <code>Fibonacci</code>, который будет итерабельным вследствие добавления
метода <code>__iter__</code>, который просто возвращает объект,
и метода <code>next</code> (В Python 3, думаю, это будет <code>__next__</code>),
который возвращает следующий элемент.</p>
<p>Внутри объект содержит текущее состояние итерации. В нашем случае это значит,
что он должен содержать последние два элемента последовательности.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/python/fibonacci_iterator.py">examples/python/fibonacci_iterator.py</a></strong></p>
<pre><code class="language-python">#!/usr/bin/env python
from __future__ import print_function

class Fibonacci(object):
    def __init__(self):
        self.values = []

    def __iter__(self):
        return self

    def next(self):
        if len(self.values) &lt; 2:
            self.values.append(1)
        else:
            self.values = [self.values[-1], self.values[-1] + self.values[-2]]
        return self.values[-1]

for f in Fibonacci():
    if f % 17 == 0:
        print(f)
        break
    if f &gt; 10000:
        break

</code></pre>
<p>Вызов <code>fib = Fibonacci()</code> создаст объект итератора, который мы можем использовать
в конструкции <code>for in</code> для перебора элементов.
Поскольку это неограниченный итератор, то есть, он не имеет конца,
мы должны быть уверены, что есть какой-то код внутри цикла <code>for</code>,
который его как-то остановит.</p>
<p>Решение выглядит проще, чем вариант <a href="/function-or-callback-in-python">с колбеками</a>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Простые типы данных в Ruby (Scalar, Array, Hash)</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-28T19:39:01Z</updated>
    <pubDate>2016-02-28T19:39:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/basic-data-structures-in-ruby" />
    <id>https://rust.code-maven.com/basic-data-structures-in-ruby</id>
    <content type="html"><![CDATA[<p>В Ruby есть три простых типа данных.</p>
<p>Scalars (скаляр) может содержать одиночное значение: число или строку.</p>
<p>Arrays (массив) это упорядоченный список скаляров (scalars).</p>
<p>Hashes это пары ключ-значение, где ключи уникальные строки, а значения это скаляры.</p>
<p>Метод <code>class</code> может сказать нам, какой тип значения содержится в переменной:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/data_structures.rb">examples/ruby/data_structures.rb</a></strong></p>
<pre><code class="language-ruby">
x = 43
puts x.class      # Fixnum

q = 3.14
puts q.class      # Float

z = &quot;abc&quot;
puts z.class      # String

colors = [ 'Blue', 'Green', 'Yellow' ]
puts colors.class # Array

person = { 'fname' =&gt; 'Foo', 'lname' =&gt; 'Bar' }
puts person.class  # Hash



</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Bootstrap Skeleton</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-28T19:35:01Z</updated>
    <pubDate>2016-02-28T19:35:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/bootstrap-skeleton" />
    <id>https://rust.code-maven.com/bootstrap-skeleton</id>
    <content type="html"><![CDATA[<p><a href="http://getbootstrap.com/">Bootstrap</a> это HTML-фреймворк, который позволяет легко делать красивые, mobile-friendly веб-сайты.
Вы можете начать с использования этого каркаса или можете скачать соответствующие файлы и использовать их с вашего собственного сервера.</p>
<p>MISSING</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>TODO в AngularJS</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-28T19:02:01Z</updated>
    <pubDate>2016-02-28T19:02:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/todo-in-angularjs" />
    <id>https://rust.code-maven.com/todo-in-angularjs</id>
    <content type="html"><![CDATA[<p>После примеров про <a href="/getting-started-with-angularjs">Hello world</a>, <a href="/angularjs-first-binding">Echo</a> и <a href="/calculator-in-angularjs">простой калькулятор</a>,
создание списка TODO - это один из ритуальных пассажей для вхождения в мир программирования на любом языке в любом окружении.
Давайте посмотрим, как реализовать TODO на AngularJS.</p>
<h2 class="title is-4">Простой список TODO</h2>
<p>После загрузки <code>angular.min.js</code> мы создаем модуль AngularJS с именем <code>todoApp</code>
и контролллер <code>todoController</code>. Внутри контроллера мы создаем пустой массив <code>tasks</code>, где будет содержаться список todo.
Мы сделаем его атрибутом текущего <code>$scope</code>, чтобы иметь возможность доступа из HTML.</p>
<p>Мы также объявляем функцию <code>add</code> (тоже атрибут <code>$scope</code>),
которая получает значение <code>title</code> (Как мы позже увидим, это будет имя поля для ввода),
и добавляем его в список задач, используя <code>push</code>. Вот и весь JavaScript, который нам нужен для простого списка TODO.</p>
<p>В части HTML у нас есть элемент <code>div</code>, который определяет область AngularJS-приложения <code>ng-app</code> и AngularJS-контроллера <code>ng-controller</code>.</p>
<p>Внутри контролллера в HTML у нас есть две части. Первая часть это поле для ввода <code>input</code>,
связанное с атрибутом <code>$scope.title</code> с помощью <code>ng-model</code>, и кнопка, использующая
<code>ng-click</code> для вызова метода <code>$scope.add</code> при нажатии.</p>
<p>Вторая часть использует директиву <code>ng-repeat</code> для прохода по элементам массива <code>$scope.tasks</code> и показа их в виде списка.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/todo1.html">examples/angular/todo1.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
angular.module('todoApp', [])
    .controller('todoController', function($scope){
        $scope.tasks = [];
        $scope.add = function() {
            $scope.tasks.push($scope.title);
        }
    })
&lt;/script&gt;
&lt;div ng-app=&quot;todoApp&quot; ng-controller=&quot;todoController&quot;&gt;
    &lt;input ng-model=&quot;title&quot;&gt;&lt;button ng-click=&quot;add()&quot;&gt;Add&lt;/button&gt;
    &lt;ul&gt;
        &lt;li ng-repeat=&quot;t in tasks&quot;&gt;{{ t }}&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/todo1.html">view</a></p>
<h2 class="title is-4">Активация поля ввода нажатием ENTER</h2>
<p>Несколько обременительно нажимать кнопку для добавления каждого элемента.
Будет гораздо лучше, если мы сможем просто нажимать ENTER.
Чтобы это сделать, нам нужно обернуть элемент <code>input</code> в <code>form</code> и на форму добавить директиву <code>ng-submit</code>,
которая будет вызывать функцию <code>$scope.add</code>. А также для избежания повторного вызова функции <code>$scope.add</code>.</p>
<pre><code class="language-html">  &lt;form ng-submit=&quot;add()&quot;&gt;
  &lt;input ng-model=&quot;title&quot;&gt;&lt;button&gt;Add&lt;/button&gt;
  &lt;/form&gt;
</code></pre>
<h2 class="title is-4">Дублирующиеся значения в ng-repeat</h2>
<p>Если вы попробовали пример выше, то могли заметить, что добавление того же элемента дважды приводит к падению приложения.
Причина в том, что директива <code>ng-repeat</code> расчитана на уникальные значения в массиве.
Я не уверен, что наличие одинаковых значений в списке TODO это хорошо, но сейчас я бы хотел позволить
пользователю добавлять то же самое значение дважды.
Для этого мы можем указать <code>ng-repeat</code> использовать <code>$index</code> массива для перебора значений:</p>
<pre><code class="language-html">&lt;li ng-repeat=&quot;t in tasks track by $index&quot;&gt;{{ t }}&lt;/li&gt;
</code></pre>
<h2 class="title is-4">Удаление элемента из списка TODO</h2>
<p>Хотя для большинства из нас реальность такова, что TODO список всегда увеличивается, иногда удача нам сопутствует и дела выполняются. (Или они просто отменяются.)
Мы бы хотели иметь способ удалить элемент. Для этого мы собираемся добавить кнопку в конце каждого пункта,
которая будет удалять конкретный элемент из списка дел.</p>
<p>Добавить кнопку это просто:</p>
<pre><code class="language-html">&lt;button ng-click=&quot;delete()&quot;&gt;x&lt;/button&gt;
</code></pre>
<p>Соответствующая кнопке функция <code>delete</code> заставила меня почесать голову, но в итоге я справился:</p>
<pre><code class="language-javascript">$scope.delete = function() {
    $scope.tasks.splice(this.$index, 1);
}
</code></pre>
<p>Когда вызывается функция <code>delete</code>, <code>this</code> содержит атрибут <code>$index</code>, который похоже указывает на индекс текущего элемента.
Мы можем использовать это для нахождения нужного элемента в массива <code>tasks</code>. Функция JavaScript `splice</a> удалит один элемент из массива,
а список сразу же обновится на HTML-странице.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/todo2.html">examples/angular/todo2.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
angular.module('todoApp', [])
    .controller('todoController', function($scope) {
        $scope.tasks = [];
        $scope.add = function() {
            $scope.tasks.push($scope.title);
        }
        $scope.delete = function() {
            $scope.tasks.splice(this.$index, 1);
        }
    })
&lt;/script&gt;
&lt;div ng-app=&quot;todoApp&quot; ng-controller=&quot;todoController&quot;&gt;
    &lt;form ng-submit=&quot;add()&quot;&gt;
    &lt;input ng-model=&quot;title&quot;&gt;&lt;button&gt;Add&lt;/button&gt;
    &lt;/form&gt;
    &lt;ul&gt;
        &lt;li ng-repeat=&quot;t in tasks track by $index&quot;&gt;{{ t }} &lt;button ng-click=&quot;delete()&quot;&gt;x&lt;/button&gt;&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/todo2.html">view</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Учебник AngularJS</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-28T18:54:01Z</updated>
    <pubDate>2016-02-28T18:54:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/angularjs" />
    <id>https://rust.code-maven.com/angularjs</id>
    <content type="html"><![CDATA[<p><a href="https://angularjs.org/">AngularJS</a> это JavaScript-фреймворк, который усиливает HTML.</p>
<p>Здесь вы найдете несколько неспешно создаваемых примеров с использованием AngularJS, которые составят руководство.</p>
<p>Другие введения вы можете найти в <a href="http://www.angularjsbook.com/">AngularJS Book</a> от Chris Smith
или <a href="https://www.ng-book.com/">ng-book</a> от Ari Lerner. Как только вы пройдете первые шаги, то будет полезно почитать
<a href="https://docs.angularjs.org/">AngularJS API and documentation</a>.</p>
<ol>
  <li>[Getting Started with AngularJS (expressions)](/getting-started-with-angularjs)</li>
  <li>[AngularJS: First binding](/angularjs-first-binding)</li>
  <li>[Hello World with AngularJS module and controller](/hello-world-with-angular-controller)</li>
  <li>[Add numbers with AngularJS](/add-numbers-with-angular)</li>
  <li>[Simple in-memory counter with AngularJS](/simple-in-memory-counter-with-angularjs)</li>
  <li>[Automatic counter using AngularJS](/automatic-counter-using-angularjs)</li>
  <li>[A calculator in AngularJS](/calculator-in-angularjs)</li>
  <li>[TODO in AngularJS](/todo-in-angularjs) Submit input box on pressing ENTER. ng-repeate and handling duplicate values in ng-repeate.</li>
</ol>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>AngularJS UI с Bootstrap</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-28T18:53:01Z</updated>
    <pubDate>2016-02-28T18:53:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/angular-ui-bootstrap-skeleton" />
    <id>https://rust.code-maven.com/angular-ui-bootstrap-skeleton</id>
    <content type="html"><![CDATA[<p>Чтобы запустить <a href="https://angularjs.org/">AngularJS</a> вместе с <a href="http://getbootstrap.com/">Bootstrap</a>, вы можете
использовать проект <a href="https://angular-ui.github.io/bootstrap/">Angular UI Bootstrap</a>.</p>
<p>MISSING</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>AngularJS: фильтрация таблиц с ng-repeat</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-28T18:18:25Z</updated>
    <pubDate>2016-02-28T18:18:25Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/angular-filter-table-created-with-ng-repeat" />
    <id>https://rust.code-maven.com/angular-filter-table-created-with-ng-repeat</id>
    <content type="html"><![CDATA[<p>Создание таблицы с помощью <code>ng-repeat</code> весьма простое. Добавление поискового блока для фильтрации результатов тоже простое, но только
если вы хотите использовать простой поиск по тексту. Немного сложнее, если вы хотите искать по значениям <b>меньше, чем</b> введенное пользователем.</p>
<p>В нашем примере мы будем использовать <a href="https://en.wikipedia.org/wiki/Solar_System">планеты Солнечной Системы</a>.
У нас есть имя, средняя дистанция от Солнца в единицах &quot;дистанция от Земли до Солнца&quot; и масса относительно массы Земли.
Таким образом, оба значения равны 1 для Земли. (Земля это не центр системы, если что :).</p>
<p>В первом примере мы сделали таблицу из данных, прописанных в коде, и добавили текстовый фильтр на все поля:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/angular_table_filter_1.html">examples/angular/angular_table_filter_1.html</a></strong></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;utf-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot;
     content=&quot;width=device-width, initial-scale=1, user-scalable=yes&quot;&gt;
  &lt;title&gt;Table Filter&lt;/title&gt;
  &lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js&quot;&gt;&lt;/script&gt;
  &lt;script&gt;
  angular.module('TableFilterApp', [])
    .controller('TableFilterController', function($scope) {
      $scope.planets = [
        {
          name : 'Mercury',
          distance : 0.4,
          mass : 0.055
        },
        {
          name : 'Venus',
          distance : 0.7,
          mass : 0.815
        },
        {
          name : 'Earth',
          distance: 1,
          mass : 1
        },
        {
          name : 'Mars',
          distance : 1.5,
          mass : 0.107
        },
        {
          name : 'Ceres',
          distance : 2.77,
          mass :     0.00015
        },
        {
          name : 'Jupiter',
          distance : 5.2,
          mass :   318
        },
        {
          name : 'Saturn',
          distance : 9.5,
          mass :    95
        },
        {
          name : 'Uranus',
          distance : 19.6,
          mass :   14
        },
        {
          name : 'Neptune',
          distance : 30,
          mass : 17
        },
        {
          name : 'Pluto',
          distance : 39,
          mass : 0.00218
        },
        {
          name : 'Charon',
          distance : 39,
          mass :  0.000254
        }
      ];
    
    });
  &lt;/script&gt;

&lt;/head&gt;
&lt;body ng-app=&quot;TableFilterApp&quot; ng-controller=&quot;TableFilterController&quot;&gt;

&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Average Distance&lt;/th&gt;&lt;th&gt;Mass&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;input ng-model=&quot;f.name&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;f.distance&quot;&gt;&lt;/td&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;f.mass&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr ng-repeat=&quot;p in planets | filter:f&quot;&gt;&lt;td&gt;{{p.name}}&lt;/td&gt;&lt;td&gt;{{p.distance}}&lt;/td&gt;&lt;td&gt;{{p.mass}}&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;



</code></pre>
<p><a href="examples/angular/angular_table_filter_1.html">view</a></p>
<p>Интересная часть кода кроется в этих двух строках:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/angular_table_filter_1.js">examples/angular/angular_table_filter_1.js</a></strong></p>
<pre><code class="language-js">&lt;tr&gt;&lt;td&gt;&lt;input ng-model=&quot;f.name&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;f.distance&quot;&gt;&lt;/td&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;f.mass&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr ng-repeat=&quot;p in planets | filter:f&quot;&gt;&lt;td&gt;{{p.name}}&lt;/td&gt;&lt;td&gt;{{p.distance}}&lt;/td&gt;&lt;td&gt;{{p.mass}}&lt;/td&gt;&lt;/tr&gt;


</code></pre>
<p>Вторая строка это то, что строит таблицу. Это обычная <code>ng-repeat</code> строка, но результаты фильтруются
на основе содержимого объекта <code>f</code>. Атрибуты этого объекта связаны в полем ввода в первой строке.
Каждый атрибут будет фильтроваться в соответствии с полем исходного массива.</p>
<p>Хотя в нашем случае фильтр имеет смысл только для первой колонки.
Так как это простой текст-фильтр, то как-то бессмысленно искать все планеты, у которых значение дистанции содержит 7.
В других таблицах, вероятно, это интереснее.</p>
<h2 class="title is-4">Поиск значений больше или меньше</h2>
<p>Гораздо интереснее найти все планеты, дистанция до которых меньше 2.
Или где масса меньше 20.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/angular_table_filter_2.html">examples/angular/angular_table_filter_2.html</a></strong></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;utf-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot;
     content=&quot;width=device-width, initial-scale=1, user-scalable=yes&quot;&gt;
  &lt;title&gt;Table Filter&lt;/title&gt;
  &lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js&quot;&gt;&lt;/script&gt;
  &lt;script&gt;
  angular.module('TableFilterApp', [])
    .controller('TableFilterController', function($scope) {
      $scope.planets = [
        {
          name : 'Mercury',
          distance : 0.4,
          mass : 0.055
        },
        {
          name : 'Venus',
          distance : 0.7,
          mass : 0.815
        },
        {
          name : 'Earth',
          distance: 1,
          mass : 1
        },
        {
          name : 'Mars',
          distance : 1.5,
          mass : 0.107
        },
        {
          name : 'Ceres',
          distance : 2.77,
          mass :     0.00015
        },
        {
          name : 'Jupiter',
          distance : 5.2,
          mass :   318
        },
        {
          name : 'Saturn',
          distance : 9.5,
          mass :    95
        },
        {
          name : 'Uranus',
          distance : 19.6,
          mass :   14
        },
        {
          name : 'Neptune',
          distance : 30,
          mass : 17
        },
        {
          name : 'Pluto',
          distance : 39,
          mass : 0.00218
        },
        {
          name : 'Charon',
          distance : 39,
          mass :  0.000254
        }
      ];
      $scope.f = {};

      $scope.filter_by = function(field) {
        console.log(field);
        console.log($scope.g[field]);
        if ($scope.g[field] === '') {
             delete $scope.f['__' + field];
             return;
        }
        $scope.f['__' + field] = true;
        $scope.planets.forEach(function(v) { v['__' + field] = v[field] &lt; $scope.g[field]; })
      }
    
    });
  &lt;/script&gt;

&lt;/head&gt;
&lt;body ng-app=&quot;TableFilterApp&quot; ng-controller=&quot;TableFilterController&quot;&gt;

&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Average Distance&lt;/th&gt;&lt;th&gt;Mass&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;input ng-model=&quot;f.name&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;g.distance&quot; ng-change=&quot;filter_by('distance')&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;g.mass&quot; ng-change=&quot;filter_by('mass')&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr ng-repeat=&quot;p in planets | filter:f&quot;&gt;&lt;td&gt;{{p.name}}&lt;/td&gt;&lt;td&gt;{{p.distance}}&lt;/td&gt;&lt;td&gt;{{p.mass}}&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;



</code></pre>
<p><a href="examples/angular/angular_table_filter_2.html">view</a></p>
<p>Это сильно сложнее. Я пока не смог найти решения лучше, так что сейчас каждый раз, когда пользователь вводит значение либо в поле &quot;distance&quot;,
либо в поле &quot;mass&quot;, код будет проходить по всем значениям массива и добавлять дополнительный ключ к каждому объекту со значениями <code>true</code>,
если объект подходит под условие, или <code>false</code>, если не подходит. Дополнительный ключ сделан с помощью добавления двух подчеркиваний '__' перед именем исходного ключа.
Предполагается, что мы вряд ли столкнемся с данными, где будут такие ключи.</p>
<p>HTML-код поменялся незначительно. Вместо привязки поля ввода к атрибуту объекта фильтра, мы привяжем его к другому объекту (с именем g), а также
добавим вызов функции, используя <code>ng-change</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/angular_table_filter_2b.js">examples/angular/angular_table_filter_2b.js</a></strong></p>
<pre><code class="language-js">&lt;tr&gt;&lt;td&gt;&lt;input ng-model=&quot;f.name&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;g.distance&quot; ng-change=&quot;filter_by('distance')&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;input ng-model=&quot;g.mass&quot; ng-change=&quot;filter_by('mass')&quot;&gt;&lt;/td&gt;&lt;/tr&gt;


</code></pre>
<p>Когда пользователь поменяет значение в одном из двух полей, Angular вызовет функцию <code>filter_by</code>. Для начала мы проверим, не пусто ли поле ввода.
Если пусто, то удалим все наши созданные ключи.</p>
<p>Если в поле будет введено значение, мы пройдемся по всем объектам в массиве <code>planets</code> и добавим соответствующий атрибут со значением <code>true</code>
или <code>false</code>. Реальная фильтрация уже будет произведена AngularJS.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/angular_table_filter_2.js">examples/angular/angular_table_filter_2.js</a></strong></p>
<pre><code class="language-js">      $scope.f = {};

      $scope.filter_by = function(field) {
        if ($scope.g[field] === '') {
             delete $scope.f['__' + field];
             return;
        }
        $scope.f['__' + field] = true;
        $scope.planets.forEach(function(v) { v['__' + field] = v[field] &lt; $scope.g[field]; })
      }
 

</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Открываем файл и читаем содержимое в Ruby</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-27T21:07:01Z</updated>
    <pubDate>2016-02-27T21:07:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/open-file-and-read-content-in-ruby" />
    <id>https://rust.code-maven.com/open-file-and-read-content-in-ruby</id>
    <content type="html"><![CDATA[<p>Чтение файла это одна из наиболее важных задач в любом языке программирования. В Ruby это сделать очень просто.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/read_file.rb">examples/ruby/read_file.rb</a></strong></p>
<pre><code class="language-ruby">if ARGV.length != 1
    puts &quot;We need exactly one parameter. The name of a file.&quot;
    exit;
end

filename = ARGV[0]
puts &quot;Going to open '#{filename}'&quot;

fh = open filename

# puts fh

content = fh.read

fh.close

puts content


</code></pre>
<pre><code>ruby read_file.rb  some/file.txt
</code></pre>
<p>Программа ожидает от нас передачи имени файла в командной строки и затем использует <a href="/argv-the-command-line-arguments-in-ruby">ARGV</a>
для доступа к значениям. Вообще-то, сначала мы проверяем, передал ли пользователь нужное количество аргументов, и прерываем работу, если это не так.</p>
<p>Затем мы используем вызов <code>open</code> для открытия файла на чтение. Этот вызов вернем нам объект класса <a href="http://ruby-doc.org/core/File.html">File</a>.</p>
<p>(Если мы выведем содержимое <code>fh</code>, то получим что-то вроде <code>#&amp;lt;File:0x007f8c0310f748&amp;gt;</code>)</p>
<p>Метод <code>read</code> этого класса прочитает все содержимое файла, которое мы сохраняем в переменную <code>content</code>.
Это полное содержимое файла, включая переводы строк.</p>
<p>По сути это тоже самое, что и <a href="https://perlmaven.com/slurp">slurp в Perl</a></p>
<h2 class="title is-4">Читаем файл построчно</h2>
<p>Чтение всего файла одним оператором выглядит простым, но не всегда хорошая идея.
Например, если у вас файл лога размером в 10 Gb, то вероятно, вам не захочется считать его весь в память.
Всегда ли у вас есть 10 Gb свободной памяти?</p>
<p>В таком случае, будет лучше читать файл построчно. После чтения строки, делайте с этой строкой что вам нужно, а затем заменяйте на новую строку.
Таким образом, в каждый момент времени в памяти мы держим только одну строку. Намного эффективнее.</p>
<p>Есть два способа реализовать это, и я не уверен, есть ли какие-то преимущества или недостатки в каждом их них.</p>
<p>Первый - с помощью <code>gets</code> и <code>while</code>. Выглядит будто это написал кто-то из мира Perl 5:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/read_file_by_line_while.rb">examples/ruby/read_file_by_line_while.rb</a></strong></p>
<pre><code class="language-ruby">if ARGV.length != 1
    puts &quot;We need exactly one parameter. The name of a file.&quot;
    exit;
end

filename = ARGV[0]
puts &quot;Going to open '#{filename}'&quot;

fh = open filename

while (line = fh.gets) 
   puts line
end

fh.close

</code></pre>
<p>Другой способ - с помощью <code>each</code>. Выглядит более Rubyish:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/read_file_by_line_each.rb">examples/ruby/read_file_by_line_each.rb</a></strong></p>
<pre><code class="language-ruby">if ARGV.length != 1
    puts &quot;We need exactly one parameter. The name of a file.&quot;
    exit;
end

filename = ARGV[0]
puts &quot;Going to open '#{filename}'&quot;

fh = open filename

fh.each do |line|
   puts line
end

fh.close

</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Диапазоны в Ruby</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-27T20:57:01Z</updated>
    <pubDate>2016-02-27T20:57:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/range-in-ruby" />
    <id>https://rust.code-maven.com/range-in-ruby</id>
    <content type="html"><![CDATA[<p>Ruby имеет два оператора для генерации диапазона значений. <code>..</code> - включающий и <code>...</code> - исключающий.</p>
<h2 class="title is-4">..</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/range_two.rb">examples/ruby/range_two.rb</a></strong></p>
<pre><code class="language-ruby">for i in 0..3
    puts i
end


</code></pre>
<p>Сгенерирует</p>
<pre><code>0
1
2
3
</code></pre>
<p>включая начало и конец, так же как это работает в Perl.</p>
<h2 class="title is-4">...</h2>
<p>Если мы будем использовать 3 точки вместо двух, тогда диапазон будет включать нижнюю границу, и не будет включать верхнюю.
Так же, как диапазоны <code>range</code> работают в Python.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/range_three.rb">examples/ruby/range_three.rb</a></strong></p>
<pre><code class="language-ruby">for i in 0...3
    puts i
end


</code></pre>
<pre><code>0
1
2
</code></pre>
<h2 class="title is-4">Обратный диапазон</h2>
<p>Если граница слева больше, чем граница справа, тогда оператор диапазона не вернет значений.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/range_two_wrong.rb">examples/ruby/range_two_wrong.rb</a></strong></p>
<pre><code class="language-ruby">for i in 7 .. 4
    puts i
end

</code></pre>
<p>Значения не возвращаются.</p>
<p>Как вариант, мы можем сгенерировать возрастающий список чисел, а затем вызвать для него метод <code>reverse</code>.
Для этого нам нужно сначала сконвертировать диапазон в массив:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/range_two_reverse.rb">examples/ruby/range_two_reverse.rb</a></strong></p>
<pre><code class="language-ruby">for i in (4..7).to_a.reverse
    puts i
end

</code></pre>
<p>напечатает:</p>
<pre><code>7
6
5
4
</code></pre>
<h2 class="title is-4">Буквенные диапазоны</h2>
<p>В дополнение к созданию диапазонов чисел, Ruby может также создавать буквенные диапазоны:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/range_letters.rb">examples/ruby/range_letters.rb</a></strong></p>
<pre><code class="language-ruby">for i in 'a'..'d'
   puts i
end

</code></pre>
<pre><code>a
b
c
d
</code></pre>
<h2 class="title is-4">Диапазоны символов</h2>
<p>Но и не только это. Мы можем использовать два любых символа из видимой части таблицы ASCI:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/range_chars.rb">examples/ruby/range_chars.rb</a></strong></p>
<pre><code class="language-ruby">for i in 'Z'..'a'
   puts i
end

</code></pre>
<pre><code>Z
[
\
]
^
_
`
a
</code></pre>
<h2 class="title is-4">Диапазоны с переменными</h2>
<p>В качестве нижней и верхней границ мы можем использовать переменные:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/range_var.rb">examples/ruby/range_var.rb</a></strong></p>
<pre><code class="language-ruby">x = 3
y = 6 
for i in x .. y
   puts i
end

</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>ARGV - аргументы командной строки в Ruby</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-27T20:45:01Z</updated>
    <pubDate>2016-02-27T20:45:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/argv-the-command-line-arguments-in-ruby" />
    <id>https://rust.code-maven.com/argv-the-command-line-arguments-in-ruby</id>
    <content type="html"><![CDATA[<p>Когда вы запускаете скрипт на Ruby, то можете указать любые значения в командной строке после имени скрипта:</p>
<p>Например:</p>
<p><code>ruby code.rb abc.txt  def.txt qqrq.txt</code></p>
<p>или вот так:</p>
<p><code>ruby code.rb Hello --machine big -d -tl</code></p>
<p>Вопрос в том, как программа на Ruby понимает, что передано в командной строке.</p>
<p>Ruby предоставляет массив <code>ARGV</code> со значениями из командной строки.
Мы можем получить доступ к элементам этого массива так же, как и в случае любого другого массива:</p>
<p><code>ARGV[0]</code> это первое значение после имени скрипта.</p>
<p>Мы можем обойти все элементы либо с помощью цикла <code>for</code>:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/command_line_argv.rb">examples/ruby/command_line_argv.rb</a></strong></p>
<pre><code class="language-ruby">for arg in ARGV
   puts arg
end


</code></pre>
<p>либо с помощью <a href="/range-in-ruby">диапазона</a> индексов, получая элементы по индексу.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/command_line_argv_with_index.rb">examples/ruby/command_line_argv_with_index.rb</a></strong></p>
<pre><code class="language-ruby">for i in 0 ... ARGV.length
   puts &quot;#{i} #{ARGV[i]}&quot;
end


</code></pre>
<pre><code>$ ruby command_line_argv_with_index.rb foo bar --machine big
0 foo
1 bar
2 --machine
3 big
</code></pre>
<h2 class="title is-4">Проверка количества аргументов</h2>
<p>Для простой валидации переданных значений мы можем проверить длину массива <code>ARGV</code>.
И если мы получили недостаточно аргументов, то сообщить об этом и преждевременно завершить работу программы.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/command_line_argv_check_length.rb">examples/ruby/command_line_argv_check_length.rb</a></strong></p>
<pre><code class="language-ruby">if ARGV.length &lt; 2
  puts &quot;Too few arguments&quot;
  exit
end

puts &quot;Working on #{ARGV}&quot;;


</code></pre>
<p>Запустив скрипт, мы получим:</p>
<pre><code>$ ruby command_line_argv_check_length.rb one
Too few arguments

$ ruby command_line_argv_check_length.rb one two
Working on [&quot;one&quot;, &quot;two&quot;]
</code></pre>
<h2 class="title is-4">Значения из командной строки имеют тип строка</h2>
<p>Во фрагменте кода мы сначала проверяем, получили ли мы точно 2 параметра, и если да, то суммируем их:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/command_line_argv_add.rb">examples/ruby/command_line_argv_add.rb</a></strong></p>
<pre><code class="language-ruby">if ARGV.length != 2
  puts &quot;We need exactly two arguments&quot;
  exit
end

puts ARGV[0] + ARGV[1]

</code></pre>
<pre><code>ruby command_line_argv_add.rb 23 19
2319
</code></pre>
<p>Результат вас не удивит, если вы знаете, что переданные в командную строку значения, приходят в программу как строки.
Даже если это на самом деле числа. Если мы хотим использовать их как числа, то нужно их сконвертировать с помощью <code>to_i</code>:</p>
<pre><code>$ ruby command_line_argv_add_numbers.rb 23 19
42
</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Упражнение: Анализ лог-файла Apache - считаем localhost</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-27T20:33:01Z</updated>
    <pubDate>2016-02-27T20:33:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/exercise-analyze-apache-log-file-count-localhost" />
    <id>https://rust.code-maven.com/exercise-analyze-apache-log-file-count-localhost</id>
    <content type="html"><![CDATA[<p>В этом <a href="/exercises">упражнении</a> мы берем файл лога, сгенерированный веб-сервером, и проводим простой анализ.</p>
<p>Файл выглядит вот так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/data/apache_access.log">examples/data/apache_access.log</a></strong></p>
<pre><code class="language-log">127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] &quot;GET / HTTP/1.1&quot; 500 606 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] &quot;GET /favicon.ico HTTP/1.1&quot; 200 766 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] &quot;GET / HTTP/1.1&quot; 500 612 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] &quot;GET /favicon.ico HTTP/1.1&quot; 200 766 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:53:10 +0300] &quot;GET / HTTP/1.1&quot; 500 612 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET / HTTP/1.0&quot; 200 3700 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET /style.css HTTP/1.1&quot; 200 614 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET /img/machine-round.jpg HTTP/1.1&quot; 200 17524 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.11 - - [10/Apr/2007:10:54:21 +0300] &quot;GET /unix_sysadmin.html HTTP/1.1&quot; 200 3880 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:54:51 +0300] &quot;GET / HTTP/1.1&quot; 200 34 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:54:51 +0300] &quot;GET /favicon.ico HTTP/1.1&quot; 200 11514 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:54:53 +0300] &quot;GET /cgi/machine.pl HTTP/1.1&quot; 500 617 &quot;http://contact.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET / HTTP/0.9&quot; 200 3700 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:58:27 +0300] &quot;GET / HTTP/1.1&quot; 200 3700 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:58:34 +0300] &quot;GET /unix_sysadmin.html HTTP/1.1&quot; 200 3880 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:58:45 +0300] &quot;GET /talks/Fundamentals/read-excel-file.html HTTP/1.1&quot; 404 311 &quot;http://machine.local/unix_sysadmin.html&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;

</code></pre>
<p>Каждая строка это запрос к веб-серверу. Что-то это страницы, что-то - изображения, что-то - файлы JavaScript.
Это сейчас не так важно. Сейчас мы собираемся сфокусироваться на первом элементе каждой строки, где указан IP-адрес хоста, откуда пришел запрос.
Делаем это с помощью простого упражнения.</p>
<p>Как вы, вероятно, знаете, каждое устройство использует IP-адрес 127.0.0.1 для ссылок на самого себя. Таким образом, запросы с этим
IP-адресом пришли с этой же самой машины.</p>
<p>Задача написать скрипт, который посчитает запросы, пришедшие с 127.0.0.1 и остальные.</p>
<h2 class="title is-4">Инструменты</h2>
<ul>
<li><a href="https://perlmaven.com/beginner-perl-maven-open-file">Perl 5: open the file for reading or die</a></li>
<li><a href="https://perlmaven.com/chomp">Perl 5: chomp remove trailing newlines</a></li>
<li><a href="https://perlmaven.com/beginner-perl-maven-string-functions-index">Perl 5: index</a></li>
<li><a href="https://perlmaven.com/beginner-perl-maven-substr">Perl 5: substr</a></li>
<li><a href="/argv-the-command-line-arguments-in-ruby">Ruby: параметры командной строки ARGV</a>.</li>
<li><a href="/open-file-and-read-content-in-ruby">Ruby: открытие файла на чтение и работа с ним</a>.</li>
</ul>
<h2 class="title is-4">Решения</h2>
<ul>
<li><a href="https://perlmaven.com/beginner-perl-maven-analyze-apache-log-file">Perl 5 - Analyze Apache log file - count localhost</a></li>
<li><a href="/analyze-apache-log-file-count-localhost-in-ruby">Ruby - Анализ лог-файла Apache - считаем localhost</a></li>
</ul>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Анализ лога Apache - считаем запросы с localhost на Ruby</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-27T20:10:01Z</updated>
    <pubDate>2016-02-27T20:10:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/analyze-apache-log-file-count-localhost-in-ruby" />
    <id>https://rust.code-maven.com/analyze-apache-log-file-count-localhost-in-ruby</id>
    <content type="html"><![CDATA[<p>Было <a href="/exercise-analyze-apache-log-file-count-localhost">упражнение</a>, где нужно в файле логов веб-сервера Apache (или любого другого веб-сервера) посчитать,
сколько запросов пришло с локального хоста localhost (IP 127.0.0.1) и сколько из других мест.</p>
<p>Лог-файл выглядит вот так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/data/apache_access.log">examples/data/apache_access.log</a></strong></p>
<pre><code class="language-log">127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] &quot;GET / HTTP/1.1&quot; 500 606 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] &quot;GET /favicon.ico HTTP/1.1&quot; 200 766 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] &quot;GET / HTTP/1.1&quot; 500 612 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] &quot;GET /favicon.ico HTTP/1.1&quot; 200 766 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:53:10 +0300] &quot;GET / HTTP/1.1&quot; 500 612 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET / HTTP/1.0&quot; 200 3700 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET /style.css HTTP/1.1&quot; 200 614 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET /img/machine-round.jpg HTTP/1.1&quot; 200 17524 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.11 - - [10/Apr/2007:10:54:21 +0300] &quot;GET /unix_sysadmin.html HTTP/1.1&quot; 200 3880 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:54:51 +0300] &quot;GET / HTTP/1.1&quot; 200 34 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:54:51 +0300] &quot;GET /favicon.ico HTTP/1.1&quot; 200 11514 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:54:53 +0300] &quot;GET /cgi/machine.pl HTTP/1.1&quot; 500 617 &quot;http://contact.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] &quot;GET / HTTP/0.9&quot; 200 3700 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:58:27 +0300] &quot;GET / HTTP/1.1&quot; 200 3700 &quot;-&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:58:34 +0300] &quot;GET /unix_sysadmin.html HTTP/1.1&quot; 200 3880 &quot;http://machine.local/&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;
217.0.22.3 - - [10/Apr/2007:10:58:45 +0300] &quot;GET /talks/Fundamentals/read-excel-file.html HTTP/1.1&quot; 404 311 &quot;http://machine.local/unix_sysadmin.html&quot; &quot;Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.3) Gecko/20061201 Firefox/2.0.0.3 (Ubuntu-feisty)&quot;

</code></pre>
<h2 class="title is-4">Алгоритм:</h2>
<p>Нам нужно два счетчика: один для подсчета хитов с 127.0.0.1 и один для хитов с других адресов.
Затем нужно пройтись по всем строкам, извлечь IP-адрес, и на его основе увеличить один из счетчиков.</p>
<p>Мы предполагаем, что программа будет использовать вот так: <code>ruby apache_localhost.rb  data/apache_access.log</code>.
Таким образом, мы предполагаем, что пользователь укажет имя файла с логом в качестве аргумента команды.</p>
<p>Тем не менее, в первых строках мы проверяем, передал ли пользователь вообще имя файла с помощью <a href="/argv-the-command-line-arguments-in-ruby">количества элементов в ARGV</a>.
Если количество полученных аргументов не равно 1, то мы говорим пользователю, как пользоваться нашей программой и завершаем работу (<code>exit</code>).</p>
<p>Затем мы копируем имя файла из <code>ARGV</code> во внутреннюю переменную <code>filename</code>. В основном для наглядности кода.</p>
<p>Затем мы создаем два счетчика и устанавливаем их в 0.</p>
<p>Затем мы <a href="/open-file-and-read-content-in-ruby">открываем файл на чтение</a> и читаем строку за строкой с помощью <code>each</code>.
В каждой итерации переменная <code>line</code> будет содержать текущую строку из файла.</p>
<p>IP-адрес это первое значение в строке до пробела.
Есть несколько способов получить это значение из строки. В этом случае мы используем метод <code>index</code> объекта <code>line</code>, передавая ему пробел.
Метод вернет позицию первого пробела в <code>line</code>. Так как нумерация начинается с 0, то этот номер будет также и длиной IP-адреса.
Поэтому мы записали полученный результат в переменную <code>length</code>.</p>
<p>Мы можем использовать эту переменную для извлечения подстроки из <code>line</code>, которая начинается с 0 и включает <code>length</code> символов.
Для этого нужно передать индекс начала подстроки и длину подстроки, которую мы хотим извлечь.
Это и будет IP-адрес из текущей строки.</p>
<p>Осталость только проверить, что полученное значение совпадает с 127.0.0.1 (localhost) и увеличить соответствующий счетчик.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/ruby/apache_localhost.rb">examples/ruby/apache_localhost.rb</a></strong></p>
<pre><code class="language-ruby">
if ARGV.length != 1 then
    puts &quot;We need the name of the log file&quot;
    exit
end

filename = ARGV[0]

local = 0
remote = 0

fh = open filename
fh.each do |line|
    length = line.index(' ')
    ip = line[0, length]
    if ip == '127.0.0.1' then
        local = local+1
    else
        remote = remote+1
    end
end

puts &quot;Number of remote requests is #{remote}. Number of local requests was #{local}&quot;

</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Crawling и scraping</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2016-02-23T17:44:01Z</updated>
    <pubDate>2016-02-23T17:44:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/adventures-in-crawling-and-scraping-the-world" />
    <id>https://rust.code-maven.com/adventures-in-crawling-and-scraping-the-world</id>
    <content type="html"><![CDATA[<p>Хотя два слова <code>crawling</code> и <code>scraping</code> обычно взаимозаменяемы - по крайней мере, когда мы говорим о веб -
они могут иметь слегка различающиеся значения. Crawling обычно подразумевает переход от страницы к странице, перемещаясь между сайтами.
Scraping в свою очередь обычно подразумеваем анализ одной или очень ограниченного набора страниц.</p>
<p>Хотя, может быть, я просто выдумал это различие. Кто знает, что другие имеют в виду под этими словами?</p>
<p><code>Боты</code>, <code>Роботы</code>, <code>Веб-пауки</code>, как правило, относятся к программам, которые реализуют <code>crawling</code> или <code>scraping</code></p>
<h2 class="title is-4">Задачи</h2>
<p>Самая простая задача это скачать заданный URL.</p>
<p>Затем, если нам вернулась HTML страница, мы можем:</p>
<p>Скачать картинки.</p>
<p>Скачать конкретные файлы. (Изображения это одна из возможностей, но возможно, вы бы хотели скачать все JavaScript файлы или все видео, или ...)</p>
<h2 class="title is-4">Встречающиеся проблемы</h2>
<p><b>Исключение</b> Есть части веб-сайта, которые вы не хотите обходить. Либо потому что вам не интересно,
или потому что вы хотите быть хорошим посетителем и соблюдать описанное в файле <code>robots.txt</code>.
<code>robots.txt</code> это файл, описывающий предпочтения владельца сайта относительно того, какие роботы могут посещать какие области сайта.</p>
<p><b>Глубина</b> - на какое количество кликов от стартовой страницы вы хотите погрузиться?</p>
<p><b>Одновременная загрузка</b> - с одной строны, скачивание страниц одной за другой может занять много времени.
С другой стороны, скачивание 100 страниц одновременно может привести к ваше блокировке на сайте.
Вам нужно найти верный баланс.</p>
<p><b>Пауза между страницами</b> для облегчения нагрузки, что мы генерируем на сервере - мы можем захотеть сделать паузу между скачиванием страниц
с одного и того же сервера.</p>
<p><b>Стартовые страницы</b> Какой-то способ описать больше одной стартовой страницы.</p>
<p><b>Циклы</b> Избежание повторяющихся загрузок одних и тех же страниц.</p>
<p><b>Условия использования</b> некоторые веб-сайты могут иметь официальные документы, описывающие, что вы уполномочены скачивать и что вы можете с этим потом делать.
К примеру, показ аналогичного контента на другом сайте, как это было на оригинальном сайте, обычно не то, что вам стоит делать.</p>
<p>Обработка JavaScript на веб-сайте.</p>
<p>Обработка параметров в URL. <a href="http://examples.org/">http://examples.org/</a>  <a href="http://examples.org/?id=42">http://examples.org/?id=42</a> Это одна и та же страница? Когда мы встретим вторую, нам нужно удалить параметры после &quot;?&quot;?</p>
<p>Обработка кнопок. Нужно ли нам обходить нажатия по кнопкам или только по ссылкам?</p>
<p>Обработка форм. Должен ли наш обходчик заполнять формы и нажимать на кнопки? Какие значения он должен заполнить?</p>
<p>Кросс-ссылки: Когда мы хотим обойти один или несколько конкретных сайтов, мы должны быть уверены, что ссылки не ведут на внешние ресурсы.
С другой стороны мы бы хотели разрешить переходить по ссылками между сайтами из предопределенного списка URL.</p>
<p>С www или без wwww. Все еще есть сайты, которые предоставляют один и тот же контент с обоих сайтов <a href="http://www.example.com">www.example.com</a> и example.com вместо редиректов
с одного на другой. Мы должны решить, рассматривать это как два разных сайта, или мы бы хотели обойти только один из них.
Что делать, если будут ссылки с одного на другой? Должны ли мы заменить один URL другим, делая вид, что там на самом деле редирект?
Другими словами, если мы решили проиндексировать example.com, но там есть ссылка на <a href="http://www.example.com/abc">http://www.example.com/abc</a> стоит ли пробовать скачать <a href="http://example.com/abc">http://example.com/abc</a> вместо этого?</p>
<h2 class="title is-4">Инструменты</h2>
<h3 class="title is-5">JavaScript / NodeJS</h3>
<ul>
<li><a href="https://nodejs.org/api/http.html">http</a> (посмотрите, как сделать <a href="/building-a-crawler-in-nodejs">crawler на NodeJS</a>)</li>
<li><a href="https://github.com/sylvinus/node-crawler">node-crawler</a></li>
<li><a href="https://www.npmjs.com/package/node-jsdom">node-jsdom</a></li>
<li><a href="https://github.com/virushuo/node-crawler-cheerio">node-crawler-cheerio</a></li>
<li><a href="http://phantomjs.org/">PhantomJS</a></li>
</ul>
<h3 class="title is-5">Python</h3>
<ul>
<li><a href="https://docs.python.org/2/library/urllib.html">urllib</a></li>
<li><a href="https://docs.python.org/2/library/urllib2.html">urllib2</a></li>
<li><a href="http://scrapy.org/">Scrapy</a></li>
</ul>
<h3 class="title is-5">Perl 5</h3>
<ul>
<li><a href="https://metacpan.org/pod/LWP::Simple">LWP::Simple</a></li>
<li><a href="https://metacpan.org/pod/LWP::UserAgent">LWP::UserAgent</a></li>
<li><a href="https://metacpan.org/pod/WWW::Mechanize">WWW::Mechanize</a></li>
<li><a href="https://metacpan.org/pod/WWW::Spyder">WWW::Spyder</a></li>
<li><a href="https://metacpan.org/pod/WWW::Crawler::Lite">WWW::Crawler::Lite</a></li>
<li><a href="https://metacpan.org/pod/WWW::Crawler::Mojo">WWW::Crawler::Mojo</a></li>
<li><a href="https://metacpan.org/pod/Web::Query">Web::Query</a></li>
<li><a href="https://metacpan.org/pod/Mojo::UserAgent">Mojo::UserAgent</a> и <a href="http://blogs.perl.org/users/stas/2013/01/web-scraping-with-modern-perl-part-1.html">mojo-crawler</a> and <a href="https://gist.github.com/creaktive/4607326">yada-crawler</a></li>
<li><a href="https://metacpan.org/pod/Scrappy">Scrappy</a></li>
<li><a href="https://metacpan.org/pod/Web::Scraper">Web::Scraper</a></li>
<li><a href="https://perlmaven.com/pro/web-scraping-with-html-treebuilder">Web scraping with HTML::TreeBuilder</a></li>
<li><a href="https://perlmaven.com/simple-way-to-fetch-many-web-pages">A Simple way to download many web pages using Perl: LWP::Simple and HTTP::Tiny</a></li>
<li><a href="https://perlmaven.com/fetching-several-web-pages-in-parallel-using-anyevent">Fetching several web pages in parallel using AnyEvent</a></li>
</ul>
<h3 class="title is-5">Ruby</h3>
<p>&lt;l&quot;&gt;<a href="https://rubygems.org/gems/mechanize">mechanize</a></p>
<ul>
<li>
<p><a href="https://rubygems.org/gems/excon">excon</a></p>
</li>
<li>
<p><a href="https://rubygems.org/gems/httparty">httparty</a></p>
</li>
<li>
<p><a href="https://www.ruby-toolbox.com/projects/httpclient">httpclient</a></p>
</li>
<li>
<p><a href="https://www.ruby-toolbox.com/projects/curb">curb</a></p>
</li>
<li>
<p><a href="https://www.ruby-toolbox.com/projects/typhoeus">Typhoeus</a></p>
</li>
<li>
<p><a href="https://www.ruby-toolbox.com/projects/patron">Patron</a></p>
</li>
</ul>
<h2 class="title is-4">Альтернатива: Common Crawl</h2>
<p><a href="http://commoncrawl.org/">Common Crawl</a></p>
<h2 class="title is-4">Книги</h2>
<ul>
<li><a href="http://shop.oreilly.com/product/0636920034391.do">Web Scraping with Python</a></li>
<li><a href="http://www.oreilly.com/openbook/webclient/">Web Client Programming with Perl</a></li>
</ul>
<h2 class="title is-4">Другое</h2>
<ul>
<li>
<p><a href="http://scrapinghub.com/">Scraping Hub</a> is scraping as a service.</p>
</li>
<li>
<p><a href="https://www.deepcrawl.com/">DeepCrawl</a></p>
</li>
</ul>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Простой калькулятор на AngularJS</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-10-25T19:02:01Z</updated>
    <pubDate>2015-10-25T19:02:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/calculator-in-angularjs" />
    <id>https://rust.code-maven.com/calculator-in-angularjs</id>
    <content type="html"><![CDATA[<p>Не так давно я сделал пример про <a href="/add-numbers-with-angular">сложение чисел на AngularJS</a>.
В этой статье мы создадим простой калькулятор на AngularJS.</p>
<p>Если вы следили за <a href="/angularjs">предыдущими статьями</a>, тогда вы увидите, что в этот раз
я разделил HTML и JavaScript.</p>
<h2 class="title is-4">HTML</h2>
<p>Вы также увидите, что HTML все еще очень прост, хотя он содержит новый элемент.
В этом примере объявления <code>ng-app</code> и <code>ng-controller</code> находятся
в одном и том же элементе HTML. Зачем создавать дополнительный слой, если
мы можем это все сделать в одном элементе <code>div</code>?</p>
<p>Кроме того у нас есть два элемента <code>input</code> и один <code>select</code>.
Каждый из них имеет свой собственный атрибут <code>ng-model</code>.</p>
<p>Последняя часть HTML это директива <code>{{ result() }}</code>.
Думаю, это первый раз, когда у нас в директиве указан вызов функции.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/calculator.html">examples/angular/calculator.html</a></strong></p>
<pre><code class="language-html">&lt;script src= &quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script src= &quot;calculator.js&quot;&gt;&lt;/script&gt;

&lt;div ng-app=&quot;CalculatorApp&quot; ng-controller=&quot;CalculatorController&quot;&gt;
  &lt;p&gt;&lt;input type=&quot;number&quot; ng-model=&quot;a&quot;&gt;&lt;/p&gt;
  &lt;p&gt;&lt;input type=&quot;number&quot; ng-model=&quot;b&quot;&gt;&lt;/p&gt;
  &lt;p&gt;&lt;select ng-model=&quot;operator&quot;&gt;
        &lt;option&gt;+&lt;/option&gt;
        &lt;option&gt;*&lt;/option&gt;
        &lt;option&gt;-&lt;/option&gt;
        &lt;option&gt;/&lt;/option&gt;
     &lt;/select&gt;&lt;/p&gt;
  &lt;p&gt;{{ result() }}&lt;/p&gt;
 &lt;/div&gt;

</code></pre>
<p><a href="examples/angular/calculator.html">view</a></p>
<h2 class="title is-4">JavaScript</h2>
<p>В JavaScript мы создали <code>модуль и контроллер Angular</code> и
описали функцию <code>result</code> как атрибут текущего <code>$scope</code>.
Именно это позволяет использовать функции в директивах Angular внутри HTML.</p>
<p>JavaScript считает результат простых операций, там все очевидно, хотя и немного скучно.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/calculator.js">examples/angular/calculator.js</a></strong></p>
<pre><code class="language-js">angular.module('CalculatorApp', [])
    .controller('CalculatorController', function($scope) {
        $scope.result = function() {
            if ($scope.operator == '+') {
                return $scope.a + $scope.b;
            }
            if ($scope.operator == '-') {
                return $scope.a - $scope.b;
            }
            if ($scope.operator == '*') {
                return $scope.a * $scope.b;
            }
            if ($scope.operator == '/') {
                return $scope.a / $scope.b;
            }
        };
    });

</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Автоматический счетчик на AngularJS</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-10-25T18:25:01Z</updated>
    <pubDate>2015-10-25T18:25:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/automatic-counter-using-angularjs" />
    <id>https://rust.code-maven.com/automatic-counter-using-angularjs</id>
    <content type="html"><![CDATA[<p>Мы видели <a href="/simple-in-memory-counter-with-angularjs">как создать счетчик на AngularJS</a>, который
мы увеличивали или уменьшали с помощью нажатий на кнопку. В этом примере мы будем автоматически
увеличивать счетчик с течением времени.</p>
<p>Не забудьте ознакомиться с другими <a href="https://code-maven.com/counter">примерами счетчиков</a>!</p>
<h2 class="title is-4">Планирование будущего выполнения, используя $timeout</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/automatic_counter.html">examples/angular/automatic_counter.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
angular.module('CounterApp', [])
    .controller('CounterController', function($scope, $timeout) {
        $scope.counter = 0;
        var updateCounter = function() {
            $scope.counter++;
            $timeout(updateCounter, 1000);
        };
        updateCounter();
    });
&lt;/script&gt;
&lt;div ng-app=&quot;CounterApp&quot;&gt;
   &lt;div ng-controller=&quot;CounterController&quot;&gt;
   {{counter}}
   &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/automatic_counter.html">view</a></p>
<p>В этом примере функция контроллера ожидает два параметра. <code>$scope</code> - содержит атрибуты, с которыми
мы взаимодействуем в нашем HTML, и <code>$timeout</code> - это функция, похожая на <code>setTimeout</code> из обычного Javascript.
(На самом деле это называется <b>внедрение зависимости</b>, а не параметры, но пока не будем беспокоиться об этом.
Особенно, пока я сам этого не понимаю.)</p>
<p><code>$timeout</code> это функция, которая принимает два параметра: функцию обратного вызова (коллбек) и время,
определенное в милисекундах.
Она откладывает выполнение полученной функции до истечения заданного времени. Если передать 1000 в качестве
второго параметра, мы отложим выполнение переданной функции на 1 секунду после того,
как собственно вызовем саму эту функцию.</p>
<p>Внутри функции контроллера первое что мы делаем, это создаем атрибут <code>counter</code> и
устанавливаем ему значение по умолчанию 0. Мы хотим, чтобы отчет начинался с 0.</p>
<p>Затем мы создаем функцию <code>updateCounter</code>, которая при вызове будет увеличивать <code>counter</code> и использовать <code>$timeout</code>,
чтобы вызвать себя же спустя 1 секунду. Это значит, что каждый раз при вызове функции <code>updateCounter</code> она увеличит
счетчик и запланирует в системе повторный вызов через 1 секунду. Это значит, функция будет запускаться каждую секунду.</p>
<p>Затем последний шаг это первый вызов <code>updateCounter</code> для запуска бесконечного цикла.</p>
<h2 class="title is-4">Счетчик с кнопкой Стоп</h2>
<p>Этот счетчик будет увеличиваться каждую секунду, но что если мы захотим остановить его?
Мы увидим пример с дополнительной кнопкой, которая остановит счетчик.</p>
<p><code>$timeout</code> возвращает объект <code>promise</code>, который мы можем использовать позднее, чтобы отключить таймер.
Чтобы сделать <code>promise</code> доступным, когда нам будет нужно, я создал переменную <code>timer</code>
и присвоил ей то, что вернула функция <code>$timeout</code>.
(Конечно, я мог бы использовать здесь любое другое имя.)</p>
<p>Затем я добавил кнопку в HTML и указал в атрибуте <code>ng-click</code> вызов метода <code>stopCounter</code>.</p>
<p>Осталось сделать только метод <code>stopCounter</code>.</p>
<p>Для начала я создал его, используя <code>var stopCounter = function() { ... }</code>
как и <code>updateCounter</code>, но это не сработало. Так как мы хотим вызывать метод из HTML,
нам нужно добавить этот метод в <code>$scope</code>. Следовательно, я должен был заменить
определение на:
<code>$scope.stopCounter = function() { ... }</code>.</p>
<p>Внутри у нас есть выражение <code>$timeout.cancel(timer);</code>, которое отменит работу таймера. Попробуйте!</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/automatic_counter_with_stop.html">examples/angular/automatic_counter_with_stop.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
angular.module('CounterApp', [])
    .controller('CounterController', function($scope, $timeout) {
        var timer;
        $scope.counter = 0;
        $scope.stopCounter = function() {
            $timeout.cancel(timer);
        };
        var updateCounter = function() {
            $scope.counter++;
            timer = $timeout(updateCounter, 1000);
        };
        updateCounter();
    });
&lt;/script&gt;
&lt;div ng-app=&quot;CounterApp&quot;&gt;
   &lt;div ng-controller=&quot;CounterController&quot;&gt;
   {{counter}}
   &lt;button ng-click=&quot;stopCounter()&quot;&gt;Stop&lt;/button&gt;
   &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/automatic_counter_with_stop.html">view</a></p>
<h2 class="title is-4">Счетчик с кнопками запуска и остановки</h2>
<p>Еще одна штука, которую я хочу показать, это как я добавил еще одну кнопку для запуска счетчика дальше.</p>
<p>Первая версия была простой. Я просто добавил кнопку и новую функцию:</p>
<pre><code class="language-javascript">$scope.startCounter = function() {
    updateCounter();
};
</code></pre>
<p>Проблема такого решения в том, что оно позволяло мне нажать несколько раз на кнопку старта,
и счетчик начинал увеличиваться слишком быстро, перескакивая иногда на 2 или 3 шага.
В реальности происходило вот что: каждый раз, когда я нажимал на кнопку <code>start</code>, запускался
новый таймер и несколько таймеров работало параллельно.</p>
<p>Я должен был как-то убедиться, что в одно время работает только один таймер. Либо заблокировать
кнопку <code>start</code> после нажатия, либо проверять, что таймер уже запущен, и запускать новый только если это не так.</p>
<p>Я выбрал это решение, так как был больше заинтересован в решении на JavaScript/AngularJS.
Я сделал два изменения. В функции <code>stopCounter</code> я добавил</p>
<pre><code class="language-javascript">timer = null;
</code></pre>
<p>В конце концов все что у нас есть, это отмененный таймер, и нет смысла держать неиспользуемые объекты.</p>
<p>Затем в методе <code>startCounter</code> я смог проверить, является ли <code>timer</code> <code>null</code> или нет,
и создать новый объект $timeout, если таймер отсутствует.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/automatic_counter_with_stop_start.html">examples/angular/automatic_counter_with_stop_start.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
angular.module('CounterApp', [])
    .controller('CounterController', function($scope, $timeout) {
        var timer;
        $scope.counter = 0;
        $scope.stopCounter = function() {
            $timeout.cancel(timer);
            timer = null;
        };
        $scope.startCounter = function() {
            if (timer === null) {
                updateCounter();
            }
        };
        var updateCounter = function() {
            $scope.counter++;
            timer = $timeout(updateCounter, 1000);
        };
        updateCounter();
    });
&lt;/script&gt;
&lt;div ng-app=&quot;CounterApp&quot;&gt;
   &lt;div ng-controller=&quot;CounterController&quot;&gt;
   {{counter}}
   &lt;button ng-click=&quot;stopCounter()&quot;&gt;Stop&lt;/button&gt;
   &lt;button ng-click=&quot;startCounter()&quot;&gt;Start&lt;/button&gt;
   &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/automatic_counter_with_stop_start.html">view</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Простой in-memory счетчик с AngularJS</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-10-25T17:54:01Z</updated>
    <pubDate>2015-10-25T17:54:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/simple-in-memory-counter-with-angularjs" />
    <id>https://rust.code-maven.com/simple-in-memory-counter-with-angularjs</id>
    <content type="html"><![CDATA[<p>В статье <a href="https://code-maven.com/counter">о примерах счетчиков</a> мы видели много вариантов реализации.
Вот один с использованием <a href="/angularjs">AngularJS</a>.</p>
<h2 class="title is-4">Простая кнопка для увеличения счетчика</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/in_memory_counter.html">examples/angular/in_memory_counter.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
    &lt;button ng-init=&quot;counter = 0&quot; ng-click=&quot;counter = counter + 1&quot;&gt;Increment&lt;/button&gt;
    {{counter}}
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/in_memory_counter.html">view</a></p>
<p>В этом примере у нас есть HTML кнопка с двумя Angular-атрибутами.
Содержимое атрибута <code>ng-init</code> будет выполнено один раз во время загрузки страницы. Он задает начальное значение атрибута <code>counter</code>.</p>
<p>Содержимое атрибута <code>ng-click</code> будет выполняться каждый раз во время нажатия кнопки. Он будет увеличить счетчик на 1.
(<code>counter++</code> здесь не работает)</p>
<p>Когда страница загружается, мы видим кнопку &quot;Increment&quot; и число 0. Как только мы нажмем на кнопку, число увеличится на 1.</p>
<h2 class="title is-4">Кнопки для увеличения (инкремент) и уменьшения (декремент)</h2>
<p>В следующем примере у нас есть новая кнопка - для уменьшения счетчика на 1.
К тому же, чтобы этот шаг сделать более явным, мы перенесли атрибут <code>ng-init</code>
в отдельный элемент <code>div</code>, который не отображается.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/in_memory_counter_with_decrement.html">examples/angular/in_memory_counter_with_decrement.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
    &lt;div ng-init=&quot;counter = 0&quot;&gt;&lt;/div&gt;
    &lt;button ng-click=&quot;counter = counter + 1&quot;&gt;Increment&lt;/button&gt;
    &lt;button ng-click=&quot;counter = counter - 1&quot;&gt;Decrement&lt;/button&gt;
    {{counter}}
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/in_memory_counter_with_decrement.html">view</a></p>
<h2 class="title is-4">In-memory счетчик с помощью контроллера</h2>
<p>С целью подготовки к более сложным действиям в третьем примере мы перенесли код, уменьшающий счетчик, в контроллер.
(Кнопка, увеличивающая счетчик, осталась без изменений.)</p>
<p>В этот раз мы создали <a href="/hello-world-with-angular-controller">модуль и контроллер Angular</a>,
в котором установили значение по умолчанию для переменной <code>$scope.counter</code> в 0 и определили метод <code>decrement</code>.
Так как это уже чистый JavaScript, то мы можем делать автоинкремент и автодекремент с помощью выражения: <code>counter--</code>.</p>
<p>В HTML мы установили атрибут <code>ng-click=&quot;decrement()&quot;</code>, который обозначает, что метод <code>decrement</code>
будет вызыван каждый раз, когда будет нажата кнопка.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/in_memory_counter_with_controller.html">examples/angular/in_memory_counter_with_controller.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
angular.module(&quot;CounterApp&quot;, [])
    .controller(&quot;CounterController&quot;, function($scope) {
        $scope.counter = 0;
        $scope.decrement = function() {
            $scope.counter--;
        };
})
&lt;/script&gt;
&lt;div ng-app=&quot;CounterApp&quot;&gt;
    &lt;div ng-controller=&quot;CounterController&quot;&gt;
        &lt;button ng-click=&quot;counter = counter + 1&quot;&gt;Increment&lt;/button&gt;
        &lt;button ng-click=&quot;decrement()&quot;&gt;Decrement&lt;/button&gt;
        {{counter}}
    &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/in_memory_counter_with_controller.html">view</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Сложение чисел с AngularJS</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-10-11T17:30:01Z</updated>
    <pubDate>2015-10-11T17:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/add-numbers-with-angular" />
    <id>https://rust.code-maven.com/add-numbers-with-angular</id>
    <content type="html"><![CDATA[<p>После написания самого простого примера, я захотел создать небольшой калькулятор с помощью Angular.
Это один из наиболее простых примеров кода, которые я могу представить после &quot;Hello World&quot; и &quot;Echo&quot;.</p>
<p>Так что я решил создать страницу с помощью <a href="/angularjs">AngularJS</a>, которая сложит два числа.</p>
<h2 class="title is-4">Наивный подход</h2>
<p>Наивным решением, которое не сработало, было создать два элемента <code>input</code> с <code>ng-model</code> 'a' и 'b',
и затем написать выражение, складывающее эти два значения.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/add.html">examples/angular/add.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
  &lt;input ng-model=&quot;a&quot;&gt;
  &lt;input ng-model=&quot;b&quot;&gt;
  &lt;h1&gt;{{ a + b }}&lt;/h1&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/add.html">view</a></p>
<p>К сожалению, JavaScript, а следовательно и Angular, обрабатывают введенные значения как строки,
даже если это на самом деле числа. Поэтому использование оператора <code>+</code> для строк приводит к их конкатенации.
Следовательно, если мы попробуем пример выше и введем в поля 2 и 3, то получим в результате 23.</p>
<h2 class="title is-4">Сложение чисел с помощью контролллера</h2>
<p>Сначала, как мы делали в примере <a href="/hello-world-with-angular-controller">Hello World</a>,
мы <a href="/hello-world-with-angular-controller">создали модуль и контроллер</a>.
Внутри контроллера мы создали функцию <code>AddNumbers</code>, связанную со <code>$scope</code>.
В той функции мы получаем значения для двух элементов <code>input</code> и преобразовываем их
в <code>Number</code> с помощью вызова функции JavaScript. (Чтобы избежать использования значения <code>undefined</code>,
мы присваиваем значение по умолчанию равное 0.)
Затем мы суммируем значения и присваиваем полученное к созданному атрибуту <code>sum</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/add_numbers_controller.js">examples/angular/add_numbers_controller.js</a></strong></p>
<pre><code class="language-js">angular.module('AddNumbersApp', [])
    .controller('AddNumbersController', function($scope) {
        $scope.AddNumbers = function() {
            var a = Number($scope.a || 0);
            var b = Number($scope.b || 0);
            $scope.sum = a+b;
        }
});

</code></pre>
<p>Затем в HTML мы можем использовать этот атрибут <code>sum</code> как часть простого выражения.
Для вызова функции <code>AddNumbers</code>, мы также добавили атрибут <code>ng-keyup</code> к обоим элементам <code>input</code>:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/add_numbers_controller.html">examples/angular/add_numbers_controller.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;add_numbers_controller.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app=&quot;AddNumbersApp&quot;&gt;
    &lt;div ng-controller=&quot;AddNumbersController&quot;&gt;
        &lt;input ng-model=&quot;a&quot; ng-keyup=&quot;AddNumbers()&quot;&gt;
        &lt;input ng-model=&quot;b&quot; ng-keyup=&quot;AddNumbers()&quot;&gt;
        &lt;h1&gt;{{ sum }}&lt;/h1&gt;
    &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/add_numbers_controller.html">view</a></p>
<p>Попробуйте! Это великолепно работает!</p>
<p>Пока я это писал, подумал, что должно быть более простое решение, так как такой способ выглядит слишком сложным.
И в самом деле, более простое решение существует.</p>
<h2 class="title is-4">Сложение чисел</h2>
<p>Как оказалось, достаточно просто указать Angular, чтобы он оперировал со значениями, как с числами.
Мы просто добавляем <code>type=&quot;number&quot;</code> к каждому элементу <code>input</code>:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/add_numbers.html">examples/angular/add_numbers.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
  &lt;input ng-model=&quot;a&quot; type=&quot;number&quot;&gt;
  &lt;input ng-model=&quot;b&quot; type=&quot;number&quot;&gt;
  &lt;h1&gt;{{ a + b }}&lt;/h1&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/add_numbers.html">view</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Hello World с модулем AngularJS и контроллером</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-09-06T16:48:01Z</updated>
    <pubDate>2015-09-06T16:48:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/hello-world-with-angular-controller" />
    <id>https://rust.code-maven.com/hello-world-with-angular-controller</id>
    <content type="html"><![CDATA[<p>В статье про <a href="/getting-started-with-angularjs">начало работы с AngularJS</a> мы видели, как работают простые выражения,
затем мы создали нашу <a href="/angularjs-first-binding">первую связку</a>. В этот раз мы рассмотрим два примера,
используя модуль AngularJS и контроллеры.</p>
<h2 class="title is-4">Контроллер Hello World</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/hello_world_controller.html">examples/angular/hello_world_controller.html</a></strong></p>
<pre><code class="language-html">
&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;hello_world_controller.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app=&quot;HelloWorldApp&quot;&gt;
    &lt;div ng-controller=&quot;HelloWorldController&quot;&gt;
        &lt;h1&gt;{{greeting}}&lt;/h1&gt;
    &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/hello_world_controller.html">view</a></p>
<p>После загрузки <code>angular.js</code> мы добавили еще немного кода JavaScript.
Мы можем встроить это в HTML-файл, используя парный тег <code>script</code> или,
как рекомендовано и как мы делаем в этом примере, мы можем поместить этот код во внешний JavaScript файл.
Единственное требование - мы загружаем его <code>после</code> загрузки <code>angular.js</code>.</p>
<p>Код JavaScript выглядит так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/hello_world_controller.js">examples/angular/hello_world_controller.js</a></strong></p>
<pre><code class="language-js">angular.module('HelloWorldApp', [])
   .controller('HelloWorldController', function($scope) {
       $scope.greeting = &quot;Hello World&quot;;
});

</code></pre>
<p>Сначала мы создаем объект <code>angular.module</code>, а вслед за этим создаем <code>controller</code>.
<code>Module</code> принимает два параметра: первый это имя, которое мы выбрали для этого модуля.
Это может быть любая строка, но так как это имя приложения Angular, так что хорошо бы назвать это как-то с &quot;App&quot;.</p>
<p>Мы собираемся использовать это имя в HTML файле как значение атрибута <code>ng-app</code>.
(Раньше мы не указывали имя для этого атрибута, поэтому использовалось приложение по умолчанию)</p>
<p>Второй параметр для <code>module</code> это список зависимостей. Сейчас мы оставим его пустым.</p>
<p><code>Controller</code> также имеет два параметра. Первый - это его имя. Обычно это какое-нибудь слово,
оканчивающееся на &quot;Controller&quot;. Второй параметр это функция, реализующая контроллер.
Она будет выполнена сразу как загрузится контроллер. Окружение передается в переменной <code>$scope</code>.
Модели и переменные, которые мы использовали ранее, это атрибуты этого объекта.
Теперь когда мы создали новый атрубут <code>$scope.greeting</code> и присвоили ему значение,
мы сможем получить доступ к нему из нашего HTML.</p>
<p>Чтобы подключиться к нашему модулю и контроллеру мы должны создать HTML элемент
с атрибутом <code>ng-app</code>, содержащим имя нашего модуля, и внутри этого элемента
мы должны создать другой HTML элемент с атрибутом <code>ng-controller</code>, содержащим имя нашего контроллера.</p>
<p>Это две метки области, которой соответствует <code>$scope</code>.</p>
<p>Это был очень простой пример с фиксированным значением атрибута, который используется в выражении.</p>
<h2 class="title is-4">Контроллер Hello user</h2>
<p>Давайте посмотрим на более сложный пример, в котором мы получаем введенное пользователем значение и обрабатываем
его в контроллере. Обработка будет очень простой, просто конкатенация с заданной строкой.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/hello_user_controller.js">examples/angular/hello_user_controller.js</a></strong></p>
<pre><code class="language-js">angular.module('HelloUserApp', [])
      .controller('HelloUserController', function($scope) {
          $scope.NameChange = function () {
              $scope.greeting = &quot;Hello &quot; + $scope.name;
          };
      });

</code></pre>
<p>В этом примере атрибут <code>NameChange</code>, который мы добавили в <code>$scope</code>, это функция,
и эта функция будет создавать значение для атрибута <code>$scope.greeting</code>, используя
значение из <code>$scope.name</code>.</p>
<p>HTML</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/hello_user_controller.html">examples/angular/hello_user_controller.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;hello_user_controller.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app=&quot;HelloUserApp&quot;&gt;
    &lt;div ng-controller=&quot;HelloUserController&quot;&gt;
        &lt;input ng-model=&quot;name&quot; ng-keyup=&quot;NameChange()&quot;&gt;
        &lt;h1&gt;{{greeting}}&lt;/h1&gt;
        &lt;h2&gt;{{name}}&lt;/h2&gt;
    &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/hello_user_controller.html">view</a></p>
<p>Атрибут <code>ng-model=&quot;name&quot;</code> связывает введенные данные элемента с переменной <code>$scope.name</code>.</p>
<p>Атрибут <code>ng-keyup=&quot;NameChange()&quot;</code> связывает событие <code>keyup</code> страницы HTML с функцией определенной в <code>$scope.NameChange</code>.
Это означает, что функция будет вызвана каждый раз, когда содержимое поля ввода будет меняться.</p>
<p>Два выражения в HTML коде <code>{{name}}</code> и <code>{{greeting}}</code> будут отображать содержимое <code>$scope.name</code> и <code>$scope.greeting</code> соответственно.</p>
<p>В результате, если мы напишем &quot;Foo&quot; в поле ввода, наша страница отобразит &quot;Hello Foo&quot; в теге <code>h1</code> и <code>Foo</code> в теге <code>h2</code>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Голосовалка на Flask</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-08-29T17:37:01Z</updated>
    <pubDate>2015-08-29T17:37:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/a-polling-station-with-flask" />
    <id>https://rust.code-maven.com/a-polling-station-with-flask</id>
    <content type="html"><![CDATA[<p>В этой серии статей мы будем делать приложение для запуска голосований и, может быть, даже опросов с использованием Flask.</p>
<p>Дополнительно к этой статье, вы можете следить за развитием приложения в <a href="https://github.com/szabgab/flask-poll">этом</a> репозитории.</p>
<p>Давайте начнем с создания простого Flask-based приложения.</p>
<p>Мы создали новую директорию и в ней создали такой скрипт на Python:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll1/poll.py">examples/flask/poll1/poll.py</a></strong></p>
<pre><code class="language-python">from flask import Flask, render_template
import os
app = Flask(__name__)

@app.route('/')
def root():
    return render_template('poll.html')

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)


</code></pre>
<p>Мы создали обработчик для <code>/</code>, который вызывает функцию <code>root()</code>.
Эта функция возвращает страницу, собранную из шаблона <code>poll.html</code>. Сам шаблон находится в поддиректории <code>templates/</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll1/templates/poll.html">examples/flask/poll1/templates/poll.html</a></strong></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Poll&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Poll&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;

</code></pre>
<p>Сейчас директория нашего проекта выглядит вот так:</p>
<pre><code>$ tree
.
├── poll.py
└── templates
    └── poll.html
</code></pre>
<p>Теперь мы можем запустить приложение командой <code>python poll.py</code>, которая скажет нам:</p>
<pre><code> * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
</code></pre>
<p>Если открыть браузер по полученному адресу, то мы увидим следующее:</p>
<img src="/img/flask_poll_1.png" alt="Flask poll" />
<p>Немного, но оно работает. Прям как <a href="/hello-world-with-flask-and-python">hello world</a>, но с шаблоном.</p>
<pre><code>$ git init
$ git add .
$ git commit -m &quot;step 1 - hello world with a template&quot;
</code></pre>
<p><a href="https://github.com/szabgab/flask-poll/commit/c78124201aeb49a2853cac6dc9d28fc1ee03edb3">commit</a>.</p>
<h2 class="title is-4">Отображение голосования</h2>
<p>Чтобы провести голосование, нам нужен вопрос и варианты ответа для выбора.
Возможно, позже это все будет перемещено в конфигурационный файл, но сейчас давайте просто создадим словарь с данными
в нашем приложении.</p>
<pre><code class="language-python">poll_data = {
   'question' : 'Which web framework do you use?',
   'fields'   : ['Flask', 'Django', 'TurboGears', 'web2py', 'pylonsproject']
}
</code></pre>
<p>Мы также изменили вызов рендеринга шаблона <code>render_template</code> и теперь
передаем туда наш словарь под ключом <code>data</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll2/poll.py">examples/flask/poll2/poll.py</a></strong></p>
<pre><code class="language-python">from flask import Flask, render_template
import os
app = Flask(__name__)

poll_data = {
   'question' : 'Which web framework do you use?',
   'fields'   : ['Flask', 'Django', 'TurboGears', 'web2py', 'pylonsproject']
}

@app.route('/')
def root():
    return render_template('poll.html', data=poll_data)

if __name__ == &quot;__main__&quot;:
    app.run(debug=True)


</code></pre>
<p>В шаблоне мы используем выражение <code>{{ data.question }}</code>, чтобы добавить вопрос.
Мы используем эту конструкцию для двух случаев: заголовка нашей страницы, который вы видите во вкладке браузера,
и в качестве элемента <code>h1</code>.</p>
<p>Затем мы создаем форму с <code>action=&quot;/poll&quot;&gt;</code>, это значит, что мы должны создать новый обработчик для этого
запроса в нашем приложении.
Внутри формы мы создаем несколько элементов <code>radio</code> для ввода данных (выбора значений).
По одному для каждого варианта ответа. Тип поля radio хорошо подходит, когда нам нужно получить
ровно один ответ.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll2/templates/poll.html">examples/flask/poll2/templates/poll.html</a></strong></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{ data.question }}&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;{{ data.question }}&lt;/h1&gt;
&lt;form action=&quot;/poll&quot;&gt;
  {% for e in data.fields %}
     &lt;input type=&quot;radio&quot; name=&quot;field&quot; value=&quot;{{ e }}&quot;&gt; {{ e }}&lt;br&gt;
  {% endfor %}
  &lt;input type=&quot;submit&quot; value=&quot;Vote&quot; /&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;

</code></pre>
<p>После всех этих изменений зайдем на нашу страницу, и вот что мы увидим:</p>
<img src="/img/flask_poll_2.png" alt="Flask poll" />
<p>Если выбрать один из элементов и нажать кнопку &quot;Vote&quot;, то получим такой ответ:</p>
<img src="/img/flask_poll_2_2.png" alt="Flask poll" />
<p>Это значит, что мы еще не добавили обработчик для <code>/poll</code>. Давайте сделаем его.</p>
<pre><code>$ git add .
$ git commit -m &quot;add poll data and display it&quot;
</code></pre>
<p><a href="https://github.com/szabgab/flask-poll/commit/2a293a4051bc4ba3ae4c8b95dd1e02b669a76b82">commit</a></p>
<h2 class="title is-4">Принимаем результаты голосования</h2>
<p>Первый шаг это добавление хендлера для обработки <code>/poll</code>, прием значения поля <code>field</code> формы с помощью
<code>request.args.get('field')</code>. Для начала, просто вернем выбранное значение пользователю:</p>
<pre><code class="language-python">@app.route('/poll')
def poll():
    vote = request.args.get('field')
    return vote 
</code></pre>
<p>Мы можем перезагрузить страницу в браузере и увидим там выбранный нами вариант:</p>
<img src="/img/flask_poll_3_1.png" alt="Flask poll" />
<p>Следующий шаг - сохранение результатов. Для простоты мы будем использовать обычный файл.
В начале скрипта <code>poll.py</code> мы добавим имя файла в виде переменной:
<code>filename = 'data.txt'</code> (всегда хорошо иметь переменные для таких случаев),
а затем открываем файл, чтобы добавить туда контент (используя <code>'a'</code> в качестве аргумента для функции <code>open</code>),
записываем результат в файл и закрываем файл.</p>
<p>Мы собираемся хранить по одному результату голосований в строке. Тогда будет легко собирать данные впоследствии.</p>
<pre><code class="language-python">@app.route('/poll')
def poll():
    vote = request.args.get('field')

    out = open(filename, 'a')
    out.write( vote + '\n' )
    out.close()

    return vote 
</code></pre>
<p>Теперь, если мы обновим веб-страницу, наш выбранный вариант сохранится в файл данных, но мы все еще получаем обратно выбранный вариант.
Вместо этого, давайте добавим более дружественную страницу благодарности:</p>
<pre><code class="language-python">    return render_template('thankyou.html', data=poll_data)
</code></pre>
<p>Теперь Flask скрипт выглядит вот так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll3/poll.py">examples/flask/poll3/poll.py</a></strong></p>
<pre><code class="language-python">from flask import Flask, render_template, request
import os
app = Flask(__name__)

poll_data = {
   'question' : 'Which web framework do you use?',
   'fields'   : ['Flask', 'Django', 'TurboGears', 'web2py', 'pylonsproject']
}
filename = 'data.txt'

@app.route('/')
def root():
    return render_template('poll.html', data=poll_data)

@app.route('/poll')
def poll():
    vote = request.args.get('field')

    out = open(filename, 'a')
    out.write( vote + '\n' )
    out.close()

    return render_template('thankyou.html', data=poll_data)


if __name__ == &quot;__main__&quot;:
    app.run(debug=True)


</code></pre>
<p>Шаблон страницы благодарности вот такой:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll3/templates/thankyou.html">examples/flask/poll3/templates/thankyou.html</a></strong></p>
<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{ data.question }}&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Thank you for submitting your vote for&lt;/h1&gt;
{{ data.question }}

&lt;/body&gt;
&lt;/html&gt;


</code></pre>
<pre><code>$ git add poll.py templates/thankyou.html
$ git commit -m &quot;save the vote and thank the voter&quot;
</code></pre>
<p><a href="https://github.com/szabgab/flask-poll/commit/ba5a516c7e1506d7c25807ebd18e9ef388df2b9b">commit</a></p>
<p>Эта версия голосовалки уже работает, но давайте добавим еще одну страницу - с результатами голосования.</p>
<h2 class="title is-4">Отображение результатов</h2>
<p>Для отображения результатов мы создадим еще один обработчик (для пути с именем <code>/results</code>), который будет читать файл с данными
и показывать количество голосов по каждому варианту.</p>
<p>Вот наш обработчик:</p>
<pre><code class="language-python">@app.route('/results')
def show_results():
    votes = {}
    for f in poll_data['fields']:
        votes[f] = 0

    f  = open(filename, 'r')
    for line in f:
        vote = line.rstrip(&quot;\n&quot;)
        votes[vote] += 1

    return render_template('results.html', data=poll_data, votes=votes)
</code></pre>
<p>Сначала мы создали словарь <code>votes</code>, куда собираемся собрать количество голосов.
Затем мы идем по списку ожидаемых значений из исходного списка значений и создаем там элементы для каждого из них с количеством 0.
Это будет гарантией, что каждый элемент из нашего списка вариантов представлен в результатах,
даже есть за него никто не проголосовал.</p>
<p>Затем мы открываем файл с данными для чтения и читаем построчно. Перед обновлением нашего словаря <code>votes</code>,
мы должны удалить символы перевода строки с помощью <code>line.rstrip(&quot;\n&quot;)</code>.</p>
<p>Затем мы передаем собранные результаты голосований в функцию <code>render_template</code>.</p>
<p>Шаблон выглядит вот так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll4/templates/results.html">examples/flask/poll4/templates/results.html</a></strong></p>
<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{ data.question }}&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Results for&lt;/h1&gt;
{{ data.question }}

&lt;ul&gt;
{% for e in votes %}
  &lt;li&gt;{{ e }} {{ votes[e] }}&lt;/li&gt;
{% endfor %}
&lt;/ul&gt;

&lt;/body&gt;
&lt;/html&gt;



</code></pre>
<p>и вот скрипт целиком:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/poll4/poll.py">examples/flask/poll4/poll.py</a></strong></p>
<pre><code class="language-python">from flask import Flask, render_template, request
import os
app = Flask(__name__)

poll_data = {
   'question' : 'Which web framework do you use?',
   'fields'   : ['Flask', 'Django', 'TurboGears', 'web2py', 'pylonsproject']
}
filename = 'data.txt'

@app.route('/')
def root():
    return render_template('poll.html', data=poll_data)

@app.route('/poll')
def poll():
    vote = request.args.get('field')

    out = open(filename, 'a')
    out.write( vote + '\n' )
    out.close()

    return render_template('thankyou.html', data=poll_data)

@app.route('/results')
def show_results():
    votes = {}
    for f in poll_data['fields']:
        votes[f] = 0

    f  = open(filename, 'r')
    for line in f:
        vote = line.rstrip(&quot;\n&quot;)
        votes[vote] += 1

    return render_template('results.html', data=poll_data, votes=votes)



if __name__ == &quot;__main__&quot;:
    app.run(debug=True)


</code></pre>
<p>Если мы перейдем по ссылке <a href="http://127.0.0.1:5000/results">http://127.0.0.1:5000/results</a>, то увидим такой ответ:</p>
<img src="/img/flask_poll_4.png" alt="Flask poll" />
<pre><code>$ git add poll.py templates/results.html
$ git commit -m &quot;show the results&quot;
</code></pre>
<p><a href="https://github.com/szabgab/flask-poll/commit/9c0f04d7c7d80da68c681dfec2c0f7ad4f4d605a">commit</a></p>
<h2 class="title is-4">Что дальше?</h2>
<p><a href="/testing-the-flask-poll">Тестирование голосовалки на Flask</a>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>AngularJS - первая связка</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-08-01T14:27:01Z</updated>
    <pubDate>2015-08-01T14:27:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/angularjs-first-binding" />
    <id>https://rust.code-maven.com/angularjs-first-binding</id>
    <content type="html"><![CDATA[<p>Теперь, когда мы создали наше <a href="/getting-started-with-angularjs">самое первое выражение в AngularJS</a>,
пришло время для следующего шага. Время для чего-то гораздо более интересного. Мы собираемся
связать поле ввода с выражением, которое будет автоматически показывать все, что мы вводим.</p>
<h2 class="title is-4">Минимальный пример &quot;Hello User&quot;</h2>
<p>Примеры &quot;Hello World&quot; обычно достаточно скучны из-за линейности. Просто показывают строку, которая является частью кода.
В этом примере у нас есть элемент <code>input</code>, в котором мы объявили <code>ng-model</code> со значением <code>name</code>.</p>
<pre><code class="language-html">&lt;input ng-model=&quot;name&quot;&gt;
</code></pre>
<p>Как только мы это сделали, то можем использовать атрибут <code>name</code> в выражениях Angular: <code>{{ name }}</code>
Например:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/minimal_hello_user.html">examples/angular/minimal_hello_user.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
  &lt;input ng-model=&quot;name&quot;&gt;
  &lt;h1&gt;Hello, {{name}}&lt;/h1&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/minimal_hello_user.html">view</a></p>
<p>Если вы откроете этот пример, то увидите поле для ввода. По мере ввода текста в поле,
вы будете видеть появляющийся текст после слова <b>Hello</b>.</p>
<p>В этом примере вы видите, как связать (<b>bind</b>) элемент ввода и атрибут AngularJS,
который затем можно использовать в выражениях.</p>
<h2 class="title is-4">Полный пример &quot;Hello User&quot;</h2>
<p>Выше представлен самый короткий из возможных примеров использования связи (биндинга) в AngularJS.
Полный пример, по крайней мере более полный, можно найти здесь:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/hello_user.html">examples/angular/hello_user.html</a></strong></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html ng-app&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0, user-scalable=yes&quot;&gt;
    &lt;title&gt;&lt;/title&gt;
    &lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
      &lt;input ng-model=&quot;name&quot; type=&quot;text&quot; placeholder=&quot;Your name please&quot;&gt;
      &lt;h1&gt;Hello, {{name}}&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;

</code></pre>
<p><a href="examples/angular/hello_user.html">view</a></p>
<p>В этой версии у нас есть &quot;настоящая&quot; HTML 5 страница, <code>ng-app</code> объявлен для всего <code>html</code> файла, и элемент <code>input</code>
описан более полно с помощью <code>type</code> и <code>placeholder</code>, чтобы предоставить пользователю подсказки, что ему делать
с этой формой.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Начало работы с AngularJS</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-08-01T13:52:01Z</updated>
    <pubDate>2015-08-01T13:52:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/getting-started-with-angularjs" />
    <id>https://rust.code-maven.com/getting-started-with-angularjs</id>
    <content type="html"><![CDATA[<p><a href="https://angularjs.org/">AngularJS</a> это JavaScript фреймворк, который расширяет HTML.</p>
<p>Здесь мы рассмотрим несколько простых примеров использования AngularJS.
Для лучшего понимания, возможно, вы заходите взглянуть на <a href="http://www.angularjsbook.com/">AngularJS Book</a>
от Chris Smith или <a href="https://www.ng-book.com/">ng-book</a> от Ari Lerner.</p>
<p>Чтобы начать работу с AngularJS, нам нужна HTML страница с тремя вещами:</p>
<h2 class="title is-4">1) Загрузить angular.js</h2>
<p>Нам нужно загрузить файл angular.js с одного из CDN или с локального диска.</p>
<p>Если вы хотите загрузить его с Google CDN, тогда добавьте в HTML такой код:</p>
<pre><code>&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js&quot;&gt;&lt;/script&gt;
</code></pre>
<p>Если хотите использовать Cloudflare CDNjs, тогда такой:</p>
<pre><code>&lt;script src=&quot;http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.min.js&quot;&gt;&lt;/script&gt;
</code></pre>
<p>Также вы можете скачать файл angular.min.js, загрузить его на ваш сервер и подключить вот так:</p>
<pre><code>&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
</code></pre>
<p>В примерах выше я использовал версию 1.4.2 AngularJS, но ко времени, когда вы будете читать эту статью,
у Angular может выйти новый релиз, и, возможно, вы захотите использовать новую версию.</p>
<h2 class="title is-4">2) Добавить ng-app</h2>
<p>Добавьте <code>ng-app</code> к одному из элементов на вашей странице. Все, имеющее этот элемент, будет рассматриваться
как часть AngularJS кода. Мы можем добавить это к элементу <code>html</code>, <code>body</code>,
или даже <code>div</code>, как это сделано в нашем первом примере.</p>
<h2 class="title is-4">3) Добавить выражение AngularJS.</h2>
<p>AngularJS имеет различные элементы. Выражение (<b>expression</b>) это фрагмент кода, помещенный в
<code>{{ }}</code>. Он может содержать ограниченный набор выражений JavaScript.</p>
<p>Теперь мы подошли к нашему первому примеру. Еще даже до написания Hello</p>
<h2 class="title is-4">Hello World с AngularJS</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/hello_world.html">examples/angular/hello_world.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
  Hello {{ &quot;World&quot; }}
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/hello_world.html">view</a></p>
<p>В нашем самом первом примере выражение это просто фиксированная строка. Ничего особенного.
Даже немного оскорбительно.</p>
<p>И результат - <code>Hello World</code>.</p>
<h2 class="title is-4">Простое выражение AngularJS</h2>
<p>В нашем следующем примере выражение это вычисление.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/first_expression.html">examples/angular/first_expression.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
  Hello Angular {{ 19 + 23 }}
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/first_expression.html">view</a></p>
<p>Результат - <code>Hello Angular 42</code>.</p>
<p>Angular выполнил выражение и показал результат.</p>
<p>Запомните, это работает в браузере, так что если вы нажмете &quot;view source&quot;, то увидите
этот код как и обычный html файл.</p>
<h2 class="title is-4">Переменные в выражениях AngularJS</h2>
<p>В следующем все еще очень простом примере, мы сможем увидеть, как можно присваивать значения переменным,
а затем мы сможем использовать эти переменные в выражениях.</p>
<p>Замечание: здесь мы не используем <code>var</code> для присвоения значений переменным, потому что
это на самом деле атрибуты внутреннего объекта AngularJS.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/variables_in_expressions.html">examples/angular/variables_in_expressions.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
  {{ x = 23; y= 19; x + y }}
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/variables_in_expressions.html">view</a></p>
<h2 class="title is-4">Разделим установку переменной и ее использование на два выражения.</h2>
<p>Мы можем даже присвоить значение переменной в одном выражении, а использовать ее в другом.
И не только. Даже расположение этих выражений в HTML не имеет значения.
Как мы можем выдеть в следующем примере, мы можем использовать переменную даже до ее установки:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/assignment_and_expression.html">examples/angular/assignment_and_expression.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
  &lt;div&gt;
  Result
  {{ x + y }}
  &lt;/div&gt;
  &lt;div&gt;
    Assignment:
    {{ x = 23; y= 19 }}
  &lt;/div&gt;
  &lt;div&gt;
    Result
    {{ x + y }}
  &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/assignment_and_expression.html">view</a></p>
<p>Результатом будет:</p>
<pre><code>Result 42
Assignment: 19
Result 42
</code></pre>
<p>Здесь есть некоторая проблема: последний результат выражения, в котором мы присваиваем значение, тоже отображается.
Вот поэтому мы видим 19 на странице.</p>
<p>Для решения проблемы можно добавить другой оператор к выражению присваивания,
который не будет возвращать видимого значения. Это может быть <code>null</code> или <code>''</code> (пустая строка).</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/angular/assignment_and_expression_fixed.html">examples/angular/assignment_and_expression_fixed.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;angular.min.js&quot;&gt;&lt;/script&gt;
&lt;div ng-app&gt;
    &lt;div&gt;
    Result
    {{ x + y }}
    &lt;/div&gt;
  &lt;div&gt;
    Assignment:
    {{ x = 23; y= 19; null}}
  &lt;/div&gt;
  &lt;div&gt;
    Result
    {{ x + y }}
  &lt;/div&gt;
&lt;/div&gt;

</code></pre>
<p><a href="examples/angular/assignment_and_expression_fixed.html">view</a></p>
<p>Результатом будет:</p>
<pre><code>Result 42
Assignment:
Result 42
</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Добавляем сниппеты кода в Atom - текстовый редактор</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-08-01T13:24:01Z</updated>
    <pubDate>2015-08-01T13:24:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/add-code-snippets-to-atom" />
    <id>https://rust.code-maven.com/add-code-snippets-to-atom</id>
    <content type="html"><![CDATA[<p>Сниппеты это великолепная штука в любом редакторе и IDE.
В <a href="https://atom.io/">Atom</a> они достаточно просты в использовании.</p>
<h2 class="title is-4">Как использовать сниппеты в Atom</h2>
<p>В файле вы начинаете набирать префикс существующего сниппета.
Atom покажет список сниппетов, которые совпадают с написанным текстом.
Когда вы прекратите ввод текста, то сможете выбрать один из них, используя стрелки вверх и вниз.</p>
<img src="/img/atom_snippet_use.png" alt="Сниппеты Atom в действии" />
<p>Когда вы нажмете TAB или ENTER, Atom вставит код сниппета на то место, где вы начинали вводить текст.</p>
<p>В Atom есть много предустановленных сниппетов, и также вы можете легко создать свои собственные.</p>
<h2 class="title is-4">Добавляем свой сниппет в Atom</h2>
<p>Ваш собственный сниппет должен быть описан в файле <code>snippets.cson</code>, который находится
в домашней директории. У меня это директория <code>~/.atom/</code>, хотя я об этом даже не знал.
Если я открою меню &quot;Atom&quot;, то там есть пункт <code>Open Your Snippets</code>, который открывает
<code>snippets.cson</code> в вашем любимом редакторе.</p>
<img src="/img/atom_snippet_editor.png" alt="Меню Atom для открытия редактора сниппетов" />
<p>В этом файле вам нужно написать такой код</p>
<pre><code>'.text.html':
  'HTML 5':
    'prefix': 'html'
    'body': '''
    &lt;!DOCTYPE html&gt;
    &lt;html&gt;
      &lt;head&gt;
        &lt;meta charset=&quot;utf-8&quot;&gt;
        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0, user-scalable=yes&quot;&gt;
        &lt;title&gt;&lt;/title&gt;
        &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.3/handlebars.min.js&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;http://code.jquery.com/jquery-1.11.3.min.js&quot;&gt;&lt;/script&gt;

        &lt;link href=&quot;style.css&quot; rel=&quot;stylesheet&quot;&gt;
      &lt;/head&gt;
      &lt;body&gt;

      &lt;/body&gt;
    &lt;/html&gt;
'''
</code></pre>
<p>Это будет работать для html файлов.</p>
<p>Первая строка описывает область, где сниппет должен работать.</p>
<p>Каждый тип файла имеет свою область, и каждое расширение файла привязано к области.
Конкретно область HTML файлов это <code>text.html.basic</code> и следующие расширения файлов рассматриваются
как HTML файлы:
<code>htm, html, kit, shtml, tmpl, tpl, xhtml</code></p>
<p>Я знаю это, потому что открыл <code>Settings</code> (На самом деле, это пункт меню <code>Atom / Preferences</code>)
и среди <code>Packages</code> нашел тот, что обрабатывает HTML файлы. Вот как он выглядит:</p>
<img src="img/atom_html_file_type.png" alt="Типы HTML файлов в Atom" />
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Echo с Flask и Python</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-05-31T16:15:01Z</updated>
    <pubDate>2015-05-31T16:15:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/echo-with-flask-and-python" />
    <id>https://rust.code-maven.com/echo-with-flask-and-python</id>
    <content type="html"><![CDATA[<p>Чтобы показать, как Flask предоставляет доступ к информации, отправляемой пользователем на сервер, мы
собираемся создать очень простое приложение, возвращающее назад полученные данные.</p>
<p>Главная страница содержит форму и кнопку. Если мы введем что-нибудь в поле и нажмем кнопку,
запрос будет отправлен на сервер, который вернем нам обратно введенные данные уже на другой странице.</p>
<p>Всего есть два основных метода отправки данных на сервер через HTTP. Один это использование GET-запроса, другой - POST-запроса.
Сначала давайте посмотрим решение с GET-запросом:</p>
<h2 class="title is-4">Использование GET-запроса</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/echo_get.py">examples/flask/echo_get.py</a></strong></p>
<pre><code class="language-python">from flask import Flask, request
app = Flask(__name__)

@app.route(&quot;/&quot;)
def hello():
    return '&lt;form action=&quot;/echo&quot; method=&quot;GET&quot;&gt;&lt;input name=&quot;text&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Echo&quot;&gt;&lt;/form&gt;'

@app.route(&quot;/echo&quot;)
def echo():
    return &quot;You said: &quot; + request.args.get('text', '')


if __name__ == &quot;__main__&quot;:
    app.run()

</code></pre>
<p>У нас есть два роута (маршрута, пути). Первый, что отвечает на запрос <code>/</code>, отправит нам HTML-сниппет, который мы описали в коде.
Как только мы рассмотрим основные примеры, мы перейдем к использованию шаблонизатора, чтобы разделить HTML и Python, но
для этого примера мы все еще используем HTML, описанный прямо в скрипте.</p>
<p>Этот HTML-сниппет отобразится в нашем браузере как поле для ввода и кнопка. Свойство <code>action</code> элемента <code>form</code>
говорит браузеру, куда отправлять данные, когда пользователь нажмет на кнопку <code>submit</code>.
Свойство <code>method</code> говорит браузеру, какой метод использовать. И хотя <code>GET</code> используется по умолчанию, я
все равно его добавил, чтобы сделать пример более понятным.</p>
<p>В нашем случае имеется в виду, что когда пользователь нажмет на кнопку, браузер отправит <code>GET</code>-запрос на <code>/echo</code>.</p>
<p>Если мы напишем &quot;hello&quot; и нажмем на кнопку, то увидим, что URL в строке адреса браузера сменился на
<code>http://127.0.0.1:5000/echo?text=hello</code></p>
<p>Имя поля &quot;text&quot; это значение атрибута <code>name</code> элемента <code>input</code> в нашем HTML на главной странице.
&quot;hello&quot; это то, что мы там написали.</p>
<p>Второй путь привязывает URL <code>/echo</code> к функции <code>echo</code>.</p>
<p>Самая интересная часть в этой функции это использование контекста <a href="http://flask.pocoo.org/docs/0.10/reqcontext/">request</a>.
<code>request</code> имеет атрибут с именем <code>args</code>, который является словарем и содержит данные, полученные в URL.
В нашем случае там будет ключ &quot;text&quot; со значением &quot;hello&quot;.</p>
<p>Вместо прямого доступа к значению ключа &quot;text&quot; с помощью <code>request.args['text']</code> мы используем метод <code>get</code>
и сразу же указываем пустое значение как значение по умолчанию. <code>request.args.get('text', '')</code></p>
<p>Причина, по которой мы выбираем второй способ, кроется в самом Python - если мы пытаемся получить значение ключа, которого
не существует, даже просто для чтения, Python генерирует исключение. (Другими словами, Python
не предоставляет <a href="https://perlmaven.com/autovivification">/autovivification</a>.)</p>
<p>Пользователь может просто исправить значение в адресной строке. Если он решит убрать вообще все атрибуты
и отправить запрос на <code>http://127.0.0.1:5000/echo</code>, тогда запрос сгенерирует исключение и
в браузере будет сообщение <b>Bad Request</b>.</p>
<p>Мы могли бы добавить код, ловящий такие исключения, но кажется проще вызывать <code>get</code>
и если там не будет такого ключа, то позволить ему вернуть пустую строку.
Тогда эта функция просто вернет обратно текст &quot;You said: &quot; и дальше то, что ввел пользователь.</p>
<h2 class="title is-4">Использование POST-запроса</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/echo_post.py">examples/flask/echo_post.py</a></strong></p>
<pre><code class="language-python">from flask import Flask, request
app = Flask(__name__)

@app.route(&quot;/&quot;)
def hello():
    return '&lt;form action=&quot;/echo&quot; method=&quot;POST&quot;&gt;&lt;input name=&quot;text&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;Echo&quot;&gt;&lt;/form&gt;'

@app.route(&quot;/echo&quot;, methods=['POST'])
def echo():
    return &quot;You said: &quot; + request.form['text']


if __name__ == &quot;__main__&quot;:
    app.run()

</code></pre>
<p>Здесь было немного изменений:</p>
<ol>
  <li>В описанном HTML мы заменили метод `GET` на `POST`</li>
  <li>В определении роута (маршрута) мы явно указали обрабатывать POST-запрос: `@app.route("/echo", methods=['POST'])>`</li>
  <li>Мы получаем данные, отправленные пользователем, из словаря `form` объекта `request`</li>
</ol>
<p>В этом случае Flask рекомендуем обращаться к ключам словаря <code>form</code> напрямую, используя квадратные скобки: <code>request.form['text']</code>.</p>
<p>Причина в том, что для обычного пользователя отправить форму с неверными ключами намного сложнее, но если такое случилось, то
лучше сгенерировать исключение. Нам не нужно делать это вручную, потому что Python его нам сгенерирует.</p>
<p>Если мы не хотим получать эти исключения, тогда мы можем использовать код, похожий на предыдущий:
<code>request.form.get('text', '')</code></p>
<p>Перед запуском нового скрипта убедитесь, что предыдущий остановлен. Иначе вы получите противное исключение:</p>
<pre><code> * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Traceback (most recent call last):
  File &quot;examples/flask/echo_post.py&quot;, line 14, in &lt;module&gt;
    app.run()
  File &quot;/Library/Python/2.7/site-packages/flask/app.py&quot;, line 772, in run
    run_simple(host, port, self, **options)
  File &quot;/Library/Python/2.7/site-packages/werkzeug/serving.py&quot;, line 624, in run_simple
    inner()
  File &quot;/Library/Python/2.7/site-packages/werkzeug/serving.py&quot;, line 602, in inner
    passthrough_errors, ssl_context).serve_forever()
  File &quot;/Library/Python/2.7/site-packages/werkzeug/serving.py&quot;, line 512, in make_server
    passthrough_errors, ssl_context)
  File &quot;/Library/Python/2.7/site-packages/werkzeug/serving.py&quot;, line 440, in __init__
    HTTPServer.__init__(self, (host, int(port)), handler)
  File &quot;/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py&quot;, line 419, in __init__
    self.server_bind()
  File &quot;/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/BaseHTTPServer.py&quot;, line 108, in server_bind
    SocketServer.TCPServer.server_bind(self)
  File &quot;/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py&quot;, line 430, in server_bind
    self.socket.bind(self.server_address)
  File &quot;/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py&quot;, line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 48] Address already in use
</code></pre>
<p>По крайней мере, в отличие от <a href="/getting-started-with-nodejs">Node.js</a>, здесь показано нормальное объяснение
на последней строке ошибки.</p>
<p>Как только вы успешно запустили новый скрипт, нужно также не забыть перезагрузить страницу по адресу <a href="http://127.0.0.1:5000/">http://127.0.0.1:5000/</a>.</p>
<p>Если этого не сделать, то там будет содержаться предыдущий HTML код, который отправляет данные, используя <code>GET</code>.
Если нажать на кнопку из старого HTML, оставшегося в браузере, а новый скрипт уже запущен, тогда новый скрипт выдаст следующую ошибку в браузер:</p>
<pre><code>Method Not Allowed

The method is not allowed for the requested URL.
</code></pre>
<p>Это случилось, потому что браузер отправил <code>GET</code>-запрос, но новый скрипт обрабатывает только метод <code>POST</code> для URL <code>/echo</code>.</p>
<h2 class="title is-4">Как вызвать ошибку в POST-запросе?</h2>
<p>Как мы увидели, если использовать <code>GET</code>-запрос, то пользователь легко может отправить некорректные данные с отсутствующими
или лишними полями. Пользователь может просто загрузить <a href="http://127.0.0.1:5000/echo">http://127.0.0.1:5000/echo</a> или <a href="http://127.0.0.1:5000/echo?txt=hello">http://127.0.0.1:5000/echo?txt=hello</a>.</p>
<p>Если использовать <code>POST</code>-запрос, тогда отправить неверный запрос будет сложнее.
Это нельзя сделать просто из браузера, хотя для таких вещей есть специальные плагины.</p>
<p>С другой стороны очень просто отправить некорректный запрос, используя <code>curl</code>
из командной строки Linux/Unix:</p>
<p>Отправим POST-запрос без данных и посмотрим ошибку:</p>
<pre><code>$ curl --data '' http://127.0.0.1:5000/echo

&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 3.2 Final//EN&quot;&gt;
&lt;title&gt;400 Bad Request&lt;/title&gt;
&lt;h1&gt;Bad Request&lt;/h1&gt;
&lt;p&gt;The browser (or proxy) sent a request that this server could not understand.&lt;/p&gt;
</code></pre>
<p>Отправим POST-запрос с некорректными данным (имя поля будет txt вместо text), и увидим ошибку:</p>
<pre><code>$ curl --data 'txt=world' http://127.0.0.1:5000/echo

&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 3.2 Final//EN&quot;&gt;
&lt;title&gt;400 Bad Request&lt;/title&gt;
&lt;h1&gt;Bad Request&lt;/h1&gt;
&lt;p&gt;The browser (or proxy) sent a request that this server could not understand.&lt;/p&gt;
</code></pre>
<p>... и просто покажу, что проблема не в <code>curl</code>. Если мы отправим нормальные данные, то получим нормальный ответ:</p>
<pre><code>$ curl --data 'text=world' http://127.0.0.1:5000/echo

You said: world
</code></pre>
<h2 class="title is-4">Вывод</h2>
<p>Вы можете получить доступ к значениям, переданным в URL, с помощью <code>request.args</code>, а к значениям, переданным через POST-request - с помощью <code>request.form</code>.</p>
<p>Рекомендованный способ доступа к значениям: через <code>request.args.get('key', '')</code> для GET-запросов и <code>request.form['key']</code> для POST-запросов, хотя мы можем использовать
любой.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Hello World с Flask и Python</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-05-16T09:33:01Z</updated>
    <pubDate>2015-05-16T09:33:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/hello-world-with-flask-and-python" />
    <id>https://rust.code-maven.com/hello-world-with-flask-and-python</id>
    <content type="html"><![CDATA[<p><a href="http://flask.pocoo.org/">Flask</a> это микрофреймворк для Python, основанный на
<a href="http://werkzeug.pocoo.org/">Werkzeug</a>, <a href="http://jinja.pocoo.org/">Jinja 2</a> и хороших намерениях.</p>
<p>В этой статье мы рассмотрим пример &quot;Hello World&quot; на Flask, который описан на главной странице сайта этого фреймворка.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/flask/hello_world.py">examples/flask/hello_world.py</a></strong></p>
<pre><code class="language-python">from flask import Flask
app = Flask(__name__)

@app.route(&quot;/&quot;)
def hello():
    return &quot;Hello World!&quot;

if __name__ == &quot;__main__&quot;:
    app.run()


</code></pre>
<p>После установки Flask с помощью <code>pip install Flask</code> я могу запустить приведенный выше скрипт через командную строку:</p>
<pre><code>$ python examples/flask/hello_world.py 
</code></pre>
<p>И увижу такой ответ:</p>
<pre><code>* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
</code></pre>
<p>Затем я открыл браузер по указанному адресу и там действительно отображался &quot;Hello World!&quot;, тем временем в консоли я увидел:</p>
<pre><code>127.0.0.1 - - [03/Feb/2015 09:43:14] &quot;GET / HTTP/1.1&quot; 200 -
127.0.0.1 - - [03/Feb/2015 09:43:14] &quot;GET /favicon.ico HTTP/1.1&quot; 404 -
</code></pre>
<p>Первая запись это мой запрос, вторая запись относится к браузеру, попытавшемуся загрузить иконку сайта.
В конце первой строки приведен <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes">HTTP-статус 200</a>,
который указывает на успешное выполнение запроса, вторая строка заканчивается HTTP-статусом 404, обозначающим &quot;Not found&quot;.</p>
<p>Код приложения выглядит достаточно очевидным.</p>
<p>Мы объявили функцию с произвольным именем (<code>hello</code>), и использовали декоратор <code>@app.route(&quot;/&quot;)</code>, чтобы связать
запрос на <code>/</code> с этой функцией.</p>
<pre><code class="language-python">@app.route(&quot;/&quot;)
def hello():
    return &quot;Hello World!&quot;
</code></pre>
<p>Когда Flask запущен, он принимает HTTP-запросы, а затем перенаправляет их на функции, основываясь на пути, указанном в запросе.
Таким образом код выше означает - если запрос приходит на <code>/</code>, тогда запустить функцию <code>hello</code>.</p>
<p>И в конце скрипта мы видим следующее:</p>
<pre><code class="language-python">if __name__ == &quot;__main__&quot;:
    app.run()
</code></pre>
<p>Код <code>app.run()</code> запускает веб-сервер с приложением, основанным на Flask.
Код <code>if __name__ == &quot;__main__&quot;:</code> позволяет запустить веб-сервер только в случае, если этот код запускается как скрипт.</p>
<p>Это позволит нам использовать повторно код из этого файла как часть другого веб-приложения на Flask.</p>
<p>(В Perl такое поведение называют <a href="http://www.masteringperl.org/category/chapters/modulinos/">Modulino</a>.)</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Условия в Handlebars</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-05-11T09:52:01Z</updated>
    <pubDate>2015-05-11T09:52:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/handlebars-conditionals" />
    <id>https://rust.code-maven.com/handlebars-conditionals</id>
    <content type="html"><![CDATA[<p>Шаблонизатор <a href="http://handlebarsjs.com/">Handlebars</a> для JavaScript предоставляет условный оператор <code>if</code> (так же возможно использование и <code>else</code>),
но оператор <code>if</code> может обрабатывать только единственное значение (не выражение). Вы можете написать</p>
<pre><code>{{#if name}}
..
{{/if}}
</code></pre>
<p>но не можете написать</p>
<pre><code>{{#if name == 'Foo'}}
..
{{/if}}
</code></pre>
<p>Давайте создадим хелпер (обработчик) для <a href="/handlebars-helpers">Handlebars</a>, который будет предоставлять такую функциональность.</p>
<h2 class="title is-4">Условие if</h2>
<p>Но перед тем, как создавать хелпер, давайте посмотрим на полноценный пример с использованием оператора <code>if</code>.
В объекте есть два значения: cond1 и cond2, true и false соответственно. Остальная часть кода это просто получение шаблона
и обработка данных в Handlebars.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_if.js">examples/js/handlebars_if.js</a></strong></p>
<pre><code class="language-js">var data = {
   'cond1'  : true,
   'cond2'  : false,
};

document.getElementById('show').addEventListener('click', function () {
    var source = document.getElementById('text-template').innerHTML;
    var template = Handlebars.compile(source);
    var html = template(data);
    document.getElementById('content').innerHTML = html;
});


</code></pre>
<p>Шаблон имеет два фрагмента типа этого, каждый из которых используется для своей переменной.</p>
<pre><code>{{#if cond1}}
    true
{{else}}
    false
{{/if}}
</code></pre>
<p>Полный html код такой:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_if.html">examples/js/handlebars_if.html</a></strong></p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Handlebars conditionals&lt;/title&gt;

  &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    &lt;br&gt;#if cond1 (expected true)
    {{#if cond1}}
       true
    {{else}}
      false
    {{/if}}

    &lt;br&gt;#if cond2 (expected false)
    {{#if cond2}}
      true
    {{else}}
      false
    {{/if}}
  &lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;
&lt;button id=&quot;show&quot;&gt;Show&lt;/button&gt;
&lt;hr&gt;
&lt;div id=&quot;content&quot;&gt;&lt;/div&gt;


&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;/try/examples/js/handlebars_helpers_if_eq.js&quot;&gt;&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;



</code></pre>
<p><a href="examples/js/handlebars_if.html">view</a></p>
<p>Вы можете посмотреть его работу, нажав на ссылку &quot;Try&quot; (откроется в новом окне). Кнопка &quot;show&quot; запускает обработку.</p>
<h2 class="title is-4">if_eq</h2>
<p>В следующем примере мы реализуем <a href="/handlebars-helpers">хелпер Handlebars</a> с именем
<code>if_eq</code>. Он ожидает два параметра и будет сравнивать их с помощью <code>==</code>.
Хелпер выглядит вот так:</p>
<pre><code class="language-javascript">Handlebars.registerHelper('if_eq', function(a, b, opts) {
    if (a == b) {
        return opts.fn(this);
    } else {
        return opts.inverse(this);
    }
});
</code></pre>
<p>Шаблон, использующий наш хелпер, выглядит вот так: (<code>name</code> это атрибут, передаваемый в функцию <code>template</code>.)</p>
<pre><code>{{#if_eq name 'Foo'}}
      true
{{else}}
      false
{{/if_eq}}
</code></pre>
<p>Файл с JavaScript также содержит объект с данными и код, который у нас был раньше (объединяющий шаблон и данные):</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_helpers_if_eq.js">examples/js/handlebars_helpers_if_eq.js</a></strong></p>
<pre><code class="language-js">var data = {
   'name'   : 'Foo',
};

document.getElementById('show').addEventListener('click', function () {
    var source = document.getElementById('text-template').innerHTML;
    var template = Handlebars.compile(source);
    var html = template(data);
    document.getElementById('content').innerHTML = html;
});

Handlebars.registerHelper('if_eq', function(a, b, opts) {
    if (a == b) {
        return opts.fn(this);
    } else {
        return opts.inverse(this);
    }
});


</code></pre>
<p>Весь HTML, включая шаблон, выглядит так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_helpers_if_eq.html">examples/js/handlebars_helpers_if_eq.html</a></strong></p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Handlebars conditionals&lt;/title&gt;

  &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    &lt;br&gt;#if_eq name Foo (expected true)
    {{#if_eq name 'Foo'}}
      true
    {{else}}
      false
    {{/if_eq}}
    
    &lt;br&gt;#if_eq name 'Bar' (expected false)
    {{#if_eq name 'Bar'}}
       true
    {{else}}
       false
    {{/if_eq}}
  &lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;
&lt;button id=&quot;show&quot;&gt;Show&lt;/button&gt;
&lt;hr&gt;
&lt;div id=&quot;content&quot;&gt;&lt;/div&gt;


&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;/try/examples/js/handlebars_helpers_if_eq.js&quot;&gt;&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;


</code></pre>
<p><a href="examples/js/handlebars_helpers_if_eq.html">view</a></p>
<p>Вы можете попробовать пример, нажав на ссылку &quot;Try&quot;.</p>
<h2 class="title is-4">Uncaught Error: if_eq doesn't match if - 3:7</h2>
<p>Мне потребовалось некоторое время, чтобы понять в чем же дело, когда я увидел эту ошибку.
Возможно, что-то заблокировало мой разум, я не уверен. Сможете ли вы определить проблему в этом примере:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_helpers_if_eq_typo.html">examples/js/handlebars_helpers_if_eq_typo.html</a></strong></p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Handlebars conditionals&lt;/title&gt;

  &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    &lt;br&gt;#if_eq name Foo (expected true)
    {{#if_eq name 'Foo'}}
      true
    {{else}}
      false
    {{/if}}
    
    &lt;br&gt;#if_eq name 'Bar' (expected false)
    {{#if_eq name 'Bar'}}
       true
    {{else}}
       false
    {{/if_eq}}
  &lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;
&lt;button id=&quot;show&quot;&gt;Show&lt;/button&gt;
&lt;hr&gt;
&lt;div id=&quot;content&quot;&gt;&lt;/div&gt;


&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;/try/examples/js/handlebars_helpers_if_eq.js&quot;&gt;&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;


</code></pre>
<p><a href="examples/js/handlebars_helpers_if_eq_typo.html">view</a></p>
<p>Это случилось, когда я начал преобразовывать оператор <code>if</code> в условие <code>if_eq</code>, но я заменил только открывающий оператор
<code>{{#if ...}}</code> на <code>{{#if_eq ...}}</code>, но не заменил закрывающий оператор, который остался таким - <code>{{/if}}/hl&gt;. Таким образом, ошибка говорит нам, что </code>if_eq<code>не соответствует</code>if`. Возможно, если бы ключевые слова были как-то выделены,
все было бы проще.</p>
<p>В любом случае, будьте осторожны с такими опечатками. Это просто трата времени. Делайте более интересные ошибки!</p>
<h2 class="title is-4">iff - для других условий</h2>
<p>Наконец, сделаем более мощный хелпер для проверки условий. Я назвал его <code>iff</code>. Я знаю математически смысл этого,
но название выглядит мило и коротко, чтобы быть использованным в нашем случае. Идея такова, чтобы я мог писать условия вот так:</p>
<pre><code>    {{#iff name '==' 'Foo'}}
</code></pre>
<p>и вот так:</p>
<pre><code>    {{#iff answer '&gt;' 40}}
</code></pre>
<p>В примере я сделал два шаблона. В первом шаблоне есть три таких условия.
Во втором - одно условие <code>{{#iff 4 '*' 5}}</code> - чтобы показать, как будет вести себя
хелпер <code>iff</code>, если получит неподдерживаемый оператор. Также я добавил две кнопки - одну для
обработки первого шаблона, и вторую - для второго шаблона.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_conditionals.html">examples/js/handlebars_conditionals.html</a></strong></p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Handlebars conditionals&lt;/title&gt;

  &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    &lt;br&gt;#iff name '==' 'Foo' (expected true)
    {{#iff name '==' 'Foo'}}
      true
    {{else}}
      false
    {{/iff}}

    &lt;br&gt;#iff 42 &amp;gt; 40 (expected true)
    {{#iff answer '&gt;' 40}}
      true
    {{else}}
      false
    {{/iff}}

    &lt;br&gt;#iff 42 &amp;gt; 50 (expected false)
    {{#iff answer '&gt;' 50}}
      true
    {{else}}
      false
    {{/iff}}
  &lt;/script&gt;

  &lt;script id=&quot;text2-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    &lt;br&gt;Exception!
    {{#iff 4 '*' 5}}
       true
    {{else}}
       false
    {{/iff}}
  &lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;
&lt;button id=&quot;show&quot;&gt;Show&lt;/button&gt;
&lt;button id=&quot;show2&quot;&gt;Try invalid&lt;/button&gt;
&lt;hr&gt;
&lt;div id=&quot;content&quot;&gt;&lt;/div&gt;


&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;/try/examples/js/handlebars_conditionals.js&quot;&gt;&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;


</code></pre>
<p><a href="examples/js/handlebars_conditionals.html">view</a></p>
<p>В файле JavaScript лежат данные, код, реагирующий на нажатия и обрабатывающий шаблон, и частичная(!) реализация хелпера <code>iff</code>.
По сути, это огромный оператор <code>switch</code>, обрабатывающий отдельно в <code>case</code> каждый из допустимых входных операторов.
Поведение по умолчанию (<code>default</code>), когда полученный оператор не может быть обработан одним из <code>case</code>,
генерирует исключение.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_conditionals.js">examples/js/handlebars_conditionals.js</a></strong></p>
<pre><code class="language-js">var data = {
   'cond1'  : true,
   'cond2'  : false,
   'name'   : 'Foo',
   'answer' : 42
};

document.getElementById('show').addEventListener('click', function () {
    var source = document.getElementById('text-template').innerHTML;
    var template = Handlebars.compile(source);
    var html = template(data);
    document.getElementById('content').innerHTML = html;
});

document.getElementById('show2').addEventListener('click', function () {
    document.getElementById('content').innerHTML = 'Look at the console!';
    var source = document.getElementById('text2-template').innerHTML;
    var template = Handlebars.compile(source);
    var html = template(data);
    document.getElementById('content').innerHTML = html;
});


Handlebars.registerHelper('iff', function(a, operator, b, opts) {
    var bool = false;
    switch(operator) {
       case '==':
           bool = a == b;
           break;
       case '&gt;':
           bool = a &gt; b;
           break;
       case '&lt;':
           bool = a &lt; b;
           break;
       default:
           throw &quot;Unknown operator &quot; + operator;
    }

    if (bool) {
        return opts.fn(this);
    } else {
        return opts.inverse(this);
    }
});



</code></pre>
<h2 class="title is-4">compare</h2>
<p>Добравшись до этого момента, я узнал, что уже есть реализация подобного хелпера, называемая <code>#compare</code>.
Этот хелпер можно найти среди <a href="http://assemble.io/helpers/helpers-comparison.html">хелперов сравнения</a>.</p>
<p>В любом случае, я думаю, что было интересно узнать, как такое можно сделать и использовать.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Хелперы Handlebars</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-05-03T10:20:01Z</updated>
    <pubDate>2015-05-03T10:20:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/handlebars-helpers" />
    <id>https://rust.code-maven.com/handlebars-helpers</id>
    <content type="html"><![CDATA[<p>Кроме языка шаблонов, который предлагает нам <a href="http://handlebarsjs.com/">Handlebars</a>, он также позволяет создавать обработчики (хендлеры).
Думаю, что в другой среде это могло бы назваться макросы, или вы можете их рассматривать как подпрограммы.</p>
<p>Они позволяют нам создавать повторно используемые выражения.</p>
<p>На сайте Handlebars есть несколько примеров <a href="http://handlebarsjs.com/block_helpers.html">хелперов блоков</a>,
но я собираюсь показать немного другие. Давайте начнем с самого простого хелпера.
Он возвращает HTML сниппет.</p>
<h2 class="title is-4">Статический HTML хелпер</h2>
<p>Весь код выглядит вот так, и вы можете его запустить, нажав ссылку <code>Try!</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_helpers_static.html">examples/js/handlebars_helpers_static.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
&lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    &lt;h3&gt;{{greeting}}&lt;/h3&gt;
&lt;/script&gt;

&lt;button id=&quot;show&quot;&gt;Show&lt;/button&gt;
&lt;div id=&quot;content&quot;&gt;&lt;/div&gt;

&lt;script&gt;
Handlebars.registerHelper('greeting', function() {
    return new Handlebars.SafeString( '&lt;i&gt;Hello World&lt;/i&gt;' );
});

document.getElementById('show').addEventListener('click', function () {
    var source = document.getElementById('text-template').innerHTML;
	var template = Handlebars.compile(source);
	var html = template();

    document.getElementById('content').innerHTML = html;
});

&lt;/script&gt;



</code></pre>
<p><a href="examples/js/handlebars_helpers_static.html">view</a></p>
<p>Хелпер это сниппет JavaScript кода. Строка (в нашем случае <code>greeting</code>) связана с функцией.
Функция может возвращать простую строку с экранированным HTML, или может вернуть объект <code>SafeString</code>,
который оставит строку такой, какая она есть. В нашем случае, так как мы хотим вернуть HTML сниппет, мы используем
объект <code>SafeString</code>. Обычно такой код помещают во внешний JavaScript файл, например, чтобы использовать его в нескольких проектах.</p>
<pre><code class="language-javascript">Handlebars.registerHelper('greeting', function() {
    return new Handlebars.SafeString( '&lt;i&gt;Hello World&lt;/i&gt;' );
});
</code></pre>
<p>Теперь у нас есть хелпер с именем <code>greeting</code> и мы можем использовать его в нашем коде шаблона:</p>
<pre><code class="language-javascript">    &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
        &lt;h3&gt;{{greeting}}&lt;/h3&gt;
    &lt;/script&gt;
</code></pre>
<p>Шаблон это просто HTML сниппет с неколькими плейсхолдерами.</p>
<p>Оставшаяся часть кода в примере это просто обычный Handlebars код, который получает шаблон из HTML кода, компилирует его и генерирует
HTML сниппет.</p>
<p>Конечно, демонстрация &quot;Hello World&quot; не так уж интересна, но возможно, если бы хелпер возвращал информацию о копирайте
для сайта или возвращал меню, тогда он был бы более интересным.</p>
<h2 class="title is-4">Хендлер для ссылок</h2>
<p>Следующий пример основан на одном примере с веб-сайта <a href="http://handlebarsjs.com/block_helpers.html">Handlebars</a>.
Он уже принимает параметр. Предполагается, что это объект JavaScript имеет атрибут <code>url</code> и необязательный атрибут <code>text</code>.
Получив такой объект, этот хендлер вернет HTML ссылку, используя ссылку и текст из объекта.
Если атрибут 'text' отсутствует в объекте, когда будет использован тот же URL.</p>
<p>Полный пример выглядит вот так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_helpers_link.html">examples/js/handlebars_helpers_link.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
&lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    {{link home}}&lt;br&gt;
    {{link perlmaven}}&lt;br&gt;
&lt;/script&gt;

&lt;button id=&quot;show&quot;&gt;Show&lt;/button&gt;
&lt;div id=&quot;content&quot;&gt;&lt;/div&gt;

&lt;script&gt;
Handlebars.registerHelper('link', function(obj) {
    var url  = obj.url;
    var text = obj.text;
    if (text == undefined) {
        text = url;
    }
    return new Handlebars.SafeString( '&lt;a href=&quot;' + url + '&quot;&gt;' + text + '&lt;/a&gt;' );
});

document.getElementById('show').addEventListener('click', function () {
    var source = document.getElementById('text-template').innerHTML;
    var template = Handlebars.compile(source);
    var html = template({
        'home' : {
           'url'  : '/',
           'text' : 'Code Maven'
        },
        'perlmaven' : {
            'url' : 'http://perlmaven.com/'
        }
    });

    document.getElementById('content').innerHTML = html;
});

&lt;/script&gt;




</code></pre>
<p><a href="examples/js/handlebars_helpers_link.html">view</a></p>
<p>Хендлер выглядит вот так:</p>
<pre><code class="language-javascript">Handlebars.registerHelper('link', function(obj) {
    var url  = obj.url;
    var text = obj.text;
    if (text == undefined) {
        text = url;
    }
    return new Handlebars.SafeString( '[' + text + '](' + url + ')' );
});
</code></pre>
<p>Здесь мы связали строку 'link' с функцией, которая принимает единственный параметр.
Мы копирует атрибуты <code>url</code> и <code>text</code> в подходящие переменные, но используем <code>url</code> в качестве текста ссылки, если он не определен.</p>
<p>Затем мы вручную собираем HTML. Выглядит, как будто мы снова вернулись в эру конкатенации HTML, но не забывайте, что этот код будет
размещен во внешнем файле JavaScript, и мы будем использовать его в разных частях проекта, или даже в разных проектах.
Мы погли бы использовать и здесь шаблонизатор Handlebars, но это не выглядит необходимым.</p>
<p>Как только мы создали этот хендлер, мы можем использовать его в нашем шаблоне:</p>
<pre><code class="language-javascript">    &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
        {{link home}}&lt;br&gt;
        {{link perlmaven}}&lt;br&gt;
    &lt;/script&gt;
</code></pre>
<p>В отличие от статического случая, который мы рассмотрели ранее, в этот раз мы используем новое ключевое слово
<code>link</code> наряду с параметром.
Один раз параметр это 'home', и один раз 'perlmaven'. Это плейсхолдеры, которые будут заменены на данные,
переданные в функцию <code>template()</code>.</p>
<p>В итоге давайте посмотрим на вызов функции <code>template()</code> с передаваемыми в нее данными.
Здесь вы можете видеть, что мы передаем объект с двумя атрибутами - 'home' и 'perlmaven'.
Они будут связаны с соответствующими плейсхолдерами в шаблоне. Заметьте, что для 'home' мы передаем оба атрибута - 'url' и 'text',
в то же время для 'perlmaven' передаем только 'url'.</p>
<pre><code class="language-javascript">    var html = template({
        'home' : {
           'url'  : '/',
           'text' : 'Code Maven'
        },
        'perlmaven' : {
            'url' : 'https://perlmaven.com/'
        }
    });
</code></pre>
<p>Результат, который вы увидите, будет таким:</p>
<p><a href="/">Code Maven</a><br>
<a href="https://perlmaven.com/">http://perlmaven.com/</a><br></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Handlebars с более сложными данными</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-05-03T08:52:01Z</updated>
    <pubDate>2015-05-03T08:52:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/handlebars-with-slightly-complex-data" />
    <id>https://rust.code-maven.com/handlebars-with-slightly-complex-data</id>
    <content type="html"><![CDATA[<p>В статье, где мы впервые рассмотрели <a href="/introduction-to-handlebars-javascript-templating-system">Handlebars (шаблонизатор JavaScript)</a>,
был работающий пример, но возможно он был недостаточно убедителен в отношении, почему использование Handlebars лучше конкатенации для создания HTML сниппетов.</p>
<p>Затем был еще этот пример с <a href="/ajax-request-for-json-data">Ajax запросом, возвращающим JSON данные</a>.
Там мы также использовали простой JavaScript, но там было уже совсем неприятно. Давайте теперь посмотрим, как мы можем делать
те же самые вещи, используя Handlebars.</p>
<p>В предыдущем примере мы получили JSON-ответ со следующим содержимым:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/data.json">examples/js/data.json</a></strong></p>
<pre><code class="language-json">{
   &quot;title&quot; : &quot;Code Maven&quot;,
   &quot;description&quot; : &quot;Coding is fun!&quot;,
   &quot;articles&quot; : [
       {
          &quot;title&quot; : &quot;Handling user events in JavaScript&quot;,
          &quot;url&quot;   : &quot;http://code-maven.com/handling-events-in-javascript&quot;
       },
       {
          &quot;title&quot; : &quot;On-load counter with JavaScript and local storage&quot;,
          &quot;url&quot;   : &quot;http://code-maven.com/on-load-counter-with-javascript-and-local-storage&quot;
       }
   ]
}

</code></pre>
<p>Мы использовали этот код:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/ajax.js">examples/js/ajax.js</a></strong></p>
<pre><code class="language-js">function ajax_get(url, callback) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 &amp;&amp; xmlhttp.status == 200) {
            console.log('responseText:' + xmlhttp.responseText);
            try {
                var data = JSON.parse(xmlhttp.responseText);
            } catch(err) {
                console.log(err.message + &quot; in &quot; + xmlhttp.responseText);
                return;
            }
            callback(data);
        }
    };

    xmlhttp.open(&quot;GET&quot;, url, true);
    xmlhttp.send();
}

ajax_get('/try/examples/js/data.json', function(data) {
    document.getElementById(&quot;title&quot;).innerHTML = data[&quot;title&quot;];

    var html = &quot;&lt;h2&gt;&quot; + data[&quot;title&quot;] + &quot;&lt;/h2&gt;&quot;;
    html += &quot;&lt;h3&gt;&quot; + data[&quot;description&quot;] + &quot;&lt;/h3&gt;&quot;;
    html += &quot;&lt;ul&gt;&quot;;
       for (var i=0; i &lt; data[&quot;articles&quot;].length; i++) {
           html += '&lt;li&gt;&lt;a href=&quot;' + data[&quot;articles&quot;][i][&quot;url&quot;] + '&quot;&gt;' + data[&quot;articles&quot;][i][&quot;title&quot;] + &quot;&lt;/a&gt;&lt;/li&gt;&quot;;
       }
    html += &quot;&lt;/ul&gt;&quot;;
    document.getElementById(&quot;text&quot;).innerHTML = html;
});



</code></pre>
<p><a href="/try/examples/js/ajax.html">Попробовать здесь!</a></p>
<h2 class="title is-4">Используя Handlebars</h2>
<p>Функция <code>ajax_get</code> осталась такой же. Она была рассмотрена в статье про <a href="/ajax-request-for-json-data">Ajax запрос</a>.</p>
<p>Изменения в строках 23-25, где вместо конкатенации HTML по фрагментам, мы получаем шаблон из элемента с id <code>text-template</code>,
компилируем исходный код шаблона в функцию <code>template</code>, а затем просто передаем в нее данные, которые мы получили
из Ajax запроса. Намного чище, чем раньше, когда мы должны были думать об использовании одинарных кавычек снаружи так,
чтобы они не пересекались с двойными кавычками, которые мы хотели использовать для HTML атрибутов.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/ajax_handlebars.js">examples/js/ajax_handlebars.js</a></strong></p>
<pre><code class="language-js">function ajax_get(url, callback) {
    xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 &amp;&amp; xmlhttp.status == 200) {
            console.log('responseText:' + xmlhttp.responseText);
            try {
                var data = JSON.parse(xmlhttp.responseText);
            } catch(err) {
                console.log(err.message + &quot; in &quot; + xmlhttp.responseText);
                return;
            }
            callback(data);
        }
    };

    xmlhttp.open(&quot;GET&quot;, url, true);
    xmlhttp.send();
}

ajax_get('/try/examples/js/data.json', function(data) {
    document.getElementById(&quot;title&quot;).innerHTML = data[&quot;title&quot;];

    var source   = document.getElementById('text-template').innerHTML;
    var template = Handlebars.compile(source);
    var html    = template(data);

    document.getElementById(&quot;text&quot;).innerHTML = html;
});




</code></pre>
<p>Сам шаблон находится в HTML файле в теге <code>script</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/ajax_handlebars.html">examples/js/ajax_handlebars.html</a></strong></p>
<pre><code class="language-html">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
 
  &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    &lt;h2&gt;{{title}}&lt;/h2&gt;
    &lt;h3&gt;{{description}}&lt;/h3&gt;
    &lt;ul&gt;
    {{#each articles}}
        &lt;li&gt;&lt;a href=&quot;{{url}}&quot;&gt;{{title}}&lt;/a&gt;&lt;/li&gt;
    {{/each}}
    &lt;/ul&gt;
  &lt;/script&gt;

&lt;h1 id=&quot;title&quot;&gt;&lt;/h1&gt;
&lt;hr&gt;
&lt;div id=&quot;text&quot;&gt;&lt;/div&gt;

&lt;script src=&quot;ajax_handlebars.js&quot;&gt;&lt;/script&gt;


</code></pre>
<p><a href="examples/js/ajax_handlebars.html">view</a></p>
<p>Плейсхолдеры для <code>{{title}}</code> и <code>{{description}}</code> это простые значения, которые мы уже видели во
<a href="/introduction-to-handlebars-javascript-templating-system">введении в Handlebars</a>,
но здесь также есть цикл для прохождения по элементам массива.
<code>{{#each articles}}</code> начинает цикл по элементам массива, лежащего в ключе <code>articles</code>.
Цикл заканчивается, когда мы достигаем инструкции <code>{{/each}}</code>.
Внутри цикла мы можем использовать ключи объектов, которые являются элементами массива <code>articles</code>.</p>
<p>Это делает шаблон гораздо чише, чем он был раньше, когда мы использовали конкатенацию.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Ajax запрос и JSON результат</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-04-25T09:00:01Z</updated>
    <pubDate>2015-04-25T09:00:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/ajax-request-for-json-data" />
    <id>https://rust.code-maven.com/ajax-request-for-json-data</id>
    <content type="html"><![CDATA[<p>Один из краеугольных камней современных веб-приложений находится за сценой - ассинхронный обмен данными между
сервером и Javascript'ом, работающим в браузере. Хотя Ajax это стандарт для XML, в реальности многие приложения
отправляют данные в формате JSON. В большинстве случаев это удобнее, чем использовать XML.</p>
<p>Чтобы сделать этот пример проще, я создал JSON файл на сервере, который мы будем запрашивать.
В реальной ситуации сервер бы сгенерировал такой JSON по запросу, основываясь на информации в своей базе данных,
но сейчас нам интересна только та сторона, которая работает в браузере.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/data.json">examples/js/data.json</a></strong></p>
<pre><code class="language-json">{
   &quot;title&quot; : &quot;Code Maven&quot;,
   &quot;description&quot; : &quot;Coding is fun!&quot;,
   &quot;articles&quot; : [
       {
          &quot;title&quot; : &quot;Handling user events in JavaScript&quot;,
          &quot;url&quot;   : &quot;http://code-maven.com/handling-events-in-javascript&quot;
       },
       {
          &quot;title&quot; : &quot;On-load counter with JavaScript and local storage&quot;,
          &quot;url&quot;   : &quot;http://code-maven.com/on-load-counter-with-javascript-and-local-storage&quot;
       }
   ]
}

</code></pre>
<p>У нас есть HTML страница с элементом <code>h1</code>, который мы собираемся заполнить значением ключа &quot;title&quot;,
также есть элемент <code>div</code>, для которого мы соберем HTML сниппет.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/ajax.html">examples/js/ajax.html</a></strong></p>
<pre><code class="language-html">&lt;h1 id=&quot;title&quot;&gt;&lt;/h1&gt;
&lt;hr&gt;
&lt;div id=&quot;text&quot;&gt;&lt;/div&gt;

&lt;script src=&quot;ajax.js&quot;&gt;&lt;/script&gt;

</code></pre>
<p><a href="examples/js/ajax.html">view</a></p>
<p>JavaScript код выглядит вот так:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/ajax.js">examples/js/ajax.js</a></strong></p>
<pre><code class="language-js">function ajax_get(url, callback) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 &amp;&amp; xmlhttp.status == 200) {
            console.log('responseText:' + xmlhttp.responseText);
            try {
                var data = JSON.parse(xmlhttp.responseText);
            } catch(err) {
                console.log(err.message + &quot; in &quot; + xmlhttp.responseText);
                return;
            }
            callback(data);
        }
    };

    xmlhttp.open(&quot;GET&quot;, url, true);
    xmlhttp.send();
}

ajax_get('/try/examples/js/data.json', function(data) {
    document.getElementById(&quot;title&quot;).innerHTML = data[&quot;title&quot;];

    var html = &quot;&lt;h2&gt;&quot; + data[&quot;title&quot;] + &quot;&lt;/h2&gt;&quot;;
    html += &quot;&lt;h3&gt;&quot; + data[&quot;description&quot;] + &quot;&lt;/h3&gt;&quot;;
    html += &quot;&lt;ul&gt;&quot;;
       for (var i=0; i &lt; data[&quot;articles&quot;].length; i++) {
           html += '&lt;li&gt;&lt;a href=&quot;' + data[&quot;articles&quot;][i][&quot;url&quot;] + '&quot;&gt;' + data[&quot;articles&quot;][i][&quot;title&quot;] + &quot;&lt;/a&gt;&lt;/li&gt;&quot;;
       }
    html += &quot;&lt;/ul&gt;&quot;;
    document.getElementById(&quot;text&quot;).innerHTML = html;
});



</code></pre>
<p>Весь код, относящийся к отправке асинхронного запроса, был помещен в функцию <code>ajax_get</code>.
Эта функция принимает два параметра. Первый - URL, который мы запрашиваем. Это может быть URL примерно такой <code>http://somesite.com/some/page</code>,
или он может быть без имени хоста, например <code>/some/page</code>, если мы хотим отправить запрос на тот же сервер, с которого получили
наш JavaScript. Так же мы можем отправлять параметры, добавляя их после URL. Примерно так: <code>http://somesite.com/some/page?fname=Foo&amp;lname=Bar</code>.</p>
<p>Второй параметр - это функция, которая будет вызвана, когда от сервера придет ответ.</p>
<p>В нашем примере мы ожидаем, что ответом будет корректный JSON.</p>
<p>Пройдемся по функции: сначала мы создали объект <code>XMLHttpRequest()</code>. Затем мы присвоили атрибуту <code>onreadystatechange</code> вызов функции.
Функция будет вызвана, когда прийдет корректный ответ.
Затем мы вызываем <code>open</code>, здесь мы используем <code>url</code>, и в итоге отправляем запрос функцией <code>send</code>.
Здесь вызов нашей функции завершается и приложение может дальше заниматься своими делами, пока...</p>
<p>Пока сервер не ответит. В этот момент будет вызвана функция, связанная с <code>onreadystatechange</code>.
Внутри функции мы проверяем, что запрос действительно был успешным, и затем смотрим на атрибут <code>responseText</code>,
который будет содержать ответ в виде текста. В этом примере мы отправляем его в консоль для того, чтобы
видеть, что мы получили. Дальше здесь есть блок <code>try-catch</code>, оборачивающий вызов <code>JSON.parse</code>.
Это может сэкономить немало времени, если сервер возвратит строку, которая не будет правильным JSON.
(Например, с лишними или пропущенными запятыми). Затем идет интересная часть. Мы вызываем функцию <code>callback(data)</code>, которую
<code>ajax_get</code> получила вторым параметром, и передаем туда данные (уже в виде JavaScript объекта).</p>
<p>Это что касается реализации функции <code>ajax_get</code>, но как нам ее использовать?</p>
<pre><code class="language-javascript">ajax_get('/try/examples/js/data.json', function(data) {
    document.getElementById(&quot;title&quot;).innerHTML = data[&quot;title&quot;];
});
</code></pre>
<p>Мы вызываем функцию <code>ajax_get</code>, передавая ей url (относительный к текущему серверу), и мы также передаем функцию,
которая принимает единственную переменную. Это коллбек-функция и ее параметр будет содержать данные, полученные от сервера.
Затем мы можем получить доступ к атрибутам объекта JavaScript также, как и в случае любого другого Javascript объекта,
и устанавливаем атрибут <code>innerHTML</code> элемента с id &quot;title&quot;.</p>
<p>Вот так мы можем использовать ajax-запрос.</p>
<h2 class="title is-4">Сборка HTML</h2>
<p>Вообще-то в нашем примере есть еще код в этой функциии. После установки имени элемента здесь есть пример,
как создать html строку из разных частей этого объекта с данными. Это не обязательно в данном примере,
но я собираюсь использовать эту возможнжость, чтобы продемонстрировать более убедительную причину использовать Handlebars,
про который я рассказывал во <a href="/introduction-to-handlebars-javascript-templating-system">введении в Handlebars</a>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Введение в Handlebars, шаблонизатор JavaScript</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-04-18T10:07:01Z</updated>
    <pubDate>2015-04-18T10:07:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/introduction-to-handlebars-javascript-templating-system" />
    <id>https://rust.code-maven.com/introduction-to-handlebars-javascript-templating-system</id>
    <content type="html"><![CDATA[<p>В статье про <a href="/input-output-in-plain-javascript">ввод и вывод в JavaScript</a>
вы видели проблему создания сниппетов HTML на лету для последующего добавления на страницу.</p>
<p><a href="http://handlebarsjs.com/">Handlebars</a> это шаблонизатор для JavaScript, который помогает снизить
сложность создания таких страниц.</p>
<p>Давайте перепишем наш пример на использование Handlebars.</p>
<h2 class="title is-4">Версия на чистом JavaScript</h2>
<p>Этот пример из статьи <a href="/input-output-in-plain-javascript">ввод и вывов в JavaScript</a>:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/pure_js_greating.html">examples/js/pure_js_greating.html</a></strong></p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Hello World&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

First name: &lt;input id=&quot;first_name&quot;&gt;
Last name: &lt;input id=&quot;last_name&quot;&gt;
&lt;button id=&quot;say&quot;&gt;Say hi!&lt;/button&gt;

&lt;hr&gt;
&lt;div id=&quot;result&quot;&gt;&lt;/div&gt;

&lt;script&gt;
function say_hi() {
    var fname = document.getElementById('first_name').value;
    var lname = document.getElementById('last_name').value;

    var html = 'Hello &lt;b&gt;' + fname + '&lt;/b&gt; ' + lname;

    document.getElementById('result').innerHTML = html;
}

document.getElementById('say').addEventListener('click', say_hi);
&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;


</code></pre>
<p><a href="examples/js/pure_js_greating.html">view</a></p>
<h2 class="title is-4">Переключение на Handlebars</h2>
<p>Вот решение с использованием Handlebars:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/handlebars_greating.html">examples/js/handlebars_greating.html</a></strong></p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Hello World&lt;/title&gt;

  &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;

  &lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
    Hello &lt;b&gt;{{first_name}}&lt;/b&gt; {{last_name}}
  &lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;

First name: &lt;input id=&quot;first_name&quot;&gt;
Last name: &lt;input id=&quot;last_name&quot;&gt;
&lt;button id=&quot;say&quot;&gt;Say hi!&lt;/button&gt;

&lt;hr&gt;
&lt;div id=&quot;result&quot;&gt;&lt;/div&gt;

&lt;script&gt;
function say_hi() {
    var fname = document.getElementById('first_name').value;
    var lname = document.getElementById('last_name').value;

    var source   = document.getElementById('text-template').innerHTML;
    var template = Handlebars.compile(source);
    var context = {first_name: fname, last_name: lname};
    var html    = template(context);

    document.getElementById('result').innerHTML = html;
}

document.getElementById('say').addEventListener('click', say_hi);
&lt;/script&gt;


&lt;/body&gt;
&lt;/html&gt;

</code></pre>
<p><a href="examples/js/handlebars_greating.html">view</a></p>
<p>Чтобы использовать Handlebars, нам нужно сначала загрузить библиотеку Handlebars. Мы можем использовать ее прямо с
<a href="https://cdnjs.com/">CDN JS</a>:</p>
<pre><code>&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js&quot;&gt;&lt;/script&gt;
</code></pre>
<p>либо мы можем скачать этот файл к себе на сервер и загружать его оттуда.</p>
<p>Мы создаем сниппет HTML и расставляем плейсхолдеры в двойных фигурных скобках:</p>
<pre><code>Hello &lt;b&gt;{{first_name}}&lt;/b&gt; {{last_name}}
</code></pre>
<p>Мы можем описать шаблоны в HTML несколькими способами, но один из рекомендуемых способов
это включить его в блоке <code>head</code> HTML страницы внутри тегов <code>script</code> с уникальным <code>id</code>.
Таким образом мы легко можем описать несколько шаблонов. И намного понятнее, какой мы хотим видеть окончальтельную HTML страницу.</p>
<pre><code>&lt;script id=&quot;text-template&quot; type=&quot;text/x-handlebars-template&quot;&gt;
   Hello &lt;b&gt;{{first_name}}&lt;/b&gt; {{last_name}}
&lt;/script&gt;
</code></pre>
<p>Затем мы описываем JavaScript. В коде JavaScript мы заменяем нашу строку,
собирающую переменные и HTML, которая выглядит вот так:</p>
<pre><code>var html = 'Hello &lt;b&gt;' + fname + '&lt;/b&gt; ' + lname;
</code></pre>
<p>на новый код:</p>
<pre><code>var source   = document.getElementById('text-template').innerHTML;
var template = Handlebars.compile(source);
var context = {first_name: fname, last_name: lname};
var html    = template(context);
</code></pre>
<p>Я знаю, что это выглядит сложнее, чем раньше, и в таком простом примере, где нам
нужно просто вставить содержимое двух переменных в простой сниппет HTML, это может быть
чрезмерно. Но когда ваше приложение будет расти, вы увидите, что сложность
решения на простом Javascript будет расти, в то же время сложность решения на Handlebar
останется примерно такой же.</p>
<p>Давайте пройдемся по тем 4 строкам.</p>
<p>В первой строке мы обращаемся к элементу с id <code>text-template</code>, где у нас лежит шаблон,
и, используя метод <code>innerHTML</code>, мы копируем содержимое элемента в переменную <code>source</code>.</p>
<p>Во второй строке мы компилируем шаблон и создаем объект Handlebars, используя метод <code>Handlebars.compile()</code>.
Вообще-то, метод <code>compile</code> возвращает функцию, которую мы вызовем позднее.</p>
<p>В третьей строке мы создаем ассоциативный массив с ключами, которые совпадают с плейсхолдерами в шаблоне. Значения этих ключей
заменят плейсхолдеры. В массиве находятся значения, которые мы получили из элементов <code>input</code>.
Это просто обычный объект JavaScript. Ничего особенного.
(Вы можете называть это хэш, ассоциативный массив или словарь в зависимости от другого языка, с которым вы знакомы.)</p>
<p>И в конце мы говорим шаблону заменить плейсхолдеры предоставленными значениями и присвоить полученный результат переменной <code>html</code>.</p>
<p>После этого мы можем вернуться обратно к оставшемуся коду JavaScript, и добавить новый HTML в существующий DOM с помощью</p>
<pre><code>document.getElementById('result').innerHTML = html;
</code></pre>
<p>Это были основы Handlebars. Если вы хотите узнать больше, ознакомьтесь с документацией на веб-сайте <a href="http://handlebarsjs.com/">Handlebars</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Ввод и вывод в простом JavaScript</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-04-18T09:13:01Z</updated>
    <pubDate>2015-04-18T09:13:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/input-output-in-plain-javascript" />
    <id>https://rust.code-maven.com/input-output-in-plain-javascript</id>
    <content type="html"><![CDATA[<p>В первой статье мы посмотрели <a href="/javascript-hello-world-change-the-dom">как изменить DOM, чтобы показать чего-нибудь</a>,
а затем мы посмотрели как <a href="/handling-events-in-javascript">обрабатывать события пользователя</a>. В этот раз мы собираемся
рассмотреть, как получить одни данные, введенные пользователем, и соединить их другими, чтобы сделать простую страницу, приветствующую вас.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/pure_js_greating.html">examples/js/pure_js_greating.html</a></strong></p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Hello World&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

First name: &lt;input id=&quot;first_name&quot;&gt;
Last name: &lt;input id=&quot;last_name&quot;&gt;
&lt;button id=&quot;say&quot;&gt;Say hi!&lt;/button&gt;

&lt;hr&gt;
&lt;div id=&quot;result&quot;&gt;&lt;/div&gt;

&lt;script&gt;
function say_hi() {
    var fname = document.getElementById('first_name').value;
    var lname = document.getElementById('last_name').value;

    var html = 'Hello &lt;b&gt;' + fname + '&lt;/b&gt; ' + lname;

    document.getElementById('result').innerHTML = html;
}

document.getElementById('say').addEventListener('click', say_hi);
&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;


</code></pre>
<p><a href="examples/js/pure_js_greating.html">view</a></p>
<p>В этом примере у нас немного больше HTML, чем раньше. Кроме <code>button&lt;/h&gt; и </code>div<code>, где мы будем показывать наши результаты, у нас также есть два элемента </code>input`. Каждый со своим ID.</p>
<p>Если вы нажмете на ссылку Try, то увидите два поля для ввода и кнопку:</p>
<img src="/img/input_form.png" alt="Input form" />
<p>В коде JavaScript у нас есть функция <code>say_hi</code>. Она использует метод <code>getElementById</code>, который мы рассмотрели ранее,
чтобы получить DOM элемент, представляющий input с id <code>first_name</code>. Возвращенный объект имеет метод <code>value</code>,
который вернет текст, введенный пользователем в это поле.</p>
<p>Мы применяем этот способ для получения содержимого обоих элементов <code>input</code> и присваиваем полученные значения двум переменным:
<code>fname</code> и <code>lname</code>.</p>
<p>Затем, используя эти переменные, мы создаем HTML-сниппет и присваиваем его новой переменной <code>html</code>.</p>
<p>Потом мы устанавливаем атрибут <code>innerHTML</code> (как мы делали это <a href="/javascript-hello-world-change-the-dom">ранее</a>)
чтобы показать сгенерированный HTML. Результат может выглядеть вот так:</p>
<img src="/img/input_form_and_output.png" alt="Input form and output" />
<h2 class="title is-4">Громоздкое создание HTML</h2>
<p>Даже в таком простом HTML мы должны использовать <code>+</code> несколько раз, и код получается достаточно нечитаемый.
Представьте, что бы произошло, если бы мы захотели создать более сложное приложение, где мы бы хотели генерировать списки элементов
или даже таблицы. Генерация HTML на лету и вставка его в DOM была бы довольно неприятной.</p>
<p>В бекенде, написанном на Perl, Python или Ruby, люди сталкивались с теми же самыми проблемами. Решением было создание
различных шаблонизаторов. В принципе, шаблон это HTML сниппет с некоторыми плейсхолдерами (ключевыми словами),
некая функция получает этот HTML сниппет (шаблон) в качестве параметра, а также несколько пар ключ-значение.
Затем функция возвращает новый HTML сниппет, в котором плейсхолдеры заменены полученными значениями подходящих ключей.</p>
<p>Точно так же и в Javascript есть много шаблонизаторов. Мы собираемся посмотреть на
<a href="/introduction-to-handlebars-javascript-templating-system">HandlebarsJS, шаблонизатор JavaScript</a>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Обработка пользовательских событий в JavaScript</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-04-12T16:44:01Z</updated>
    <pubDate>2015-04-12T16:44:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/handling-events-in-javascript" />
    <id>https://rust.code-maven.com/handling-events-in-javascript</id>
    <content type="html"><![CDATA[<p>В прошлой статье мы видели, как <a href="/javascript-hello-world-change-the-dom">менять DOM</a> и обновлять HTML страницу,
но когда мы должны это делать? В предыдущем примере код, обновляющий HTML, запускался сразу же, как только страница загружалась в браузер.</p>
<p>В этот раз мы бы хотели отловить событие, сгенерированное пользователем - нажатие на кнопке, к примеру - и мы бы хотели
обновить HTML страницу, когда это произойдет.</p>
<p>В Javascript мы можем присоединить (повесить) различные &quot;event listeners&quot; (обработчик события),
к любому элементу DOM, и даже указать, на какое точно событие он должен реагировать.</p>
<p>Для этого мы можем использовать метод <code>addEventListener</code> элемента DOM, который получит два параметра. Первый - это
имя события, такое как <code>click</code> или <code>keyup</code>, или <code>change</code>. Второй - функция.
(Возможно, мне бы стоило объяснить, как вы можете передать функцию как параметр в другую функцию.)</p>
<p>Вот полное выражение:</p>
<p><code>document.getElementById('btn').addEventListener('click', clicked);</code></p>
<p>Это значит что, как только браузер обнаруживает событие 'click' на HTML элементе с id 'btn', он будет выполнять функцию 'clicked'.</p>
<p>Что делает функция 'clicked'?</p>
<p>Она меняет DOM (HTML), вставляя текст 'Hello World' в элемент с id 'display'. Эта операция была рассмотрена в статье про
<a href="/javascript-hello-world-change-the-dom">изменение DOM</a>.</p>
<p>Попробуйте пример, нажав на ссылку <code>Try</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/event_listener.html">examples/js/event_listener.html</a></strong></p>
<pre><code class="language-html">&lt;button id=&quot;btn&quot;&gt;Click me&lt;/button&gt;

&lt;div id=&quot;display&quot;&gt;&lt;/div&gt;

&lt;script&gt;
function clicked() {
    document.getElementById('display').innerHTML = 'Hello World';
}

document.getElementById('btn').addEventListener('click', clicked);

&lt;/script&gt;


</code></pre>
<p><a href="examples/js/event_listener.html">view</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>JavaScript Hello World - меняем DOM с помощью getElementById и innerHTML</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-04-12T16:39:01Z</updated>
    <pubDate>2015-04-12T16:39:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/javascript-hello-world-change-the-dom" />
    <id>https://rust.code-maven.com/javascript-hello-world-change-the-dom</id>
    <content type="html"><![CDATA[<p>В статье <a href="/introduction-to-javascript">Введение в JavaScript</a> мы видели функцию <code>document.write</code>,
которая меняет содержимое веб-страницы, видимой пользователем. Но у нее мало возможностей для управления местом,
где менять страницу. А точнее, она пишет текст в то же самое место, где и выполняется (в пределах остального HTML).
Это делает функцию очень негибкой.</p>
<p>Лучше это делать, получив представление элемента в DOM и используя функцию <code>innerHTML</code> этого элемента, чтобы
изменить его содержимое.</p>
<p>Для начала DOM - <a href="http://en.wikipedia.org/wiki/Document_Object_Model">Document Object Model</a> - это представление
HTML страницы с помощью объектов Javascript. Это сердце взаимодействия между простым JavaScript и HTML в браузере.
Когда мы использовали <code>document.write</code> во <a href="/introduction-to-javascript">введении</a>, мы меняли HTML,
что влечет за собой изменение DOM.</p>
<p>В этом примере мы меняем DOM, который меняет HTML, отображаемый в браузере.</p>
<p>Преимущество такого метода в том, что мы можем независимо от расположения нашего Javascript, получить доступ и изменить
любую часть DOM, а следовательно и HTML.</p>
<p>Единственное, что важно знать относительно расположения HTML, который мы хотим изменить, и Javascript, который будет менять этот HTML, это то,
что HTML должен быть уже загрузен и разобран браузером, когда Javascript будет пытаться получить к нему доступ.</p>
<p>Этого можно добиться, либо поместив код Javascript после нужного HTML (либо вообще загружая Javascript после HTML),
либо если Javascript загружен до HTML, тогда как-то дать ему понять, что нужно ждать до полной загрузки страницы.
Для последнего способа есть несколько решений, но для простоты мы будем использовать первый способ. Мы просто
поместим наш Javascript после HTML.</p>
<p>Чтобы иметь возможность изменить DOM объект, сначала нам нужно его получить. Есть достаточно много способов сделать это,
но, возможно, самый простой это метод <code>getElementById</code> класса <code>document</code>.</p>
<p>В следующем фрагменте кода вызов <code>document.getElementById('display')</code> получает объект, представляющий HTML элемент с
id <b>display</b>.</p>
<p>Один из атрибутов этого объекта называется <code>innerHTML</code>.
Если мы присвоим ему значение, тогда поменяется содержимое соответствующего HTML элемента.</p>
<p>В этом примере вы можете видеть просто элемент <code>div</code> (мы можем использовать любые элементы, но div это что-то нейтральное, и
поэтому используется часто) с текстом 'Hello World' и id <b>display</b>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/set_innerhtml.html">examples/js/set_innerhtml.html</a></strong></p>
<pre><code class="language-html">&lt;div id=&quot;display&quot;&gt;&lt;/div&gt;

&lt;script&gt;
document.getElementById('display').innerHTML = 'Hello World';
&lt;/script&gt;


</code></pre>
<p><a href="examples/js/set_innerhtml.html">view</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Счетчик загрузок с помощью JavaScript и локального хранилища</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-04-05T17:30:01Z</updated>
    <pubDate>2015-04-05T17:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/on-load-counter-with-javascript-and-local-storage" />
    <id>https://rust.code-maven.com/on-load-counter-with-javascript-and-local-storage</id>
    <content type="html"><![CDATA[<p>Являясь часть большого проекта <a href="https://code-maven.com/counter">Примеры счетчиков</a>, эта статья расскажет, как создать
простой счетчик загрузок на чистом JavaScript, использующим локальное хранилище (Local Storage) из HTML5.</p>
<p>В HTML5 <b>localStorage</b> это термин, используемый для обозначения простой &quot;ключ-значение&quot; базы данных в браузере (или, если более точно,
на жестком диске компьютера, планшета или смартфона, где работает браузер), к которой мы можем получить доступ из JavaScript.</p>
<p>Это очень простой пример, демонстрирующий счетчик, который увеличивается каждый раз, когда вы перезагружаете страницу.
Так как счетчик хранится в вашем собственном браузере и связан с конкретным сайтом, который вы посетили, то его значение не зависит от того,
что видят другие люди, или от того, что увидите вы, загрузив страницу с другого устройства или в другом браузере на этом же устройстве.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/counter_on_load.html">examples/js/counter_on_load.html</a></strong></p>
<pre><code class="language-html">&lt;div id=&quot;counter&quot;&gt;&lt;/div&gt;

&lt;script&gt;
var n = localStorage.getItem('on_load_counter');

if (n === null) {
    n = 0;
}

n++;

localStorage.setItem(&quot;on_load_counter&quot;, n);

document.getElementById('counter').innerHTML = n;
&lt;/script&gt;


</code></pre>
<p><a href="examples/js/counter_on_load.html">view</a></p>
<p>Нажмите на <a href="/try/examples/js/counter_on_load.html" target="_new">Try!</a>, чтобы увидеть, как это работает (откроется в отдельном окне).</p>
<p>Пример содержит единственный HTML элемент <code>div</code>, который имеет уникальный ID <code>counter</code> и немного JavaScript.
Метод <code>getItem</code> из класса <code>localStorage</code> запросит текущее значение для полученного ключа (в этом случае 'on_load_counter') и
присвоит его к <code>n</code>.</p>
<p>В первый раз, когда мы загрузим эту страницу, мы не получим значение для ключа, а вместо этого <code>getItem</code> вернет <code>null</code>.</p>
<p>Затем, если мы получили действительно <code>null</code>, мы установим наш счетчик в 0.</p>
<p>Затем увеличиваем счетчик <code>n++;</code>.</p>
<p>Затем используем метод <code>setItem</code> класса <code>localStorage</code>, чтобы установить значение для ключа 'on_load_counter' в то, что сейчас в <code>n</code></p>
<p>Заключительный шаг - показ нового значения на HTML странице. <code>document.getElementById('counter')</code> предоставляет доступ
к элементу с id <code>counter</code>, содержимое которого мы заменяем на значение в n.</p>
<h2 class="title is-4">Сброс счетчика</h2>
<p>В следующем примере мы собираемся добавить кнопку сброса счетчика. Но для начала посмотрим кое-что другое.
Если вы нажмете на <a href="/try/examples/js/counter_on_load_reset.html" target="_new">Try!</a>, в новом окне откроется другой пример
(URL будет другой, но страница находится на том же самом сайте). Вы увидите счетчик на этой странице, начинающийся со значения,
которое было на первой странице (в первом примере). На самом деле, если вы по очереди будете посещать эти две страницы, то увидите,
что на самом деле, они ссылаются на один и тот же счетчик (на то же самое место в локальном хранилище).</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/counter_on_load_reset.html">examples/js/counter_on_load_reset.html</a></strong></p>
<pre><code class="language-html">&lt;div id=&quot;counter&quot;&gt;&lt;/div&gt;
&lt;button id=&quot;reset&quot;&gt;Reset&lt;/button&gt;

&lt;script&gt;
var n = localStorage.getItem('on_load_counter');

if (n === null) {
    n = 0;
}

n++;

localStorage.setItem(&quot;on_load_counter&quot;, n);

document.getElementById('counter').innerHTML = n;


function reset_counter() {
    localStorage.removeItem('on_load_counter');
}

document.getElementById('reset').addEventListener('click', reset_counter);
&lt;/script&gt;


</code></pre>
<p><a href="examples/js/counter_on_load_reset.html">view</a></p>
<p>В этом примере мы добавили другой HTML элемент - <code>button</code> с ID <code>reset</code>.
В коде JavaScript мы добавили функцию <code>reset_counter</code>, которая при вызове будет использовать метод <code>removeItem</code> класса
<code>localStorage</code>, чтобы удалить пару ключ-значение из локального хранилища.</p>
<p>В последней строке мы снова вызываем <code>document.getElementById('reset')</code>, чтобы идентифицировать нашу кнопку, затем добавляем
обработчик события с помощью метода <code>addEventListener</code>. Это заставит JavaScript вызывать функцию <code>reset_counter</code> каждый раз,
когда переданный элемент HTML (кнопка 'reset') будет нажат.</p>
<p>Если вы откроете пример, нажав по ссылке <b>Try!</b>, то увидите счетчик и кнопку. Когда вы нажмете на кнопку, то вам покажется, что ничего
не произошло. Это потому, что мы не обновили страницу после сброса счетчика. Единственная вещь, которая на самом деле произошла - мы удалили
пару ключ-значение из локального хранилища.</p>
<p>Если вам хочется поиграться с этим примером, тогда добавьте немного кода, который будет автоматически обновлять значение счетчика на
новое после нажатия кнопки сброса.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Делаем веб-клиент (сканер) с помощью Node.js</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-04-05T16:49:01Z</updated>
    <pubDate>2015-04-05T16:49:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/building-a-crawler-in-nodejs" />
    <id>https://rust.code-maven.com/building-a-crawler-in-nodejs</id>
    <content type="html"><![CDATA[<p>Создание веб-сервера, или веб-приложения, как мы делали в <a href="/getting-started-with-nodejs">первом примере</a>, может быть интересным,
также и с созданием веб-сканера. Вы знаете, это такая штука, которая скачивает страницы и делает с ними что-нибудь интересное.</p>
<p>Давайте начнем с чего-нибудь простого.</p>
<p>Класс <a href="http://nodejs.org/api/http.html">http</a>, который мы рассматривали ранее, предоставляет для этого несколько методов.
Мы рассмотрим метод <a href="http://nodejs.org/api/http.html#http_http_get_options_callback">http.get</a>, который предоставляет простой,
хотя и ограниченный интерфейс.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/crawl_01.js">examples/node/crawl_01.js</a></strong></p>
<pre><code class="language-js">var http = require('http');

if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; URL&quot;);
    process.exit(-1);
}

var url = process.argv[2]

http.get(url, function(res) {
    console.log(&quot;Got response: &quot; + res.statusCode);
}).on('error', function(e) {
    console.log(&quot;Got error: &quot; + e.message);
});


</code></pre>
<p>Первая часть кода это просто проверка, передал ли пользователь URL в <a href="/argv-raw-command-line-arguments-in-nodejs">командной строке</a>.</p>
<p>Как только мы получили <code>url</code>, мы вызываем <code>http.get</code>, передавая url и коллбек (функцию обратного вызова).
Коллбек будет вызван с <a href="http://nodejs.org/api/http.html#http_class_http_serverresponse">объектом ответа</a>.</p>
<p>Давайте посмотрим, как ведет себя наш скрипт с различными параметрами.</p>
<p>Сначала запустим его вообще без параметров:</p>
<pre><code>$ node crawl_01.js 
Usage: /Users/gabor/work/articles/code-maven/examples/node/crawl_01.js URL
</code></pre>
<p>Ок, он ответил, что нам нужно передать ему URL.</p>
<pre><code>$ node crawl_01.js http://code-maven.com/
Got response: 200
</code></pre>
<p>Выглядит нормально.</p>
<p>Давайте запросим страницу, которой не существует:</p>
<pre><code>$ node crawl_01.js http://code-maven.com/x
Got response: 404
</code></pre>
<p>Выглядит правильно, мы получили <a href="http://en.wikipedia.org/wiki/HTTP_404">код http 404</a> как и ожидалось, но:
он завис. Не знаю, сколько я ждал, пока он закончил работу. Может быть, минуту или больше.
Это не совсем то, чего мы хотим, не так ли?</p>
<p>Сначала я подумал, что у меня какая-то проблема с сервером, поэтому я попробовал другой запрос:</p>
<pre><code>$ time node crawl_01.js http://google.com/
Got response: 302
</code></pre>
<p><a href="http://en.wikipedia.org/wiki/HTTP_302">Код http 302</a> выглядит правильно, но после этого скрипт опять завис как и раньше.</p>
<p>В общем, проблема не в моем сервере.
Я не был уверен, как решить эту проблему, поэтому я решил двигаться дальше. В конце концов, мы получили верный код ответа, и все еще хотим получить
содержимое ответа. Так как тут все асинхронное, то содержимое совершенно не обязательно прийдет к нам в момент, когда будет вызван коллбек.
Мы должны использовать <code>объект ответа</code> и добавить немного кода, чтобы забрать пришедшие данные.</p>
<h2 class="title is-4">Получение данных</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/crawl_02.js">examples/node/crawl_02.js</a></strong></p>
<pre><code class="language-js">var http = require('http');

if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; URL&quot;);
    process.exit(-1);
}

var url = process.argv[2]

http.get(url, function(res) {
    console.log(&quot;Got response: &quot; + res.statusCode);
    var content = '';
    res.on('data', function(chunk) {
        console.log('chunk ' + chunk.length);
        content += chunk;
    });
    res.on('end', function() {
        console.log('end');
        console.log(content.length);
        console.log(content);
    });
}).on('error', function(e) {
    console.log(&quot;Got error: &quot; + e.message);
});


</code></pre>
<p>Как только соединение установлено и сервер отдал какой-то ответ, Node.js вызывает коллбек, передавая объект ответа.
Это все можно найти в переменной <code>res</code>.</p>
<p>Мы добавили два коллбека в это объект: <code>res.on('data', function(chunk) { ... </code> - будет вызываться каждый раз, когда придет очередная
порция данных, отправленных сервером. Если страница маленькая, то может быть он будет вызван всего один раз, но если страница большая,
то может потребоваться некоторое время (даже несколько секунд?), чтобы получить все данные. Тем временем, мы можем сделать что-нибудь другое.
Таким образом, эта функция будет вызываться каждый раз, когда к нам приходят какие-то данные. Параметр, передаваемый в функцию, будет содержать
текущую порцию данных.</p>
<p>Мы создали переменную <code>content</code>, к которой будем добавлять текущую порцию данных.</p>
<p>Конечно, мы предполагаем, что размер страницы не превышает объем памяти. Это вполне разумное допущение в случае html страницы.</p>
<p>Второй коллбек, добавленный к событию, сработает тогда, когда мы завершим получение данных:
<code>res.on('end', function() { ...</code></p>
<p>Без этого мы не сможем быть уверены, что получили все данные, которые сервер собирался отправить.
Мы просто выведем в консоль 'end' и выведем размер содержимого (<code>content</code>), которое мы получили от сервера.</p>
<p>Давайте запустим теперь наш скрипт:</p>
<pre><code>$ node crawl_02.js http://code-maven.com/
Got response: 200
end
20558
</code></pre>
<p>Итак, главная страница <a href="/">Code Maven</a> имеет размер 20,558 байт.</p>
<pre><code>$ node crawl_02.js https://perlmaven.com/
Got response: 200
end
18487
</code></pre>
<p>По-видимому, главная страница <a href="https://perlmaven.com/">Perl Maven</a> меньше.</p>
<p>А что на счет страниц, которые зависли?</p>
<pre><code>$ node crawl_02.js http://code-maven.com/x
Got response: 404
end
7641
</code></pre>
<p>Они больше не зависают!</p>
<pre><code>$ node crawl_02.js http://google.com/
Got response: 302
end
261
</code></pre>
<p>И эта тоже не зависает.</p>
<p>По-видимому, ранее скрипт ожидал, что мы будем и дальше забирать данные. И вот почему он ждал, пока не отключился по таймауту.
Хотя мне все равно не понятно, почему он не зависал в случае ответа 200.</p>
<h2 class="title is-4">На самом деле порция-за-порцией?</h2>
<p>Тут есть две закомментированных строки. Если мы уберем <code>//</code> с первой, где код <code>console.log('chunk ' + chunk.length);</code>,
и снова запустим скрипт:</p>
<pre><code>$ node crawl_02.js http://code-maven.com/
Got response: 200
chunk 1235
chunk 12672
chunk 1408
chunk 1408
chunk 1408
chunk 1408
chunk 1026
end
20558
</code></pre>
<p>мы сможем увидеть, что получаем данные несколькими частями.</p>
<h2 class="title is-4">Содержимое в случае кода 302</h2>
<p>Если мы уберем второй комментарий <code>//</code>, где код <code>console.log(content);</code>, тогда мы увидим содержимое страницы.</p>
<p>К примеру:</p>
<pre><code>$ node crawl_02.js http://google.com/
Got response: 302
chunk 261
end
261
&lt;HTML&gt;&lt;HEAD&gt;&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html;charset=utf-8&quot;&gt;
&lt;TITLE&gt;302 Moved&lt;/TITLE&gt;&lt;/HEAD&gt;&lt;BODY&gt;
&lt;H1&gt;302 Moved&lt;/H1&gt;
The document has moved
&lt;A HREF=&quot;http://www.google.co.il/?gfe_rd=cr&amp;amp;ei=abcdVK1234GG8Qftxx1234&quot;&gt;here&lt;/A&gt;.
&lt;/BODY&gt;&lt;/HTML&gt;
</code></pre>
<p>Goole.com переадресовывает на локальную версию Google.</p>
<h2 class="title is-4">Выводы</h2>
<p>Это хороший старт для сканера, но многое нужно сделать. На самом деле, вот несколько сканеров на Node.js, которые предоставляют
более высокий уровень абстракции.</p>
<h2 class="title is-4">Продвинутые сканеры</h2>
<p>Для получения более продвинутого сканера нам нужно взглянуть на один их этих проектов:
<a href="https://github.com/cgiffard/node-simplecrawler">node-simplecrawler</a>,
<a href="https://github.com/sylvinus/node-crawler">node-crawler</a>, and
<a href="https://github.com/mikeal/spider">spider</a>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Введение в JavaScript - простой вывод</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-03-28T18:40:01Z</updated>
    <pubDate>2015-03-28T18:40:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/introduction-to-javascript" />
    <id>https://rust.code-maven.com/introduction-to-javascript</id>
    <content type="html"><![CDATA[<p>Изучение Node.js, JQuery, и Angular.js может быть очень веселым, но я думаю, что иметь некие базовые знания очень важно, и знать, как
использовать простой JavaScript. Эта серия статей посвятит вас в JavaScript.</p>
<p>Прежде, чем мы перейдем к синтаксису, давайте узнаем, где мы можем запустить JavaScript.</p>
<p>Традиционно JavaScript использовался внутри браузеров, таких как Mozilla Firefox, Internet Explorer, Chrome, Opera, или Safari.
Авторы добавляют JavaScript код в HTML страницы, которые получают пользователи, посещая веб-сайт. JavaScript код выполняется в браузере
(то, что мы называем &quot;на стороне клиента&quot;, в отличие от запуска &quot;на стороне сервера&quot;).</p>
<p>В последнее время люди начали использовать JavaScript также и на сервере. Возможно, самая известная среда
для работы JavaScript на сервере это <a href="http://nodejs.org/">Node.js</a>, но есть и другие.
К примеру, <a href="https://iojs.org/">io.js</a> (форк от Node.js).</p>
<p>Мы можем выделить три основные части того, что мы обычно называем &quot;JavaScript&quot;.</p>
<ol>
  <li>Сам язык. Он достаточно стандартный среди различных сред, как на стороне браузера, так и сервера.</li>
  <li>DOM API - как язык может взаимодействовать с различными частями веб страницы в браузере. И, хотя с этой стороны браузеры достаточно близки друг к другу, 
  все же они отличаются. Некоторые библиотеки, особенно заметна Query, пытаются предоставлять унифицированный API.</li>
  <li>API на сервере (или просто API), предоставляемый Node.js или одной из других систем на стороне сервера.</li>
</ol>
<p>В этой серии статей мы посмотрим все три основных компонента.</p>
<p>Давайте начнем с нескольких простых примеров, которые мы можем запустить в браузере.
Возможно, это самый просто способ начать, так как эти примеры требуют только браузер (раз вы это читаете, вероятно, он у вас есть) и текстовый редактор.</p>
<h2 class="title is-4">Редактор или IDE</h2>
<p>Можно использовать любой текстовый редактор.</p>
<p>На MS Windows вы можете использовать даже встроенный Notepad, но я бы рекомендовал что-нибудь более функциональное.
Вы можете скачать <a href="http://notepad-plus-plus.org/">Notepad++</a>, который очень похож на Notepad, но с кучей разных фич,
или <a href="http://www.aptana.com/">Aptana Studio</a>. Научиться работать в последней будет сложнее, так что возможно,
вы заходите начать с чего-то попроще.</p>
<h2 class="title is-4">Вставка или подключение</h2>
<p>Вы можете как вставить JavaScript код прямо внутрь HTML файла, так и подключить внешний файл, содержащий весь JavaScript код.
В большинстве случаев последнее предпочтительнее, но для нашего первого примера мы вставим JavaScript внутрь некоего HTML (просто для того,
чтобы делать всю работу в одном файле).</p>
<p>Чтобы это сделать, мы просто добавляем открывающий тег <code>&amp;lt;script&gt;</code> и закрывающий тег <code>&amp;lt;/script&gt;</code>. Между ними мы пишем наш JavaScript код.</p>
<h2 class="title is-4">Ввод и вывод</h2>
<p>Самое первое, что нам нужно узнать, это как взаимодействовать с кодом JavaScript, работающим в браузере. Есть несколько способов, которыми JavaScript
может показать текст для пользователя (вывод). Самый простой - функция <code>alert</code>:</p>
<h2 class="title is-4">alert</h2>
<p>Это покажет в браузере всплывающее окно (попап) с текстом. (Вы можете нажать <b>Try!</b> и страница откроется в отдельном окне).
Функция <code>alert()</code> сейчас используется редко, но это простой способ продемонстрировать работу JavaScript.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/alert.html">examples/js/alert.html</a></strong></p>
<pre><code class="language-html">&lt;script language=&quot;javascript&quot;&gt;

alert(&quot;Hello World&quot;);

&lt;/script&gt;


</code></pre>
<p><a href="examples/js/alert.html">view</a></p>
<p>Если хотите попробовать сделать это самостоятельно, откройте ваш редактор и создайте файл с расширением .html (например, hello.html) и вставьте код ниже
в ваш файл. Затем вернитесь в браузер и откройте файл в браузере (большиство браузеров позволяет это сделать с помощью меню <b>File/Open File</b>).</p>
<h2 class="title is-4">document.write</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/document_write.html">examples/js/document_write.html</a></strong></p>
<pre><code class="language-html">First line
&lt;script&gt;

document.write(&quot;&lt;h1&gt;Hello World&lt;/h1&gt;&quot;);

&lt;/script&gt;
Last line



</code></pre>
<p><a href="examples/js/document_write.html">view</a></p>
<p>В этом примере у нас есть некоторый текст (First line), затем JavaScript код, а затем еще немного текста (Last line).
Этот код на JavaScript использует функцию <code>document.write</code> для изменения содержимого страницы. Он просто вставит <code>&amp;lt;h1&gt;Hello World&amp;lt;/h1&gt;</code>
после &quot;First line&quot;, но до &quot;Last line&quot;.</p>
<p>Эта функция часто использовалась, когда нужно было изменить что-то отображаемое на странице. Сегодня есть более продвинутые способы.</p>
<h2 class="title is-4">console.log</h2>
<p>В заключение давайте посмотрим, как обычно разработчики выводять некую отладочную информацию.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/console.html">examples/js/console.html</a></strong></p>
<pre><code class="language-html">&lt;script&gt;

console.log(&quot;Hello World&quot;);

&lt;/script&gt;


</code></pre>
<p><a href="examples/js/console.html">view</a></p>
<p>Большинство веб-браузеров предоставляют то, что называется &quot;JavaScript console&quot;.
Это дополнительное окно (которое не видно в нормально режиме), где браузер выводит предупреждения и ошибки, сгенерированные кодом JavaScript.
Разработчики также могут выводить информацию в эту консоль с помощью вызова <code>console.log()</code>.</p>
<p>Для того, чтобы увидеть консоль, вам нужно будет ее открыть.
Если вы используете Chrome на OSX вы можете открыть консоль с помощью <code>Command-Option-J</code>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Содержимое директории на Node.js</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-03-28T17:47:01Z</updated>
    <pubDate>2015-03-28T17:47:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/list-content-of-directory-with-nodejs" />
    <id>https://rust.code-maven.com/list-content-of-directory-with-nodejs</id>
    <content type="html"><![CDATA[<p>По аналогии с командой <code>dir</code> в MS Windows (а точнее в DOS) или с командой <code>ls</code> в Unix/Linux, мы напишем скрипт на Node.js,
реализующий такое же поведение. Он будет получать имя директории и возвращать содержимое директории с некоторой информацией о каждом элементе
в этой директории.</p>
<p>Мы уже знаем <a href="/system-information-about-a-file-or-directory-in-nodejs">как получить информацию о файле или директории из inode</a>,
таким образом, мы можем просто вызвать <a href="http://nodejs.org/api/fs.html#fs_fs_stat_path_callback">fs.stat</a> для каждого элемента
в директории.</p>
<p>Этот скрипт получает путь к директории в командной строке (обязательный параметр),
а затем перечисляет содержимое этой директории (без рекурсии).</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/read_dir.js">examples/node/read_dir.js</a></strong></p>
<pre><code class="language-js">var fs = require('fs');


if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; path/to/directory&quot;);
    process.exit(-1);
}

var path = process.argv[2];

fs.readdir(path, function(err, items) {
    console.log(items);

    for (var i=0; i&lt;items.length; i++) {
        console.log(items[i]);
    }
});


</code></pre>
<p>Если вы читали статью о <a href="/system-information-about-a-file-or-directory-in-nodejs">получении системной информации об одном файле</a>,
тогда вам уже известна первая часть нашего скрипта.
А вот новая интересная часть:</p>
<pre><code class="language-javascript">fs.readdir(path, function(err, items) {
    console.log(items);

    for (var i=0; i&lt;items.length; i++) {
        console.log(items[i]);
    }
});
</code></pre>
<p>Здесь мы используем метод <a href="http://nodejs.org/api/fs.html#fs_fs_readdir_path_callback">readdir</a> класса <a href="http://nodejs.org/api/fs.html">fs</a>,
который получает путь и функцию-коллбек в качестве параметров.
Метод читает содержимое директории в память, а когда чтение завершено, то вызывает коллбек с двумя параметрами.</p>
<p>Если произошла какая-то ошибка, тогда первый параметр будет содержать информацию об этом. Если все прошло хорошо, тогда второй параметр будет
содержать массив со всеми найденными в директории элементами (файлы, директории, символьный ссылки и т.д.).</p>
<p>С этого момента внутри нашей функции-коллбека мы можем просто напечатать весь массив, если мы просто хотим убедиться в успешном выполнении,
или пройти циклом по массиву с помощью оператора <code>for</code> и сделать что-нибудь с каждым элементом. К примеру, мы можем напечатать каждый элемент.</p>
<p>Список будет содержать все кроме <code>.</code> (указывает на текущую директорию) и <code>..</code> (представляет собой родительскую директорию).</p>
<p>Вот как это выглядит:</p>
<pre><code>$ node examples/node/read_dir.js ~/work/code-maven.com/examples/

[ 'blocking-read-file.js',
  'node_hello_world.js',
  'node_hello_world_port.js',
  'non-blocking-read-file.js',
  'process_exit.js',
  'raw_command_line_arguments.js',
  'read_dir.js',
  'stats.js' ]
blocking-read-file.js
node_hello_world.js
node_hello_world_port.js
non-blocking-read-file.js
process_exit.js
raw_command_line_arguments.js
read_dir.js
stats.js
</code></pre>
<h2 class="title is-4">Подробная информаци о каждом элементе</h2>
<p>Теперь, когда мы знаем, как получить содержимое директории, и как <a href="/system-information-about-a-file-or-directory-in-nodejs">получить информацию о файле</a>,
мы можем соединить эти две процедуры.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/list_dir_direct.js">examples/node/list_dir_direct.js</a></strong></p>
<pre><code class="language-js">var fs = require('fs');

if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; path/to/directory&quot;);
    process.exit(-1);
}

var path = process.argv[2];

fs.readdir(path, function(err, items) {
    for (var i=0; i&lt;items.length; i++) {
        var file = path + '/' + items[i];
        console.log(&quot;Start: &quot; + file);

        fs.stat(file, function(err, stats) {
            console.log(file);
            console.log(stats[&quot;size&quot;]);
        });
    }
});



</code></pre>
<p>Код достаточно прост и понятен. И он также содержит ошибки, как мы увидим чуть позже.</p>
<p>Внутри коллбека для метода <code>readdir</code> у нас есть цикл <code>for</code>.
В этом цикле в каждой итерации мы выводим имя текущего файла (после добавления полного пути директории) - в основном для отладочных целей -
и вызываем <code>fs.stat</code>. Этот метод в свою очередь тоже принимает коллбек. Там мы выводим имя файла - в этот раз, как часть результата,
и затем выводим размер файла. Мы могли бы вывести все данные о файле как мы это делали в
<a href="/system-information-about-a-file-or-directory-in-nodejs">другой статье</a>, но сейчас размера достаточно.</p>
<p>Вывод в консоль:</p>
<pre><code>$ node examples/node/list_dir_direct.js ~/work/code-maven.com/examples/

Start: /home/gabor/work/code-maven.com/examples//blocking-read-file.js
Start: /home/gabor/work/code-maven.com/examples//node_hello_world.js
Start: /home/gabor/work/code-maven.com/examples//node_hello_world_port.js
Start: /home/gabor/work/code-maven.com/examples//non-blocking-read-file.js
Start: /home/gabor/work/code-maven.com/examples//process_exit.js
Start: /home/gabor/work/code-maven.com/examples//raw_command_line_arguments.js
Start: /home/gabor/work/code-maven.com/examples//read_dir.js
Start: /home/gabor/work/code-maven.com/examples//stats.js

/home/gabor/work/code-maven.com/examples//stats.js
97
/home/gabor/work/code-maven.com/examples//stats.js
243
/home/gabor/work/code-maven.com/examples//stats.js
270
/home/gabor/work/code-maven.com/examples//stats.js
151
/home/gabor/work/code-maven.com/examples//stats.js
18
/home/gabor/work/code-maven.com/examples//stats.js
324
/home/gabor/work/code-maven.com/examples//stats.js
27
/home/gabor/work/code-maven.com/examples//stats.js
1382
</code></pre>
<p>Отладочный вывод напечатал имена как и ожидалось, но внутри коллбека функции <code>fs.stat()</code> мы снова печатаем одно и тоже имя файла.
Сравните результаты:</p>
<pre><code>$ ls -l ~/work/code-maven.com/examples/
total 64
-rw-r--r--  1 gabor  staff    97 Jan 29 14:26 blocking-read-file.js
-rw-r--r--  1 gabor  staff   243 Jan 27 12:34 node_hello_world.js
-rw-r--r--  1 gabor  staff   270 Jan 27 12:34 node_hello_world_port.js
-rw-r--r--  1 gabor  staff   151 Jan 29 14:26 non-blocking-read-file.js
-rw-r--r--  1 gabor  staff    18 Jan 31 08:24 process_exit.js
-rw-r--r--  1 gabor  staff    27 Jan 29 14:54 raw_command_line_arguments.js
-rw-r--r--  1 gabor  staff   324 Jan 31 15:26 read_dir.js
-rw-r--r--  1 gabor  staff  1382 Jan 31 10:45 stats.js
</code></pre>
<p>Количество выведенных строк совпадает с количеством файлов (мы их печатали в том же порядке, как и вызывали <code>fs.stat()</code>),
но по какой-то причине содержимое переменной <code>file</code> было одно и то же для каждого коллбека.
Это случилось потому, что переменная <code>file</code> это просто глобальная переменая (с точки зрения коллбека), и в первый раз, когда
коллбек был вызван, переменная <code>file</code> содержала уже имя последнего файла в директории.</p>
<p>Таким образом, если мы хотим сочетать имя файла и результат вызова функции <code>fs.stat()</code>, тогда мы должны опираться на порядок вызовов.
Но можем ли мы полагаться на него?
В этом конкретном случае вызова функции для каждого файла в директории это могло бы сработать как мы ожидаем - вызов функций по порядку.
Но в случае более сложных операций, особенно, если есть еще и внутренние коллбеки, мы не можем полагаться на то, что функции будут вызваны
в нужном нам порядке - в порядке их инициализации.</p>
<p>Следовательно, нам нужен способ передачи параметра <code>file</code> во внутренний коллбек.</p>
<h2 class="title is-4">Генерация коллбеков</h2>
<p>В этот раз, вместо добавления жестко заданного коллбека, мы будем вызывать функцию <code>generate_callback()</code>, которая будет генерировать
для нас коллбеки.</p>
<p>Теперь каждый раз, когда мы вызываем <code>fs.stat()</code>, до того как <code>fs.stat()</code> будет реально выполнен,
JavaScript будет вызывать функцию <code>generate_callback()</code> с текущим значением переменной <code>file</code>.
<code>Generate_callback</code> будет создавать новую функцию и затем возвращать ее нам.
Эта вновь созданная функция станет коллбеком для метода <code>fs.stat()</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/list_dir_generate.js">examples/node/list_dir_generate.js</a></strong></p>
<pre><code class="language-js">var fs = require('fs');

if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; path/to/directory&quot;);
    process.exit(-1);
}

var path = process.argv[2];

fs.readdir(path, function(err, items) {
    for (var i=0; i&lt;items.length; i++) {
        var file = path + '/' + items[i];

        console.log(&quot;Start: &quot; + file);
        fs.stat(file, generate_callback(file));
    }
});

function generate_callback(file) {
    return function(err, stats) {
            console.log(file);
            console.log(stats[&quot;size&quot;]);
        }
};


</code></pre>
<p>Результат:</p>
<pre><code>$ node examples/node/list_dir_generate.js ~/work/code-maven.com/examples/
Start: /Users/gabor/work/code-maven.com/examples//blocking-read-file.js
Start: /Users/gabor/work/code-maven.com/examples//node_hello_world.js
Start: /Users/gabor/work/code-maven.com/examples//node_hello_world_port.js
Start: /Users/gabor/work/code-maven.com/examples//non-blocking-read-file.js
Start: /Users/gabor/work/code-maven.com/examples//process_exit.js
Start: /Users/gabor/work/code-maven.com/examples//raw_command_line_arguments.js
Start: /Users/gabor/work/code-maven.com/examples//read_dir.js
Start: /Users/gabor/work/code-maven.com/examples//stats.js

/Users/gabor/work/code-maven.com/examples//blocking-read-file.js
97
/Users/gabor/work/code-maven.com/examples//node_hello_world.js
243
/Users/gabor/work/code-maven.com/examples//node_hello_world_port.js
270
/Users/gabor/work/code-maven.com/examples//non-blocking-read-file.js
151
/Users/gabor/work/code-maven.com/examples//process_exit.js
18
/Users/gabor/work/code-maven.com/examples//raw_command_line_arguments.js
27
/Users/gabor/work/code-maven.com/examples//read_dir.js
324
/Users/gabor/work/code-maven.com/examples//stats.js
1382
</code></pre>
<p>Теперь переменная <code>file</code> содержит имя файла, которое было у нее на момент инициализации функции, когда <code>fs.stat()</code> приняла ее
в качестве аргумента.</p>
<h2 class="title is-4">Безимянные генераторы функций</h2>
<p>В заключение давайте посмотрим решение без использования внешней функции <code>generate_callback</code>.</p>
<p>Функция все еще здесь, но у нее просто нет имени. Вместо отдельного объявления мы ее включили в <code>fs.stat()</code>.
Я не уверен, нравится ли мне это или вариант более длинный. Возможно, с функцией <code>generate_callback</code> получается более читаемо.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/list_dir_noname.js">examples/node/list_dir_noname.js</a></strong></p>
<pre><code class="language-js">var fs = require('fs');

if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; path/to/directory&quot;);
    process.exit(-1);
}

var path = process.argv[2];

fs.readdir(path, function(err, items) {
    for (var i=0; i&lt;items.length; i++) {
        var file = path + '/' + items[i];

        console.log(&quot;Start: &quot; + file);
        fs.stat(file, function(f) {
            return function(err, stats) {
               console.log(f);
               console.log(stats[&quot;size&quot;]);
            }
        }(file));
    }
});


</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Запрос на подтверждение и ввод в JavaScript</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-22T23:58:01Z</updated>
    <pubDate>2015-02-22T23:58:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/javascript-input-with-prompt-and-confirm" />
    <id>https://rust.code-maven.com/javascript-input-with-prompt-and-confirm</id>
    <content type="html"><![CDATA[<p>Раз мы уже знаем, как что-то <a href="http://code-maven.com/introduction-to-javascript">вывести в JavaScript</a>, давайте взглянем на два способа ввода.
Возможно, ни один из них широко не используется, но они могут быть просто использованы для знакомства с основами.</p>
<h2 class="title is-4">Prompt. Запрос</h2>
<p>Первый из них называется <code>prompt</code>.
Он показывает всплывающее окно с текстом, который мы передаем первым параметром, и полем ввода, которое пользователь может заполнить.
Когда пользователь нажмет <code>OK</code>, функция <code>prompt()</code> вернет введенное значение.
Далее в этом примере мы используем метод <a href="http://code-maven.com/introduction-to-javascript">document.write</a>, чтобы заменить содержимое html-страницы
нашим текстом.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/prompt.html">examples/js/prompt.html</a></strong></p>
<pre><code class="language-html">&lt;script&gt;

var name = prompt(&quot;Your name:&quot;, &quot;&quot;);
document.write(&quot;Hello &quot;, name);

&lt;/script&gt;

</code></pre>
<p><a href="examples/js/prompt.html">view</a></p>
<p>Текстовое поле будет предварительно заполнено значением второго параметра. Это может быть очень полезно, если бы мы хотели,
чтобы пользователь отредактировал какое-нибудь значение. Можно заполнить поле старым значением.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/edit.html">examples/js/edit.html</a></strong></p>
<pre><code class="language-html">&lt;script&gt;

var name = prompt(&quot;Please correct your e-mail address:&quot;, &quot;foo@bar.co&quot;);
document.write(&quot;Your e-mail address is &quot;, name);

&lt;/script&gt;

</code></pre>
<p><a href="examples/js/edit.html">view</a></p>
<p>В другом случае, если пользователь нажмет <code>cancel</code> или клавишу <code>ESC</code>, функция <code>prompt()</code> вернет <code>null</code>.</p>
<h2 class="title is-4">Confirm. Подтверждение</h2>
<p>Это всплывающее окно на самом деле не метод ввода. Оно позволяет разработчику задать вопрос и получить ответ - Да/Нет.
Вызов функции <code>confirm()</code> приведет к появлению всплывающего окна с заданным текстом и двумя кнопками.
Если пользователь нажмет <code>OK</code>, функция <code>confirm()</code> вернет <code>true</code>, если нажмет <code>cancel</code> или
клавишу <code>ESC</code>, тогда функция вернет <code>false</code>.</p>
<p>Конечно, для понимания смысла, вы должны знать, что обозначают <code>true</code> и <code>false</code>,
и что делает эта конструкция <code>if - else</code>.
Если у вас уже есть какой-то опыт программирования, тогда, вероятно, вы уже поняли код, но даже если и нет, то сможете разобраться.</p>
<p>Этот код может быть описан следующим предложением:</p>
<p><code>Если &quot;подтверждение&quot; вернуло true, тогда напечатать &quot;Hello World&quot;, иначе напечатать &quot;OK, I won't print it.&quot;</code></p>
<p>Или лучше вот так:</p>
<p><code>Если пользователь нажал &quot;ОК&quot;, когда мы спросили &quot;Shall I print Hello World?&quot;, тогда напечатать &quot;Hello World&quot;,  иначе напечатать &quot;OK, I won't print it.&quot;</code></p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/confirm.html">examples/js/confirm.html</a></strong></p>
<pre><code class="language-html">&lt;script&gt;

if (confirm(&quot;Shall I print Hello World?&quot;)) {
    document.write(&quot;Hello World&quot;);
} else {
    document.write(&quot;OK, I won't print it.&quot;);
}

&lt;/script&gt;

</code></pre>
<p><a href="examples/js/confirm.html">view</a></p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Функции в JavaScript</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-22T22:40:01Z</updated>
    <pubDate>2015-02-22T22:40:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/functions-in-javascript" />
    <id>https://rust.code-maven.com/functions-in-javascript</id>
    <content type="html"><![CDATA[<p>Как в большинстве языков программирования, в JavaScript мы тоже можем создавать функции.</p>
<p>В JavaScript мы используем ключевое слово <code>function</code> и имя функции.
Потом список параметров в круглых скобках, а затем блок выражений в фигурных скобках - это тело функции.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/function.html">examples/js/function.html</a></strong></p>
<pre><code class="language-html">&lt;script&gt;
function show() {
  console.log('Hello World');
}

console.log('before');
show();
console.log('after');
&lt;/script&gt;


</code></pre>
<p><a href="examples/js/function.html">view</a></p>
<p>Если вы попробуете (Try!) этот пример и <a href="http://code-maven.com/open-javascript-console">откроете консоль JavaScript</a>,
чтобы посмотреть вывод, то увидите следующий порядок сообщений:</p>
<pre><code>before
Hello World
after
</code></pre>
<p>Как вы видите, код выполняется не в том порядке, в котором написан в файле.
Хотя функция определена раньше всего, она выполняется позднее, когда мы вызываем ее, используя имя <code>show();</code></p>
<h2 class="title is-4">Многократный вызов функции</h2>
<p>Пока еще было не очень интересно, но в примере дальше вы увидите, что мы можем вызывать одну и ту же функцию
несколько раз.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/function_calls.html">examples/js/function_calls.html</a></strong></p>
<pre><code class="language-html">&lt;script&gt;
function show() {
  console.log('Hello World');
}

show();
console.log('before');
show();
console.log('after');
show();
&lt;/script&gt;



</code></pre>
<p><a href="examples/js/function_calls.html">view</a></p>
<p>Это демонстрирует одно из предназначений функций. Они могут помочь устранить дублирование кода.
Конечно, если бы содержимое функции было больше, то выгода была бы заметнее.
Мы просто добавляем одну строку при каждом вызове функции, но выполняется все тело функции.</p>
<pre><code>Hello World
before
Hello World
after
Hello World
</code></pre>
<h2 class="title is-4">Функции с параметрами</h2>
<p>Гораздо более интересный вариант, когда мы передаем параметры в функцию.
В следующем примере в объявлении функции мы указали, что собираемся принимать единственное значение
и хотим, чтобы это значение было присвоено переменной <code>name</code>.
Затем мы вызвали функцию, передав ей значение. При каждом вызове мы передаем разные значения.</p>
<p>Внутри функции переменная <code>name</code> содержит текущее значение.</p>
<p>Это показывает реальную мощь функций.</p>
<p>Мы можем иметь один фрагмент кода, проверить его отдельно от остальной части кода, а затем
использовать его много раз.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/js/function_parameters.html">examples/js/function_parameters.html</a></strong></p>
<pre><code class="language-html">&lt;script&gt;
function show(name) {
  console.log('Hello ', name);
}

show('Foo');
show('Bar');
show('Zorg');
&lt;/script&gt;



</code></pre>
<p><a href="examples/js/function_parameters.html">view</a></p>
<p>Вывод функции:</p>
<pre><code>Hello  Foo
Hello  Bar
Hello  Zorg
</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>HTTP-запрос клиента в Node.js (GET-запрос и данные из POST-запроса)</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-22T21:51:01Z</updated>
    <pubDate>2015-02-22T21:51:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/http-client-request-in-nodejs" />
    <id>https://rust.code-maven.com/http-client-request-in-nodejs</id>
    <content type="html"><![CDATA[<p>При создании веб-приложения на чистом Node.js вы могли использовать класс <a href="http://nodejs.org/api/http.html">http</a>,
как мы делали в <a href="/getting-started-with-nodejs">Начинаем с Node.js</a>.
Тогда мы использовали только объект <code>response</code>, но если нас интересует сам запрос, тогда нужно взглянуть на
объект <code>request</code>, который мы получаем в функции обратного вызова (callback, колбек).</p>
<p>В этом простом примере <code>http-сервера на Node.js</code> выводятся некоторые значения из объекта запроса, который является
экземпляром класса <a href="http://nodejs.org/api/http.html#http_class_http_clientrequest">http.ClientRequest</a>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/http_client_request.js">examples/node/http_client_request.js</a></strong></p>
<pre><code class="language-js">var http = require('http');

var port = 8081;

var s = http.createServer();
s.on('request', function(request, response) {
    response.writeHead(200);
    console.log(request.method);
    console.log(request.headers);
    console.log(request.url);
    response.write('hi');
    response.end();
});

s.listen(port);
console.log('Browse to http://127.0.0.1:' + port);



</code></pre>
<p>Я запустил приведенный выше скрипт с помощью команды <code>node examples/node/http_client_request.js</code>,
он вывел: <code>Browse to http://127.0.0.1:8081</code>, и я зашел по указанному адресу через мой обычный браузер.</p>
<p>И вот что было выведено в консоль:</p>
<pre><code>GET
{ host: '127.0.0.1:8081',
  connection: 'keep-alive',
  'cache-control': 'max-age=0',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.94 Safari/537.36',
  'accept-encoding': 'gzip, deflate, sdch',
  'accept-language': 'en-US,en;q=0.8,he;q=0.6,ru;q=0.4' }
/
GET
{ host: '127.0.0.1:8081',
  connection: 'keep-alive',
  accept: '*/*',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.94 Safari/537.36',
  'accept-encoding': 'gzip, deflate, sdch',
  'accept-language': 'en-US,en;q=0.8,he;q=0.6,ru;q=0.4' }
/favicon.ico
</code></pre>
<p>Сначала это меня слегка смутило. Почему у меня два GET-запроса? Но потом я кое-что вспомнил и, присмотревшись, все понял.
Первый запрос действительно был к <code>/</code> (как вы сами можете увидеть - перед вторым GET-запросом), но затем браузер отправил
второй запрос к <code>/favicon.ico</code>. Это автоматический запрос браузера, отправленный в надежде,
что он сможет поместить это маленькое изображение на вкладке, где я открыл страницу.</p>
<p>Я не хочу, чтобы в моем исследовании была лишная путаница, поэтому я перешел на команду <code>curl</code>, которая доступна в Linux/Unix.</p>
<p>Попробуем еще раз:</p>
<p>Я запустил сервер:</p>
<pre><code>$ node examples/node/http_client_request.js 
Browse to http://127.0.0.1:8081
</code></pre>
<p>и открыл еще одно командное окно, где написал свой запрос:</p>
<pre><code>$ curl http://127.0.0.1:8081/
</code></pre>
<p>Затем переключился на предыдущую консоль, чтобы посмотреть ответ:</p>
<pre><code>GET
{ 'user-agent': 'curl/7.37.1',
  host: '127.0.0.1:8081',
  accept: '*/*' }
/
</code></pre>
<p>С этого момента я переключался туда-сюда между двумя консолями.</p>
<p>Второй запрос содержит путь к документу на сервере и параметр со значением:</p>
<pre><code>$ curl http://127.0.0.1:8081/some/path?field=value
</code></pre>
<p>Вывод в консоль был таким же, как и в предыдущем примере, кроме последней строки, которая содержит <code>url</code>.</p>
<pre><code>GET
{ 'user-agent': 'curl/7.37.1',
  host: '127.0.0.1:8081',
  accept: '*/*' }
/some/path?field=value
</code></pre>
<p>Последней попыткой стала отправка POST-запроса с некоторыми данными с помощью curl:</p>
<pre><code>$ curl --data &quot;field=value&quot; http://127.0.0.1:8081/
</code></pre>
<p>вывод выглядел вот так:</p>
<pre><code>POST
{ 'user-agent': 'curl/7.37.1',
  host: '127.0.0.1:8081',
  accept: '*/*',
  'content-length': '11',
  'content-type': 'application/x-www-form-urlencoded' }
/
</code></pre>
<p>Первая строка показывает, что это действительно был <code>POST</code> запрос, заголовок содержал дополнительные поля,
но сами данные не отображались.</p>
<p>Конечно, данные должны быть прочитаны и обработаны другим способом.</p>
<h2 class="title is-4">Прием HTTP POST запросов в Node.js</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/http_client_request_post.js">examples/node/http_client_request_post.js</a></strong></p>
<pre><code class="language-js">var http = require('http');

var port = 8081;

var s = http.createServer();
s.on('request', function(request, response) {
    response.writeHead(200);
    console.log(request.method);
    console.log(request.headers);
    console.log(request.url);

    var data = '';
    request.on('data', function(chunk) {
        data += chunk.toString();
    });
    request.on('end', function() {
        console.log(data);
        response.write('hi');
        response.end();
    });

});

s.listen(port);
console.log('Browse to http://127.0.0.1:' + port);




</code></pre>
<p>Это еще одна область, где видна неблокирующая природа Node.js.
Вместо простого чтения данных из объекта запроса, мы добавляем функцию обратного вызова (callback) к событию <code>data</code> объекта <code>request</code>.
Она [функция] будет вызываться каждый раз, когда придет новая партия данных.
Конечно, если данные это всего лишь 11 символов, как в нашем случае, тогда это не очень интересно,
но если вы отправляете большой объем данных, тогда нам важно их читать, не блокируя остальную часть сайта.</p>
<p>Теперь, когда у нас есть колбек, ожидающий данные, нам нужно отдать ответ тогда, когда все данные будут приняты.
Таким образом, мы добавили колбек для события <code>end</code> объекта <code>request</code>, и в нем мы выведем в консоль все данные,
отправленные клиентом, затем завершим ответ, вызвав метод <code>end</code> объекта <code>response</code></p>
<p>Давайте попробуем</p>
<pre><code>$ node examples/node/http_client_request_post.js 
Browse to http://127.0.0.1:8081
</code></pre>
<p>Обычный GET-запрос:</p>
<pre><code>$ curl http://127.0.0.1:8081/
</code></pre>
<p>отработал как раньше:</p>
<pre><code>GET
{ 'user-agent': 'curl/7.37.1',
  host: '127.0.0.1:8081',
  accept: '*/*' }
/
</code></pre>
<p>GET-запрос с указанием документа и параметрами:</p>
<pre><code>$ curl http://127.0.0.1:8081/some/path?field=value
</code></pre>
<p>результат:</p>
<pre><code>GET
{ 'user-agent': 'curl/7.37.1',
  host: '127.0.0.1:8081',
  accept: '*/*' }
/some/path?field=value
</code></pre>
<p>И как ведет себя <code>POST</code>-запрос</p>
<pre><code>$ curl --data &quot;field=value&quot; http://127.0.0.1:8081/
</code></pre>
<p>результат в консоли:</p>
<pre><code>POST
{ 'user-agent': 'curl/7.37.1',
  host: '127.0.0.1:8081',
  accept: '*/*',
  'content-length': '11',
  'content-type': 'application/x-www-form-urlencoded' }
/
field=value
</code></pre>
<p>Таким образом, удалось получить данные, отправленные клиентом.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Как получить системную информацию о файле или директории в Node.js (stat)</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-11T14:30:01Z</updated>
    <pubDate>2015-02-11T14:30:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/system-information-about-a-file-or-directory-in-nodejs" />
    <id>https://rust.code-maven.com/system-information-about-a-file-or-directory-in-nodejs</id>
    <content type="html"><![CDATA[<p>Команда <code>ls</code> в ОС Unix/Linux может предоставить информацию о файле, директории, символьной ссылке и о прочих элементах, которые могут существовать в файловой системе. С помощью флага <code>-l</code> можно увидеть тип просматриваемого элемента (файл/директория/символьная ссылка...), независимо от того, какие права для него установлены - на чтение, запись или исполнение.</p>
<p>В основном, эту информацию можно получить из структуры <a href="http://en.wikipedia.org/wiki/Inode">inode</a>, но не в Node.js под Apple.</p>
<p>Прежде чем попробовать заново реализовать UNIX команду ls, давайте посмотрим, что мы можем узнать про элемент файловой системы с помощью Node.js</p>
<p>Библиотека <a href="http://nodejs.org/api/fs.html">fs</a>, поставляющаяся вместе с Node.js, предоставляет асинхронный метод <a href="http://nodejs.org/api/fs.html#fs_fs_stat_path_callback">stat</a>, который получает первым аргументом путь к элементу файловой системы, находит информацию о нем в <b>inode</b>, затем вызывает функцию-коллбек (обратный вызов, переданный вторым аргументом). В коллбек будет передан объект <a href="http://nodejs.org/api/fs.html#fs_class_fs_stats">fs.Stats</a>.</p>
<p>Так же есть синхронная версия этого метода <a href="http://nodejs.org/api/fs.html#fs_fs_statsync_path">statSync</a>, которая вернет объект <a href="http://nodejs.org/api/fs.html#fs_class_fs_stats">fs.Stats</a>, когда будет завершено чтение информации из файловой системы.</p>
<p>Эта программа показывает, как использовать асинхронный метод:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/stats.js">examples/node/stats.js</a></strong></p>
<pre><code class="language-js">var fs = require('fs');

if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; path/to&quot;);
    process.exit(-1);
}

var path = process.argv[2];

fs.stat(path, function(err, stats) {
    console.log(path);
    console.log();
    console.log(stats);
    console.log();

    if (stats.isFile()) {
        console.log('    file');
    }
    if (stats.isDirectory()) {
        console.log('    directory');
    }

    console.log('    size: ' + stats[&quot;size&quot;]);
    console.log('    mode: ' + stats[&quot;mode&quot;]);
    console.log('    others eXecute: ' + (stats[&quot;mode&quot;] &amp; 1 ? 'x' : '-'));
    console.log('    others Write:   ' + (stats[&quot;mode&quot;] &amp; 2 ? 'w' : '-'));
    console.log('    others Read:    ' + (stats[&quot;mode&quot;] &amp; 4 ? 'r' : '-'));

    console.log('    group eXecute:  ' + (stats[&quot;mode&quot;] &amp; 10 ? 'x' : '-'));
    console.log('    group Write:    ' + (stats[&quot;mode&quot;] &amp; 20 ? 'w' : '-'));
    console.log('    group Read:     ' + (stats[&quot;mode&quot;] &amp; 40 ? 'r' : '-'));

    console.log('    owner eXecute:  ' + (stats[&quot;mode&quot;] &amp; 100 ? 'x' : '-'));
    console.log('    owner Write:    ' + (stats[&quot;mode&quot;] &amp; 200 ? 'w' : '-'));
    console.log('    owner Read:     ' + (stats[&quot;mode&quot;] &amp; 400 ? 'r' : '-'));


    console.log('    file:           ' + (stats[&quot;mode&quot;] &amp; 0100000 ? 'f' : '-'));
    console.log('    directory:      ' + (stats[&quot;mode&quot;] &amp; 0040000 ? 'd' : '-'));



});



</code></pre>
<p>Предполагается, что эта программа вызывается таким образом: <code>node examples/node/stats.js path/to/file</code>.</p>
<p>Для примера я запустил <code>node examples/node/stats.js examples</code> (указав в качестве параметра директорию 'examples') и получил такой результат:</p>
<pre><code>examples

{ dev: 16777220,
  mode: 16877,
  nlink: 11,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 32548075,
  size: 374,
  blocks: 0,
  atime: Sat Jan 31 2015 10:56:30 GMT+0200 (IST),
  mtime: Sat Jan 31 2015 10:52:13 GMT+0200 (IST),
  ctime: Sat Jan 31 2015 10:52:13 GMT+0200 (IST) }

    directory
    size: 374
    mode: 16877
    others eXecute: x
    others Write:   -
    others Read:    r
    group eXecute:  x
    group Write:    w
    group Read:     r
    owner eXecute:  x
    owner Write:    w
    owner Read:     r
    file:           -
    directory:      d
</code></pre>
<p>Сравним полученную информацию с результатом работы команды <code>ls</code>:</p>
<pre><code>$ ls -ld examples
drwxr-xr-x  11 gabor  staff  374 Jan 31 10:52 examples
</code></pre>
<p>Давайте разберем нашу программу:</p>
<pre><code class="language-javascript">var fs = require('fs');

if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; path/to&quot;);
    process.exit(-1);
}

var path = process.argv[2];
</code></pre>
<p>После загрузки библиотеки <code>fs</code> мы проверяем количество <a href="/argv-raw-command-line-arguments-in-nodejs">аргументов, полученных через командную строку</a>. Если их 2 или меньше (я не уверен, что меньше двух вообще возможно), значит пользователь вообще не передал никаких аргументов.
(Если пользователь выполнил <code>node examples/node/stats.js</code>, тогда мы получим два аргумента). В этом случае мы выводим пользователю подсказку:</p>
<pre><code>$ node examples/node/stats.js
Usage: /home/gabor/code-maven/examples/node/stats.js path/to
</code></pre>
<p>Глобальная переменная <code>__filename</code> (начинается с двух подчеркиваний) содержит полный путь к текущему выполняемому файлу.
Затем вызываем <code>process.exit()</code> для <a href="/how-to-exit-a-nodejs-script">немедленного завершения работы</a>.</p>
<p>Последний шаг в этом фрагменте кода - получаем третий элемент (его индекс равен 2) из <code>argv</code>, который содержит значение, переданное пользователем в командной строке, и присваиваем его переменной <code>path</code>.</p>
<h2 class="title is-4">Вызов fs.stat</h2>
<p>Затем мы вызвали метод <a href="http://nodejs.org/api/fs.html#fs_fs_stat_path_callback">stat</a>, передав в него <code>path</code> и функцию-коллбек. Эта функция получит объект ошибки (если она случится) и объект <a href="http://nodejs.org/api/fs.html#fs_class_fs_stats">fs.Stats</a></p>
<pre><code class="language-javascript">fs.stat(path, function(err, stats) {
</code></pre>
<p>Объект <code>Stats</code> содержит данные, полученные из inode (в нашем случае это выглядит так:)</p>
<pre><code>{ dev: 16777220,
  mode: 16877,
  nlink: 11,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 32548075,
  size: 374,
  blocks: 0,
  atime: Sat Jan 31 2015 10:56:30 GMT+0200 (IST),
  mtime: Sat Jan 31 2015 10:52:13 GMT+0200 (IST),
  ctime: Sat Jan 31 2015 10:52:13 GMT+0200 (IST) }
</code></pre>
<p>Кроме этого, <code>Stats</code> предоставляет несколько методов для большего удобства.</p>
<p>Мы получили набор данных, где <code>dev</code> - номер устройства. Это может быть полезным, если у вас несколько разделов или физических дисков.</p>
<p><code>mode</code> содержит много информации, включая тип элемента (файл/директория/символьная ссылка) и права доступа.</p>
<p><code>uid</code> - идентификатор владельца элемента.</p>
<p><code>gid</code> - идентификатор группы владельца.</p>
<p><code>size</code> - размер в байтах.</p>
<p><code>atime</code>, <code>mtime</code>, и <code>ctime</code> - время последнего доступа, изменения и создания элемента.</p>
<p>Прежде, чем мы начнем детально разбираться с <code>mode</code>, давайте рассмотрим несколько вспомогательных функций:</p>
<p><code>isFile()</code> вернет <code>True</code>, если это файл.</p>
<p><code>isDirectory()</code> вернет <code>True</code>, если это директория.</p>
<p>В <a href="http://nodejs.org/api/fs.html#fs_class_fs_stats">документации по fs.Stat</a> перечислены еще несколько подобных функций.</p>
<p>Обратиться к остальным значениям можно обычным для JavaScript способом:
К примеру, вот так можно получить значение для 'size':</p>
<h2 class="title is-4">Размер файла в Node.js</h2>
<pre><code class="language-javascript">console.log('    size: ' + stats[&quot;size&quot;]);
</code></pre>
<h2 class="title is-4">Права доступа к файлу</h2>
<p>Раздел документации <a href="http://man7.org/linux/man-pages/man2/stat.2.html">man 2 stat</a> описывает, как трактовать значение <code>mode</code>, которое в нашем случае равно 16877.</p>
<p>Нам нужно использовать специальные битовые маски, чтобы определить, установлены ли нужные нам биты в 0 или в 1.
Например, <code>mode &amp; 1</code> будет равно 1, если правый бит в <code>mode</code> установлен в 1.</p>
<p><code>mode &amp; 2</code> будет равно 2, если второй бит справа установлен в 1, и 0, если это не так.</p>
<p><code>mode &amp; 4</code> будет равно 4, если третий (!) бит справа установлен в 1, и 0, если нет.</p>
<p>К счастью JavaScript все числа, кроме 0, рассматривает как True. Таким образом, мы можем использовать тернарный оператор <code>?:</code> для возврата каких-нибудь подходящих символов, если значение выражения отлично от 0, и возвращать <code>-</code> если оно равно 0.</p>
<p>Таким образом, мы можем выводить символы <code>rwx-</code> по аналогии с командой <code>ls -ld</code>.</p>
<p>Кроме прав доступа на файл из <code>mode</code> мы можем получить тип файла, но для этого у нас есть более удобный способ, описанный выше.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Как завершить работу скрипта Node.js</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-11T14:22:01Z</updated>
    <pubDate>2015-02-11T14:22:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/how-to-exit-a-nodejs-script" />
    <id>https://rust.code-maven.com/how-to-exit-a-nodejs-script</id>
    <content type="html"><![CDATA[<p>Обычно скрипт для Node.js завершает работу при достижении конца программы и если не осталось активных обработчиков событий.
Что делать, если нужно завершить его работу раньше?</p>
<p>Это довольно просто.</p>
<p>У встроенного модуля <a href="http://nodejs.org/api/process.html">process</a> есть метод <a href="http://nodejs.org/api/process.html#process_process_exit_code">exit</a>:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/process_exit.js">examples/node/process_exit.js</a></strong></p>
<pre><code class="language-js">process.exit(-1);

</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Чтение файла с Node.js - блокирующее и неблокирующее</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-07T10:03:01Z</updated>
    <pubDate>2015-02-07T10:03:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/reading-a-file-with-nodejs" />
    <id>https://rust.code-maven.com/reading-a-file-with-nodejs</id>
    <content type="html"><![CDATA[<p>Если вы хотите сделать веб-сервер на Node.js или просто какое-то приложение, тогда вам нужно уметь читать файлы.</p>
<p>Node предоставляет библиотеку <a href="http://nodejs.org/api/fs.html">fs</a> для работы с файловой системой. К примеру, для чтения файлов.</p>
<h2 class="title is-4">Асинхронное чтение файла (неблокирующее)</h2>
<p>&quot;Нормальный&quot; способ чтения файлов в Node.js это чтение асинхронным способом. Это значит, что вы вызываете команду чтения файла и передаете callback, который будет вызван при завершении чтения. Это позволяет работать с несколькими запросами чтения параллельно.</p>
<p>Для этого мы можем использовать метод <a href="http://nodejs.org/api/fs.html#fs_fs_readfile_filename_options_callback">readFile</a> из класса <code>fs</code>.</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/non-blocking-read-file.js">examples/node/non-blocking-read-file.js</a></strong></p>
<pre><code class="language-js">var fs = require('fs');

fs.readFile('DATA', 'utf8', function(err, contents) {
    console.log(contents);
});

console.log('after calling readFile');


</code></pre>
<p>Для начала мы загружаем класс <code>fs</code> с помощью команды <code>require</code>. Затем вызываем метод <code>readFile</code>, который получает 3 параметра: имя файла ('DATA' в нашем случае), кодировку файла ('utf8' в примере) и функцию. Эта функция будет вызывана, когда завершится операция чтения файла. Функция получит два параметра. Первый - информация о каких-либо ошибках, второй - содержимое файла.</p>
<p>Как только программа будет запущена, Node начнет читать файл в фоновом режиме, но продолжит выполнение. Таким образом, сначала будет выполнен вызов <code>console.log('after calling readFile');</code>, который выведет этот текст в консоль.
Затем, когда содержимое файла будет загружено в память, Node вызовет функцию, которую мы передали в метод <code>readFile</code>, и она выведет в консоль содержимое файла.</p>
<h2 class="title is-4">Синхронное чтение файла (блокирующее)</h2>
<p>Люди, пришедшие из других языков программирования (из большинства), считают синхронное чтение файлов более очевидным. Я не знаю в какой ситуации вы захотите использовать синхронные операции в Node.js, но я вижу, что много асинхронных функций имеют синхронный вариант, наверное, этим кто-то пользуется.</p>
<p>Для чтения файлов вы можете использовать метод <a href="http://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_options">readFileSync</a> из класса <code>fs</code>:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/blocking-read-file.js">examples/node/blocking-read-file.js</a></strong></p>
<pre><code class="language-js">var fs = require('fs');

var contents = fs.readFileSync('DATA', 'utf8');
console.log(contents);


</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>argv - необработанные аргументы командной строки в Node.js</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-02T16:00:01Z</updated>
    <pubDate>2015-02-02T16:00:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/argv-raw-command-line-arguments-in-nodejs" />
    <id>https://rust.code-maven.com/argv-raw-command-line-arguments-in-nodejs</id>
    <content type="html"><![CDATA[<p>Людям, приходящим из мира клиентского JavaScript-а, не приходилось иметь дело с командной строкой, но если Вы пишете серверное приложение, то высока вероятность, что придётся столкнуться с консолью в Linux/Unix. (А если вам не повезло, тогда, может быть, даже и с командной строкой MS Windows)</p>
<p>Node.js предоставляет простой способ доступа к сырым данным, передаваемым в командной строке.</p>
<p>В общем случае в командной строке вы можете передать все типы значений:</p>
<p>Список имен: <code>node app.js file1 file2</code></p>
<p>Пары ключ-значение: <code>node app.js --port NUMBER --dir PATH</code></p>
<p>Флаги, без значений: <code>node app.js --debug --verbose</code></p>
<p>Может быть, вам даже захочется передать односимвольные флаги: <code>node app.js -d -v</code></p>
<p>И их даже можно комбинировать: <code>node app.js -dv --port NUMBER --dir PATH  file1 file2</code></p>
<p>По умолчанию Node.js предоставляет объект <a href="http://nodejs.org/api/process.html#process_process_argv">process</a>, содержащий элемент <a href="http://nodejs.org/api/process.html#process_process_argv">argv</a>, который является массивом всех значений, полученных из командной строки:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/raw_command_line_arguments.js">examples/node/raw_command_line_arguments.js</a></strong></p>
<pre><code class="language-js">console.log(process.argv);

</code></pre>
<p>Прим.: вам даже не нужно загружать <code>process</code> вручную, так как он загружен по умолчанию.</p>
<p>Запустив команду: <code>node examples/node/raw_command_line_arguments.js -dv --port NUMBER --dir PATH  file1 file2</code></p>
<p>мы получим:</p>
<pre><code>[ 'node',
  '/Users/gabor/work/code-maven.com/examples/node/raw_command_line_arguments.js',
  '-dv',
  '--port',
  'NUMBER',
  '--dir',
  'PATH',
  'file1',
  'file2' ]
</code></pre>
<p>Прим.:</p>
<p>Первый элемент - всегда <code>node</code>.</p>
<p>Второй элемент - имя файла для исполнения.</p>
<p>Оставшиеся элементы - значения, переданные в командной строке после имени файла.</p>
<p>В принципе, это просто список всех значений, которые вы ввели в командной строке.</p>
<p>Вы можете пройти циклом по этому массиву с помощью <code>for</code> или <code>forEach</code> и получить эти значения. Способ подойдет для большинства простых случаев, но чаще параметры довольно сложные, и лучше использовать специальную библиотеку.</p>
<p>В качестве примера я нашел вот эти: <a href="https://www.npmjs.com/package/minimist">minimist</a>,
<a href="https://github.com/harthur/nomnom">nomnom</a> и
<a href="https://github.com/chevex/yargs">yargs</a>
(fork от <a href="https://github.com/substack/node-optimist">node-optimist</a>)</p>
<p>Пока не могу ничего сказать про них, но думаю, если нужно будет работать с более сложными аргументами, то придется попробовать что-нибудь из этого.</p>
<h2 class="title is-4">Полезные сниппеты для скриптов, работающих из командной строки</h2>
<p>Когда вам не нужно обрабатывать множество аргументов командной строки, но вы все еще хотите быть уверенными,
что пользователь передал какое-то значение, то можете использовать следующий прием:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/argv.js">examples/node/argv.js</a></strong></p>
<pre><code class="language-js">if (process.argv.length &lt;= 2) {
    console.log(&quot;Usage: &quot; + __filename + &quot; SOME_PARAM&quot;);
    process.exit(-1);
}

var param = process.argv[2];

console.log('Param: ' + param);



</code></pre>
<p>В этом примере мы проверяем, что количество элементов в массиве <code>process.argv</code> меньше или равно 2.
Я не знаю, может ли оно вообще быть меньше 2, но если оно равно 2, тогда мы точно знаем, что пользователь не передал никаких параметров в командной строке.
Затем мы выводим строку &quot;Usage: &quot;, имя нашего файла (<code>__filename</code> содержит имя текущего файла) и некоторую информацию о том,
чего мы ожидаем получить от пользователя. Возможно, вместо фразы &quot; SOME_PARAM&quot; вы захотите написать что-то более конкретное.
К примеру, &quot;MACHINE_NAME&quot;, если нужно указать имя машины, или &quot;URL&quot;, если нужно указать URL.</p>
<p>Затем мы вызываем команду <a href="/how-to-exit-a-nodejs-script">exit</a>, чтобы завершить работу,
так как больше нет смысла продолжать выполнение программы, не получив необходимых параметров.</p>
<p>Остальная часть программы, конечно, может быть такой, как вы хотите.
В нашем случае, дальше есть только <code>console.log('Param: ' + param);</code> для индикации, что выполнение дошло до этого места.</p>
<p>Вот так это работает:</p>
<pre><code>$ node argv.js 
Usage: /home/gabor/code-maven/examples/node/argv.js SOME_PARAM
</code></pre>
<pre><code>$ node argv.js hello
Param: hello
</code></pre>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Code Maven - Keywords</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-02T15:15:03Z</updated>
    <pubDate>2015-02-02T15:15:03Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/keywords" />
    <id>https://rust.code-maven.com/keywords</id>
    <content type="html"><![CDATA[<p>This is the list of keywords or topics you can find articles about. You can look up these keywords from anywhere on the
site by typing the keyword in the box at the top of the page.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>About Code Maven</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-02T15:15:02Z</updated>
    <pubDate>2015-02-02T15:15:02Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/about" />
    <id>https://rust.code-maven.com/about</id>
    <content type="html"><![CDATA[<p>See <a href="http://code-maven.com/about">here</a>.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Code Maven - for people who code</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-02T15:15:01Z</updated>
    <pubDate>2015-02-02T15:15:01Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/" />
    <id>https://rust.code-maven.com/</id>
    <content type="html"><![CDATA[<h2 class="title is-4">Добро пожаловать на Code Maven и приятного чтения!</h2>
<p>Если вы не хотите пропускать свежие статьи, то можете подписаться на рассылку, следить за новостями через <a href="/atom">atom feed</a>, или через мой аккаунт.</p>
<p>Если вы хотите участвовать в переводе статей на другие языки, пожалуйста, свяжитесь любым удобным способом!</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Начинаем с Node.js</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-02T14:30:00Z</updated>
    <pubDate>2015-02-02T14:30:00Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/getting-started-with-nodejs" />
    <id>https://rust.code-maven.com/getting-started-with-nodejs</id>
    <content type="html"><![CDATA[<p>Посмотрев первые главы нескольких учебников по Node.js, я подумал, что стоит тоже начать с простого примера &quot;Hello World&quot;.</p>
<p>Прежде, чем вы начнете, возможно вам нужно будет установить <a href="http://nodejs.org/">Node.js</a>, но я не хочу утомлять вас этими подробностями.
На OSX все было вполне очевидно, а на других операционных системах я еще не пробовал.</p>
<h2 class="title is-4">Hello World</h2>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/hello_world.js">examples/node/hello_world.js</a></strong></p>
<pre><code class="language-js">var http = require('http');

var s = http.createServer(function(request, response) {
    response.writeHead(200);
    response.write(&quot;Hello World&quot;);
    response.end();
});

s.listen(8080);

console.log(&quot;Listening on http://127.0.0.1:8080/&quot;);

</code></pre>
<p>В первой строке этого примера мы загрузили библиотеку <a href="http://nodejs.org/api/http.html">&gt;http</a>, которая предоставляет все необходимые инструменты для запуска простого неблокирующего веб-сервера.</p>
<p>Затем мы создали объект сервера, используя метод <a href="http://nodejs.org/api/http.html#http_http_createserver_requestlistener">&gt;createServer</a> из только что подгруженного класса <code>http</code>. Это метод получает единственный параметр - функцию. Каждый раз, когда пользователь будет обращаться к вашему веб-серверу, будет вызываться эта функция, получающая два параметра. Первый из них представляет собой текущий <code>request</code> (запрос), а второй - текущий <code>response</code> (ответ).</p>
<p>В этом примере нам все равно, что запрашивает пользователь (следовательно, мы не анализируем объект запроса), мы просто отправляем ответ.
Сначала мы устанавливаем заголовок ответа <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes">200 OK HTTP status code</a>,
который означает &quot;все в порядке&quot;. Затем мы отправляем содержимое нашей страницы, и в конце вызываем метод <code>end()</code> объекта</p>
<h1 class="title">response</h1>, означающий конец ответа.
<p>Мы получили объект сервера, созданный методом <code>createServer</code>, и присвоили его переменной <code>s</code>.
Затем вызвали метод <code>listen</code> этого объекта, чтобы запустить сервер.</p>
<p>Node.JS это событийно-ориентированная технология, мы запустили &quot;event loop&quot; для прослушивания событий на порту 8080.
Последняя строка в примере - просто вывод в консоль (командная строка, где мы запустили этот код), сообщающий пользователю,
как зайти через браузер.</p>
<p>Как только я это написал, то сразу же и запустил:</p>
<p><code>node examples/node/hello_world.js</code></p>
<p>Что получилось?</p>
<pre><code>Listening on http://127.0.0.1:8080/

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: listen EADDRINUSE
    at errnoException (net.js:905:11)
    at Server._listen2 (net.js:1043:14)
    at listen (net.js:1065:10)
    at Server.listen (net.js:1139:5)
    at Object.&lt;anonymous&gt; (/Users/gabor/work/articles/code-maven/examples/node/hello_world.js:9:3)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
</code></pre>
<p>Отлично, он написал мне &quot;Listening ....&quot; в консоли, но почему же он не запустился?</p>
<p>Мне потребовалось какое-то время, чтобы найти другое приложение, занявшее этот порт.</p>
<p>Думаю, было бы весьма полезно, если бы сообщение об ошибке включало какую-нибудь подсказку, в чем может быть проблема.</p>
<p>В общем, я изменил порт <code>s.listen(8081);</code> и снова запустил код:</p>
<p><code>node examples/node/hello_world.js</code></p>
<p>Он вывел вот это в консоль и стал ждать.</p>
<pre><code>Listening on http://127.0.0.1:8080/
</code></pre>
<p>Но почему он пишет, что слушает порт 8080? Я же только что изменил его на 8081.</p>
<p>А, ну конечно, номер 8080 у меня встречается в двух местах в коде, а я заменил только в одном.</p>
<p>Это нарушает один из важнейших принципов программирования, называемый
<a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY - Do Not Repeat Yourself</a> (Не повторяй себя).
Лучше будет присвоить номер порта какой-нибудь переменной, а затем везде использовать ее.</p>
<p>Новый вариант кода почти такой же:</p>
<p><strong><a href="https://github.com/szabgab/rust.code-maven.com/tree/main/examples/node/hello_world_port.js">examples/node/hello_world_port.js</a></strong></p>
<pre><code class="language-js">var http = require('http');

var port = 8081;

var s = http.createServer(function(request, response) {
    response.writeHead(200);
    response.write(&quot;Hello World&quot;);
    response.end();
});

s.listen(port);

console.log(&quot;Listening on http://127.0.0.1:&quot; + port + &quot;/&quot;);


</code></pre>
<p>Запускаем вот так:</p>
<p><code>node examples/node/hello_world_port.js</code></p>
<p>Теперь, если я открою браузер и наберу там <a href="http://127.0.0.1:8081/">http://127.0.0.1:8081/</a>, то увижу &quot;Hello World&quot;.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

  <entry>
    <title>Zero</title>
    <summary type="html"><![CDATA[]]></summary>
    <updated>2015-02-02T14:00:00Z</updated>
    <pubDate>2015-02-02T14:00:00Z</pubDate>
    <link rel="alternate" type="text/html" href="https://rust.code-maven.com/zero" />
    <id>https://rust.code-maven.com/zero</id>
    <content type="html"><![CDATA[<p>Это первый пост, но, как и в большинстве языков программирования, мы начнем считать с нуля...</p>
<p>Мне бы стоило написать здесь что-нибудь глубокомысленное - все-таки я запустил новый сайт
и планирую писать здесь обо всем. Ладно, почти обо всем. Возможно, я не буду много писать о Perl,
потому что я пишу о нем тут: <a href="https://perlmaven.com/">Perl Maven</a></p>
<p>Раньше я много писал на &quot;Perl Maven&quot; (на сегодняшний день эти статьи ежедневно привлекают не мало читателей), но мне хотелось расширить содержание сайта, чтобы охватить все остальные языки и технологии.</p>
<p>Я размышлял, стоит ли мне просто разместить все эти статьи на сайте &quot;Perl Maven&quot;, но в итоге подумал,
что будет лучше сделать отдельный сайт, в имени которого не будет какого-то конкретного языка программирования.</p>
<p>Итак, давайте начнем.</p>
]]></content>
    <author>
      <name></name>
    </author>
  </entry>

</feed>

