31 июля 2011 г.

Html5 Workers

WebWorkers - делают возможным динамическую загрузку JS файлов и запуска их в фоновом потоке.
Пояснительный пример, основная страница:
Copy Source | Copy HTML
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4.     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  5. <script>
  6. window.onload = function () {
  7.     var worker = new Worker("message.js");// Creates a Web Worker
  8.     worker.onmessage = function (e) {// Triggered by postMessage in the Web Worker
  9.         document.write('Worker said: ', e.data);// e.data is the values from the Web Worker
  10.     };
  11.     worker.onerror = function (e) {// If the Web Worker throws an error
  12.         document.write(e.data);
  13.     };
  14.     worker.postMessage('World!'); // Send data to our worker.
  15. };
  16. </script>
  17. </head>
  18. <body>
  19. </body>
  20. </html>
Для запуска фонового процесса создается экземпляр объекта Workers с указанным путем до скрипта. Сообщение  между основной запускаемой страницей и фоновым потоком происходит при помощи метода postMessage.
Пример message.js:
Copy Source | Copy HTML
  1. onmessage = function (evt) {
  2.     postMessage("hello "+evt.data+"!");
  3. };
В запускаемом файле есть допуск к объекту контекста this или self, который можно использовать:
Copy Source | Copy HTML
  1. self.addEventListener('message', function(e) {
  2.     var rez="hello "+e.data+"!";
  3.     self.postMessage(rez);
  4. }, false);

Возможности доступные в Workers

Из того что можно запустить в основоном потоке в  Workers доступны,
navigator object
location object (read-only)
XMLHttpRequest
setTimeout()/clearTimeout() and setInterval()/clearInterval()
The Application Cache
Импорт внешних скриптов при помощи вызова метода importScripts()
Запуск других фоновых объектов
Workers не имеет доступа к:
DOM (it's not thread-safe)
window object
document object
parent object

В Workers  есть возможность загрузки внешних скриптов при помощи вызова метода importScripts(). Метод importScripts может принимать несколько параметров с указанием путей до файлов:
importScripts('script1.js', 'script2.js');
Почитать больше можно на - www.html5rocks.com

Ajax Hello world! пример использования

Ajax наиболее кроссбраузерный способ передать данные на сервер и получить ответ обратно без перезагрузки страницы.
Приведу небольшой пример в стиле "Hello world!" по применению этой техники:

Всю рутиную работу с Ajax, обработкой событий можно свести в одну библиотеку которую написать самому или использовать одну из самых ходовых (например с JQuery), чтобы не мучатся с поиском ошибок.
Для демонстрации возможностей приведу примитивные варианты на js и php  без каких либо сторонних библиотек.

Свой велосипед за 5 минут:
Copy Source | Copy HTML
  1. //Небольшая подборка объектов которая может пригодится при использовании AJAX
  2. //На самом деле код немного излишний - необходимости в детектирования IE 5 уже наверное нету 
  3. //Код на скорую руку!
  4. function AjaxObject(){
  5.     var browser=detectBrowser();
  6.     if (typeof XMLHttpRequest=="undefined"){
  7.         //window.XDomainRequest
  8.         XMLHttpRequest=function(){
  9.             return new ActiveXObject(browser.isMsie5? "Microsoft.XMLHTTP":"Msxml2.XMLHTTP");
  10.         };
  11.     }
  12.     this.xhr=new XMLHttpRequest();
  13. }
  14. //property:
  15. //.postOrGet =true if post, false if get
  16. //.onResponce =function(xhr_object)
  17. //.url
  18. //.data - data for send
  19. //.type - dataType: application/x-www-form-urlencoded or text/xml
  20. AjaxObject.prototype.start=function(property){
  21.     var self=this;
  22.     if(self.xhr){
  23.         self.xhr.onreadystatechange = function(){
  24.             if (self.xhr.readyState == 4){
  25.                 property.onResponce(self.xhr);
  26.             }
  27.         };
  28.         self.xhr.open((property.postOrGet ? "POST" : "GET"),property.url,true);//true- asynchrone, false -synchrone
  29.         if (property.type && property.postOrGet){
  30.             self.xhr.setRequestHeader("Content-Type", property.type);
  31.             if(self.xhr.ovverideMimeType)
  32.                 self.xhr.setRequestHeader("Connection","close");
  33.         }
  34.         self.xhr.send((property.postOrGet ? property.data : null));
  35.     }
  36. };
  37. // Events fix
  38. function events(o, event_name, handler){
  39.     if (o.addEventListener != undefined) {
  40.         o.addEventListener(event_name, handler, false);
  41.     }else if (o.attachEvent != undefined) {
  42.         o.attachEvent(event_name, handler);
  43.     }
  44. }
  45. // IE or not IE
  46. function detectBrowser(){
  47. var _ua = navigator.userAgent;
  48. return {
  49.   isMsie: (/msie/i.test(_ua) && !/opera/i.test(_ua)),
  50.   isMsie5: (/msie 5/i.test(_ua) && !/opera/i.test(_ua)),
  51.   isMsie6: (/msie 6/i.test(_ua) && !/opera/i.test(_ua)),
  52.   isMsie7: (/msie 7/i.test(_ua) && !/opera/i.test(_ua)),
  53.   isMsie8: (/msie 8/i.test(_ua) && !/opera/i.test(_ua)),
  54.   isMsie9: (/msie 9/i.test(_ua) && !/opera/i.test(_ua)),
  55. };
  56. }

Пример #1 Необходимо передать что-то на сервер методом GET:


Copy Source | Copy HTML
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <title>Ajax with get method</title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  6. <script src="ajaxObject.js"></script>
  7. <script>
  8. window.onload=function(){
  9.     //DOM elements:
  10.     var textField1=document.getElementById("textField1");
  11.     var sendButton1=document.getElementById("sendButton1");
  12.     var p_buf=document.getElementById("buf");
  13.     //Ajax objects & properties:
  14.     var ajObj= new AjaxObject();
  15.     var options={
  16.         postOrGet: false, //use Get method
  17.         onResponce:function(xhr){
  18.             if (xhr.status >= 200 && xhr.status<300){
  19.                 //Ok!
  20.                 if (p_buf.innerText!=undefined)
  21.                     p_buf.innerText=xhr.responseText;
  22.                 else
  23.                     p_buf.textContent=xhr.responseText;//in FF
  24.             }
  25.             else
  26.                 if (p_buf.innerText!=undefined)
  27.                     p_buf.innerText="trouble on recieve!";
  28.                 else
  29.                     p_buf.textContent="trouble on recieve!";//in FF
  30.  
  31.         },
  32.     };
  33.     //Event handlers:
  34.     var clickHandler=function(e){
  35.         options.url="ajax_get.php?name="+encodeURIComponent(textField1.value);
  36.         ajObj.start(options);
  37.     };
  38.     events(sendButton1, "click",clickHandler);
  39. }
  40. </script>
  41. </head>
  42. <body>
  43.     <p>Enter name:</p>
  44.     <input type="text" id="textField1"/>
  45.     <input type="button" id="sendButton1" value="Send name"/>
  46.     <p id="buf"></p>
  47. </body>
  48. </html>
Код ajax_get.php:
Copy Source | Copy HTML
  1. <?php
  2.     if ($_GET["name"]!="")
  3.         echo "hello ",$_GET["name"],"!";
  4.     else
  5.         echo "Please, Enter name and try again! ";
  6. ?>

Пример #2 Необходимо передать что-то на сервер методом POST (urlEncoded data):


Copy Source | Copy HTML
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <title>Ajax with post method</title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  6. <script src="ajaxObject.js"></script>
  7. <script>
  8. window.onload=function(){
  9.     //DOM elements:
  10.     var textField1=document.getElementById("textField1");
  11.     var sendButton1=document.getElementById("sendButton1");
  12.     var p_buf=document.getElementById("buf");
  13.     //Ajax objects & properties:
  14.     var ajObj= new AjaxObject();
  15.     var options={
  16.         postOrGet: true, //use Get method
  17.         onResponce:function(xhr){
  18.             if (xhr.status >= 200 && xhr.status<300){
  19.                 //Ok!
  20.                 if (p_buf.innerText!=undefined)
  21.                     p_buf.innerText=xhr.responseText;
  22.                 else
  23.                     p_buf.textContent=xhr.responseText;//in FF
  24.             }
  25.             else
  26.                 if (p_buf.innerText!=undefined)
  27.                     p_buf.innerText="trouble on recieve!";
  28.                 else
  29.                     p_buf.textContent="trouble on recieve!";//in FF
  30.         },
  31.         type:"application/x-www-form-urlencoded",
  32.     };
  33.     //Event handlers:
  34.     var clickHandler=function(e){
  35.         options.url="ajax_post.php";
  36.         options.data="name="+encodeURIComponent(textField1.value);
  37.         ajObj.start(options);
  38.     };
  39.     events(sendButton1, "click",clickHandler);
  40. }
  41. </script>
  42. </head>
  43. <body>
  44.     <p>Enter name:</p>
  45.     <input type="text" id="textField1"/>
  46.     <input type="button" id="sendButton1" value="Send name"/>
  47.     <p id="buf"></p>
  48. </body>
  49. </html>
Код ajax_post.php:
Copy Source | Copy HTML
  1. <?php
  2.     if ($_POST["name"]!="")
  3.         echo "hello ",$_POST["name"],"!";# send data on page
  4.     else
  5.         echo "Please, Enter name and try again! ";
  6. ?>

Пример #3 Необходимо передать что-то на сервер методом POST (xml data):

Copy Source | Copy HTML
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <title>Ajax with post method and XML</title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  6. <script src="ajaxObject.js"></script>
  7. <script>
  8. window.onload=function(){
  9.     //DOM elements:
  10.     var textField1=document.getElementById("textField1");
  11.     var sendButton1=document.getElementById("sendButton1");
  12.     var p_buf=document.getElementById("buf");
  13.     //Ajax objects & properties:
  14.     var ajObj= new AjaxObject();
  15.     var options={
  16.         postOrGet: true, //use Get method
  17.         onResponce:function(xhr){
  18.             if (xhr.status >= 200 && xhr.status<300){
  19.                 //Ok!
  20.                 if (p_buf.innerText!=undefined)
  21.                     p_buf.innerText=xhr.responseText;
  22.                 else
  23.                     p_buf.textContent=xhr.responseText;//in FF
  24.             }
  25.             else
  26.                 if (p_buf.innerText!=undefined)
  27.                     p_buf.innerText="trouble on recieve!";
  28.                 else
  29.                     p_buf.textContent="trouble on recieve!";//in FF
  30.         },
  31.         type:"text/xml",
  32.     };
  33.     //Event handlers:
  34.     var clickHandler=function(e){
  35.         options.url="ajax_xml_post.php";
  36.         //this is xml data for server
  37.         options.data="<data><name>"+encodeURIComponent(textField1.value)+"</name></data>";
  38.         ajObj.start(options);
  39.     };
  40.     events(sendButton1, "click",clickHandler);
  41. }
  42. </script>
  43. </head>
  44. <body>
  45.     <p>Enter name:</p>
  46.     <input type="text" id="textField1"/>
  47.     <input type="button" id="sendButton1" value="Send name"/>
  48.     <p>That ypur have send:</p>
  49.     <textarea id="buf" style="width:400px; height:200px;"></textarea>
  50. </body>
  51. </html>
Код ajax_xml_post.php:
Copy Source | Copy HTML
  1. <?php
  2. # input xml data
  3. $xml=@file_get_contents('php://input');
  4. #send back what have you send
  5. echo $xml;
  6. ?>
Скачать все одним архивом

24 июля 2011 г.

Заметки про класс URI из Ruby stdlib

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

1. Странное результат парсера:
Пример:
require 'uri'


demo_url=["http://www.host.ru","http://www.host.ru/"]
demo_url.each{|url|
_uri=URI.parse(url)
puts "\nhost: '#{_uri.host}', path: '#{_uri.path}' query: '#{_uri.query}'"
puts "path:"
p _uri.path
puts "host:"
p _uri.host
puts "query:"
p _uri.query


В этом примере на входе два url адреса один с указанием пути, другой без, но оба без указания параметров запроса (?var1=pae1&var2=pp && e.t.c.).
можно было бы подумать путь первого url адреса будет равняться nil. Но

host: 'www.host.ru', path: '' query: ''
path:
"" # <= !path.nil? == true, path.emty? ==true
host:
"www.host.ru"
query:  
nil # <= query.nil? == true , Ok!


host: 'www.host.ru', path: '/' query: ''
path:
"/"
host:
"www.host.ru"
query:
nil

В данном случае поведение парсера не логично и не понятно

2. Свойство opaque экземпляра класса URI, темное пятно в вашем url:
С английского термин можно перевести как темный, непрозрачный.
При попытка распарсить ссылку на почту (mailto:login@host) парсер выдавал ошибку opaque or fragment not null.
В документации http://www.ruby-doc.org/stdlib/libdoc/uri/rdoc/ написано:
# File uri/generic.rb, line 568
    def opaque=(v)
      check_opaque(v)
      set_opaque(v)
      v
    end
Ребята делавшие документацию ruby не тот фрагмент привели - check_opaque() ??
Метод opaque - возвращает фрагмент url, который не может быть распарсен!(Ruby cookbook стр 537 )

9 июля 2011 г.

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

Для автоматического составителя robots.txt написал регулярное выражение которая выдирает гипперссылки из html страничек (атрибут href из тега  )
Возможно кому-то будет полезным.
Код парсера с пояснением:
/<\s*a#Тег Гиперссылки
 (?:\s+#название аттрибутов и их значения одной строкой не сохраняем
  (?:href\s*=\s*#Выискиваем атрибут хранящий url
   (?:# возможны три варианта записи url в Гиперссылки
    "([^"^']*)"|# "ww.tetrapolis.ru"
    '([^'^']*)'|# 'www.tetrapolis.ru'
    ([\w\d\.=\-_\,\?\/:#]+)# www.tetrapolis.ru, в этом выражении по возможности указаны все возможные символы -
# альтернатива [\S]+ здесь не подходит так как не остановится у ">"
   )
  |\w+\s*=\s*# Обрабатываем все остальные аттрибуты сохранять бессмысленно так как сохраняется значение последнего аттрибута
   (?:
   "[^'^"]*"|# значение аттрибута html тега в двойных кавычках
   '[^'^"]*'|# значение аттрибута html тега в одинарных кавычках
   [\S]+)# записанный без кавычек - это значение не сохраняем поэтому о достоваерности значения можно не беспокоится
  |\w+)#аттрибут гипперссылки без значения (а вдруг такой будет)
 )+# подразумеваем что в гипперссылке как минимум один аттрибут (иначе он нам не нужен)
\s*>/i# ищем без учета регистра
Небольшой пример на ruby использующий этот парсер:

require 'net/http'
require 'uri'
require 'ping'

class RopotsKiller
 def initialize(url_str,proxy_ip_str, proxy_port_int)
  @url=URI.parse(url_str)
  @proxy_addr=proxy_ip_str
  @proxy_port=proxy_port_int
 end
 def internet_connection?
  Ping.pingecho @url.host, 1, 80
 end
 def start
  # если инет через прокси то использыем прокси
  str = ((self.internet_connection?) ?
  (Net::HTTP):
  (Net::HTTP::Proxy(@proxy_addr, @proxy_port))).start(@url.host, @url.port)   
                {|http|
   http.get('/index.php').body
   }
  str #возвращаем код страницы
 end
 
end
rk = RopotsKiller.new("http://www.tetrapolis.ru/index.php","192.168.255.6",8080)
text=rk.start
pattern=/<\s*a(?:\s+(?:href\s*=\s*(?:"([^"^']*)"|'([^'^"]*)'|([\w\d\.=\-_\,\?\/:#]+))|\w+\s*=\s*(?:"[^"^']*"|'[^'^"]*'|[\S]+)|\w+))+\s*>/i
i=0
text.scan(pattern){ |match|
 p match
 i=i+1
}
puts "Length: #{i}"