iframeのloadイベント 【書き直し】

今月の初めに書いた投稿が、完全に勘違いだったので、削除して改めて書き直し。

jQuery(1.7.2)でiframeを動的に生成して、そのloadイベントを書いてたときに、どうしても理解できないことが一つあります。
たぶん、僕が無知なだけかもしれませんが・・・

// <a id="test" href="http://somewhere.url/">iframeにリンク先をロードさせる</a>
// というような、HTMLがあって、

;(function($)
  {
    $('a#test').click(function(ev)
                      {
                        ev.preventDefault();
                        ev.stopPropagation();
                                          
                        //クリックされたアンカータグのhref属性を保存。
                        var href = this.href;
                        
                        //デバッグ用のカウンタ
                        var count = 1

                        //iframeを生成して、そこに読み込ませます。
                        var $iframe = $(document.createElement('iframe')).appendTo(document.body);
                        
                        //onloadイベントでチェック
                        $iframe.load(function()
                                    {
                                      console.log([count++,this.src]);
                                    });

                        //普通に読み込むと、ログには [1,'http://somewhere.url/'] が表示されます。
                        $iframe.attr('src',href);
                        
                        //window.setTimeout(function(){$iframe.attr('src',href);},100);
                        //しかし、IEやFireFoxだとsetTimeoutメソッドで強制的に非同期で読み込ませると、
                        //ログには・・・
                        //---------------------------
                        //[1,'']
                        //[2,'http://somewhere.url/']
                        //---------------------------
                        //と表示され、2回コールされています。
                        //しかし、safariやchromeなどのwebkit系のブラウザでは1回しかコールされません。
                      });
  })(jQuery);

単純にsrc属性を設定してロードした場合だと、どのブラウザでも1回しかコールされない。
だけど、setTimeoutを使用してロードを遅延(非同期)実行させると、IE/Mozilla系ブラウザは2回コールされる。
ただ、タイムアウトミリ秒を1とか10とかのようにすると1回しかコールされないときもある。

よく分からない。そういうものなの???

windowでのマウスイベント

HTMLで超シンプルなスライダーをjQueryで実装していたら、ひさびさに「超トホホ・ミス」をやって1日以上ハマってしまいました。トホホというか、単なる見落としなんですが・・・。

なんか作るとき、chromeを使って確認しているんですが・・・さて出来た!と思ってクソ・ブラウザInternet Explorerで確認すると・・・案の定動かない。IE9ではうごいていたはずなんだが・・・と思ってなにが原因かソースを見ること数時間。あれこれ試行錯誤しても動かない。

で、下のような簡単なコードをIE8で確認したら、うんともすんとも言わない。たぶん、ほとんどの人はこう思ったでしょう、

おまえはあほか!

と。

$(window).click(function(ev)
                {
                  alert('window.click!');
                });

よく考えてみたら、Internet Explorer で windowオブジェクトにonclick とか onmousedown とか onmousemoveとかなかった!というオチ。
エラー吐いてくれればすぐ分かったのに・・・なまじIE9で動いてたもんだから分からなかった。

肝心のスライダーは、こんなん。テストページはこっち。

// 単純なスライダーの一部(とりあえずUI部品だけのテストコード)
// これにコールバックを登録するコードを付け足せばとりあえず完成。の一歩手前。
var $frame = jQuery(document);

jQuery('.slider').mousedown(function(e)
                            {
                              var $slider = jQuery(this);
                              var el = this;
                              
                              if(typeof this.slider !== 'object')
                                this.slider =
                                {
                                  drag  : false,
                                  pos   : 0,
                                  limit : $slider.parent().width() - $slider.width() - parseInt($slider.css('paddingLeft')) - parseInt($slider.css('paddingRight')),
                                  bgcolor: this.style.backgroundColor
                                };

                              this.slider.drag = true;
                              
                              $frame.bind('mousemove.slider',
                                        function(e)
                                        {
                                          if(!el.slider.drag)
                                            return;
                                          
                                          el.slider.prev = el.slider.prev ? el.slider.prev : e.pageX;
                                          
                                          var cur = el.slider.pos + (e.pageX-el.slider.prev);
                                          if(el.slider.limit >= cur && 0 <= cur)
                                            {
                                              el.slider.pos = cur;
                                              el.innerHTML = el.style.marginLeft = cur + 'px';
                                              el.slider.prev = e.pageX;
                                            }
                                          else if(el.slider.limit < cur)
                                            {
                                              el.slider.pos = el.slider.limit;
                                              el.innerHTML = el.style.marginLeft = el.slider.pos + 'px';
                                            }
                                          else if(0 > cur)
                                            {
                                              el.slider.pos = 0
                                                el.innerHTML = el.style.marginLeft = el.slider.pos + 'px';
                                            }
                                        })
                                .bind('mouseup.slider',
                                      function(e)
                                      {
                                        $slider.mouseup();
                                      });
                              
                              e.preventDefault();
                       })
                 .mouseup(function(e)
                       {
                         if(this.slider.drag)
                           {
                             this.slider.drag = false;
                             this.slider.prev = 0;
                             $frame.unbind('.slider');
                           }
                       });

やっつけスクリプトに、えらい時間かけてしまった・・・あ~あ orz

・・・とにかく、一刻も早くIE8を含め、IE10以下のバージョンのInternet Explorerがこの世から消え去ることを願うばかりなり。

iTunesで曲名の列挙

ちょっとメモ。

iTunesに登録した動画・音楽の一覧をプログラムかスクリプトから取得したくて・・・。
はじめに思いついたのは「ライブラリのエクスポート」で得られるXMLファイルから取得する方法。
これは単純にXMLをパースするだけなんで、C# (.NET Framework)で使えるようにラップするクラスを作った。
これを使って、下記のようなコードで曲名を列挙できた。・・・が、

/*
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Linq;
using System.Xml.Linq;
*/

public static void Main(string [] args)
{
  if(args.Length <= 0)
    {
      Console.WriteLine("XMLファイルを指定してください。");
      return;
    }

  string xmlfile = args[0];

  var albums = new Dictionary<string,Album>();

  var xDict = new XDict(xmlfile,"/dict");
  var Tracks = xDict["Tracks"] as XDict;

  foreach(var key in Tracks.Keys)
    {
      var xDictTrack = Tracks[key] as XDict;
      
      //アルバム名がない場合、アーティスト名で作成する。
      if(xDictTrack["Album"] == null)
        xDictTrack["Album"] = xDictTrack["Artist"] ?? "No Album";
      
      var tune = new Tune(xDictTrack);
      
      if(albums.ContainsKey(tune.Album))
        albums[tune.Album].Tunes.Add(tune);
      else
        albums[tune.Album] = new Album(tune);
    }

  foreach(var album in albums.Values)
    {
      Console.WriteLine("---{0}-",album.Name);
      album.Sort(SortBy.Track);
      album.Tunes.ForEach((tune) => Console.WriteLine("{0:D2}:{1}",tune.Track,tune.Name));
    }
}

これを書いてたとき、たまたまGoogleで検索してたら、iTunesアプリケーション自体がCOMオートメーションサーバーを実装していてドキュメントが公開されているのを今更発見しました(笑) なんだ、スクリプトから簡単に曲名からプレイリストの編集までできるんじゃないですか!(^^;;
さっそく https://developer.apple.com/downloads/ で無料のデベロッパー登録?して “iTunes COM for Windows SDK”をダウンロードしドキュメントをゲット。

/*
 wscriptで動かすと延々メッセージボックスがポップアップするので注意。
*/
var	iTunes = WScript.CreateObject("iTunes.Application");
var	tracks = iTunes.LibraryPlaylist.Tracks;
var	num = tracks.Count;
for(var i = 1;i <= num;i++)
 WScript.Echo(tracks.Item(i).Name);

簡単!

最初のXMLから取得する方法は無駄になった・・・けど、C#でXMLを操作する勉強をしたと思えば・・・ま、いいか(^^;

Perlで並列処理

複数のファイルをダウンロードするとき、wget を使っているのですが、複数のファイルをダウンロードするときは、URLのリストをファイルにして、-i でwgetに食わせてました。でもこれだと順番に一個ずつダウンロードしていくので効率が悪いです。サイズの小さなファイルだと気にならないんですが・・・。

で、Perl の system関数で、複数のwgetプロセスを作れば・・・と考えました。けど、ダウンロードするファイル数と同じ数のプロセスを作ると効率が悪いし、ダウンロード先のサーバーに迷惑をかけてしまいます。ので、同時に起動するwgetの数を制限するようにしたらいいんじゃないかと。

起動するプロセス数を制限するには、Parallel::ForkManagerモジュールが簡単で便利でいいんですが・・・Windows環境では不自然・・・ということで、threadsthreads::shared モジュールを選択。

下記のような感じのPerlスクリプトをnohup コマンドで起動すれば、あとはターミナルを切断しても勝手にやってくれる。終わったら携帯にメールを投げるようなコードを付け足せば・・・より便利かなと。

#!/usr/bin/perl

####################################################
# parallel-wget.pl urllist1.txt urllist2.txt ...
#  '-'(ハイフン) を指定すると標準入力から読み込む
#
# Perl 5.8.8 で確認
####################################################
use strict;
use warnings;
use threads;
use threads::shared;
use IO::File;
use File::Basename;

#何個のWGETを起動するか = スレッドの個数
my $NUM = 4;

#wgetコマンド。パスが通ってない場合はフルパスを。
my $WGET_COMMAND = 'wget';

#WGETオプション引数の指定
my @WGET_OPTION = qw(-nd -a Thread%02d.log --content-disposition);
# sprintf関数に渡されます。 %02d には スレッド番号が入ります。

#スレッド間で共有する配列。
my @WGETS : shared;

#Startup code
&{sub
{
  @WGETS = get_wget_commandline(@_);

  my @threads;
  $NUM = scalar(@WGETS) if(@WGETS < $NUM);
  
  #わざわざ $i_ なんて使わず、$_を使えばいいところだけど、
  # $_ を使うと "Scalars leaked: 1" なんてエラーが出るので・・・。
  # ガーベージコレクタのせい? 出たり、出なかったりする。なんで?
  foreach my $i_(1..$NUM)
    {
      push @threads,threads->create(\&ThreadStart,$i_);
    }
  
  $_->join foreach(@threads);
  
}}(@ARGV);

#ワーカースレッド関数
sub ThreadStart
{
  #引数はスレッドの番号
  my $num = shift;
  
  local $| = 1;

  #スレッド間で共有された配列が空になるまでスレッドを回す。
  while(@WGETS)
    {
      my $wget_command_line;
      {
        lock(@WGETS);
        $wget_command_line = shift @WGETS;
      }
      system(sprintf($wget_command_line,$num)) if($wget_command_line);
    }

  print STDERR "Thread($num) terminated...\n";
}

#URLが列挙されているファイルからwgetコマンドラインを組み立て、
#それらを配列に格納して返す。
sub get_wget_commandline
{
  my @retval;

  #code here
  foreach my $ifile_(@_)
    {
      next if($ifile_ ne '-' && !(-e $ifile_));

      my $fin = ($ifile_ eq '-') ? IO::File->new_from_fd(fileno(STDIN),'<') : IO::File->new($ifile_);

      die "can not detect input stream...\n" unless($fin);

      my ($name,$dir,$suffix) = fileparse($ifile_,qr/\.[^\.]*/) if($ifile_ ne '-');

      $name = "wget_$$" unless($name);
      $name = qq("$name") if($name =~ /\s/);

      my $wget_command_line = join(' ',($WGET_COMMAND,@WGET_OPTION,"-P $name",''));
  
      while(my $line = $fin->getline)
        {
          #改行文字、空行を削除
          $line =~ s/[\r\n]+//;
          next if($line =~ /^\s*$/);
          
          push @retval,$wget_command_line . $line;
        }
    }

  return @retval;
}
__END__

Perlでスレッドはなんか怪しい挙動。

Scalars leaked: 1

CentOS環境では上記エラー(警告か?)が出るけど、Windows上のActive Perl では出ない。
foreachとかforのループで、$_を渡すと出たり出なかった・・・?よく分からん。

プロセスの仕組みが根本的に違うWindowsだと並列処理はスレッドベースになって複雑にならざるを得ないのが残念すね。

スレッドプールなモジュールをインストールしようと思ったんですが、単純な問題だったので、そこまでやる必要なかった感じ。

難読化なのか単なる嫌がらせなのか?

(2011/12/29 ちょこっと追記した)

javascriptの難読化についてググってたら、たまたま検索結果にAcme::EyeDropsというPerlモジュールを見かけました。

cpan Acme::EyeDrops か、ActivePerlなら ppm install Acme-EyeDrops とかでインストール。

結構はまってしまいまして・・・eyeファイル作るの楽しいす。自己満ですけど(^^;
eyeファイルは、要は「#」だけでアスキーアートを作ればいいだけ。エディターだけで作るのは手間かかるけど、テキストペイントっていうアプリが一番使いやすい。かなり古いけど。この手のアプリって、なんか有名なものってあるんですかね?

たとえば・・・下記のようなeyeファイル(拡張子はeye)と、

##    ##  #######  ##     ## ########     ######## ##    ## ########  ######    #######  ##    ## ##       ##    ##
 ##  ##  ##     ## ##     ## ##     ##    ##        ##  ##  ##       ##    ##  ##     ## ###   ## ##        ##  ##
  ####   ##     ## ##     ## ##     ##    ##         ####   ##       ##        ##     ## ####  ## ##         ####
   ##    ##     ## ##     ## ########     ######      ##    ######    ######   ##     ## ## ## ## ##          ##
   ##    ##     ## ##     ## ##   ##      ##          ##    ##             ##  ##     ## ##  #### ##          ##
   ##    ##     ## ##     ## ##    ##     ##          ##    ##       ##    ##  ##     ## ##   ### ##          ##
   ##     #######   #######  ##     ##    ########    ##    ########  ######    #######  ##    ## ########    ##
 

下記のように変換するサンプルスクリプトを用意して・・・

#!/usr/bin/perl
#
#  hello world
#
use strict;
use warnings;
use IO::File;

&amp;{sub
{
  IO::File->new_from_fd(fileno(STDERR),'>')->print('Hello,World\n');
  
}}(@ARGV);

下記変換スクリプトで上記ファイルを処理してやると・・・

#!/usr/bin/perl

use strict;
use warnings;

use Acme::EyeDrops qw/sightly/;

#Startup code
&{sub{

  my $command =
    {
      Regex => 0, 
      EyeDir => eyeファイルが置かれているディレクトリパス
      Shape =>; 変換に使用するeyeファイルのベース名
      SourceFile => 変換するPerlファイル
    };

  print sightly($command);

}}(@ARGV);

↓のような感じに変換される。。。これでちゃーーーーんとPerlスクリプトとして動くんだ!
用途は分からんけど・・・(笑) もう嫌がらせの域かと。 実際、忙しい時に、こんなファイルを見せられたら発狂するな(^^;;;
ドキュメントをよく読んでないので分かりませんが、変換後のソースを元に戻す方法あるのかな~?

遠くから見ると、文字に見えてきませんか?(^^;;;

eval eval '"'.


((    ((  '#'))))  .+     (( ('!'))).     '/'.('[' ^+    (( '.'))).(  ('[')^    "(").(  ((    (( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '['   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ))))  ^+ ((         ')')
   ))    .+     (( ((     (( '/')))))     ).('`'      |+    '"').(    ('`')|   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  ')') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ).     (('`')|   ('.')).  ((     ((    '/')))).    +(    '['^'+')  .('`'|    "%").(  ((    (( '['))))^    ((
 
 
((    ((  ')'))))  ))     ). ('`'|','     ).("!"^ ((    (( '+')))))  .('['^    ".").(  ((    (( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '['   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ))))  ^+ ((         '(')
   ))    .(     (( ((     (( '`')))))     )|'%')      .(    ('{')^    '[').(   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '[') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ^+     "(").(   '['^'/'  ).     +(    '['^')')    .(    '`'|')')  .('`'|    "#").(  ((    (( '['))))^    ((
 
 
((    ((  '/'))))  ))     ). ';'.('!'     ^"+").( ((    (( '['))))^  '.').(    '['^'('  ).    +( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '`'   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) |'%'  ). +(         '{'^
   ((    ((     (( ((     (( '[')))))     ))))))      .(    ('[')^    ',').(   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '`') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   |+     "!").(   '['^')'  ).     +(    '`'|'.')    .(    '`'|')')  .('`'|    ".").(  ((    (( '`'))))|    ((
 
 
((    ((  "'"))))  ))     ). ('['^'('     ).";".( ((    (( '!'))))^  '+').(    '['^'.'  ).    +( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '['   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ^'('  ). +(         '`'|
   ((    ((     (( ((     (( '%')))))     ))))))      .(    ('{')^    '[').(   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '`') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ^+     ")").(   '`'^'/'  ).     ((    (':'))).    ((    ":")).(  ('`')^    "&").(  ((    (( '`'))))|    ((
 
 
((    ((  ')'))))  ))     ). ('`'|','     ).("`"| ((    (( '%')))))  .';'.(    '!'^'+'  ).    +( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '!'   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ^'+'  ). ((         '&')
   ).    ((     (( ((     (( '\'))))     )))).+      ((    '{')).    ("["^   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '(') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ).     (('[')^   ".").(  ((     ((    '`'))))|    ((    '"'))).(  ('!')^    ('+')).  ((    (( '\'))))    .+
 
 
((    ((  '{'))))  .(     (( ('!')))^     ('+')).( ((    (( '{'))))^  '[').(    '{'^'['  ).    +( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '`'   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ^')'  ). +(         '`'^
   ((    ((     (( ((     (( '/')))))     ))))))      .+    (':').    ":".(   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '`') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ^+     "&").(   '`'|')'  ).     +(    '`'|',')    .(    '`'|'%')  ."-".    ('>').(  ((    (( '`'))))|    ((
 
 
((    ((  '.'))))  ))     ). ('`'|'%'     ).("["^ ((    (( ',')))))  .'_'.(    '`'|'&'  ).    +( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '['   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ^')'  ). +(         '`'|
   ((    ((     (( ((     (( '/')))))     ))))))      .(    ('`')|    "-").   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '_') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   .(     '`'|'&'   ).('`'|  ((     ((    '$')))))    .+    '('.('`'  |'&').    (('`')|  ((    (( ')')))))    .(
 
 
((    ((  '`'))))  |+     (( ','))).(     '`'|'%') .(    (( ('`')))|  '.').(    '`'|'/'  ).    (( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '('   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) )).(  (( ((         '{')
   ))    )^     (( ((     (( '(')))))     )).''.      +(    ('{')^    '/').(   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '`') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ^+     "$").(   '`'^'%'  ).     +(    '{'^')')    .(    '{'^')')  .")".    ','."'"  .+    (( ('>'))).    ((
 
 
((    ((  "'"))))  ))     .+ ')'.'-'.     '>'.('[' ^+    (( '+'))).(  ('[')^    ")").(  ((    (( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '`'   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ))))  |+ ((         ')')
   ))    .(     (( ((     (( '`')))))     )|'.')      .(    ('[')^    "/").   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '(') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   .+     ('\').   ('"').(  ((     ((    '`'))))^    ((    '('))).(  ('`')|    "%").(  ((    (( '`'))))|    ((
 
 
((    ((  ','))))  ))     ). ('`'|','     ).("`"| ((    (( '/')))))  .','.(    '{'^','  ).    +( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '`'   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) |'/'  ). +(         '['^
   ((    ((     (( ((     (( ')')))))     ))))))      .(    ('`')|    ',').(   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '`') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   |+     ('$')).   ('\').  ((     ((    '\'))))    .(    '`'|'.')  .'\'.    '"'.')'  .+    (( ";")).(    ((
 
 
((    ((  '!'))))  ))     ^+ ('+')).(     '{'^'[') .(    (( ('{')))^  '[').(    '!'^'+'  ).    (( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( (((   (( ((        ((  ((
  '\'   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ))))  )) ))         ))))
   ))    ))     )) ))     )) ))).'}'.     '\'.+      ((    '}')).    ('(').   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '\' ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ).     ('@').(   '`'^'!'  ).     +(    '{'^')')    .(    '`'^"'")  .('{'^    ('-')).  ((    (( ')')))).    ((
 
 
((    ((  ';'))))  ))     .( '!'^'+')     .(('!')^ ((    (( '+')))))  .""";    $:='.'^  ((    (( ((       ((    ((
 ((  ((  ((     (( ((     (( ((     ((    ((        ((  ((  ((       ((    ((  ((     (( '~'   )) ))        ))  ))
  ))))   ))     )) ))     )) ))     ))    ))         ))))   ))       ))        ))     )) ))))  ;( $~         )=((
   ((    ((     (( ((     (( '@')))))     ))))))      )|    '(';$^    =")"^   ((     (( (( (( (( ((          ((
   ((    ((     (( ((     (( ((   ((      ((          ((    ((             ((  ((     (( ((  '[') ))          ))
   ))    ))     )) ))     )) ))    ))     ))          ))    ))       ))    ))  ))     )) ))   ))) ))          ))
   ;(     $/)='`'   |'.';$,  =(     ((    "(")))^    ((    '}'));$  ="`"|    '!';#;#  ;#    ;# ;#;#;#;#    ;#