Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Perl入学式

Perl入学式 #4

http://www.perl-entrance.org

Perl入学式について

会場について

ロゴについて

Perl入学式

IT勉強会スタンプラリー

IT勉強会スタンプラリー

喋ってる人

今日やること(No.1/2)

今日やること(No.2/2)

前回までのおさらい

おさらいする内容

お約束

#!/usr/bin/env perl
use utf8;
use strict;
use warnings;

binmode STDIN,  ":utf8"; # 標準入力
binmode STDOUT, ":utf8"; # 標準出力
binmode STDERR, ":utf8"; # 標準エラー出力

画面に出力する

print "Hello World\n"; # Hello World[改行]
# 命令文の最後は「;」セミコロンを入力
# 「#」の後ろはコメントになる
# 「\n」は[改行]
print 'Hello World\n'; # Hello World\n
# シングルクォートの場合は「\n」がそのまま表示
print "はろーわーるど\n"; # 日本語もOK

変数を使う

代入と演算

my $string;             # 「my」は変数の宣言
$string = '文字列';      # 「=」は右の値を左の変数に代入
print $string . "\n";   # 「.」は文字列の足し算(連結)
my $num  = 123;         # 変数の宣言と代入は同時でもOK
my $num2 = '123';       # 文字列として代入
my $sum = $num + $num2; # 「+」は数値の足し算
print "$num + $num2 は $sum です。\n"; # 答えは246

画面から入力する

print "値を入力してください>>>";
my $input = <STDIN>;          # 入力待ち
print "入力は $input です\n";   # [改行]を含む
chomp($input);                # [改行]を取り除く
print "入力は $input です\n";
print "値2を入力してください>>>";
chomp( my $input2 = <STDIN> ); # 入力待ちと同時でもOK
# print "入力は$input2です\n";   # エラー
print "入力2は${input2}です\n";  # 変数名:$input2
print "入力1は${input}2です\n";  # 変数名:$input

条件分岐

数値として比較(基本)

print "値を入力してください>>>";
chomp( my $in = <STDIN> );
if ( $in == 0 ) {
  # $in == 0 が「真」の場合
  print "入力値${in}は0です\n";
}
else {
  # $in == 0 が「偽」の場合
  print "入力値${in}は0ではありません\n";
}

条件分岐

数値として比較(関係演算子一覧)

my $x = 123;
my $y = 123;
if ( $x == $y ) { print "$x と $y は同じ\n";    }
if ( $x != $y ) { print "$x と $y は違う\n";    }
if ( $x >  $y ) { print "$x は $y より大きい\n"; }
if ( $x <  $y ) { print "$x は $y より小さい\n"; }
if ( $x >= $y ) { print "$x は $y 以上\n";      }
if ( $x <= $y ) { print "$x は $y 以下\n";      }

条件分岐

数値として比較(特殊)

my $result = $x <=> $y;  # $x <=> $y の結果を代入
if ( $result == 0 ) {    # 条件1
  print "$x と $y は同じ\n";
}
elsif ( $result < 0 ) {  # 条件2
  print "$x は $y より小さい\n";
}
else {                   # すべての条件に当てはまらない
  print "$x は $y より大きい\n";
}

条件分岐

文字列として比較(基本)

print "値を入力してください>>>";
chomp( my $in = <STDIN> );
if ( $in eq 'a' ) {
  # $in eq 'a' が「真」の場合
  print "入力値${in}は'a'です\n";
}
else {
  # $in eq 'a' が「偽」の場合
  print "入力値${in}は'a'ではありません\n";
}

条件分岐

文字列として比較(関係演算子一覧)

my $x = 'xyz';
my $y = 'xyz';
if ( $x eq $y ) { print "$x と $y は同じ\n";    }
if ( $x ne $y ) { print "$x と $y は違う\n";    }
if ( $x gt $y ) { print "$x は $y より大きい\n"; }
if ( $x lt $y ) { print "$x は $y より小さい\n"; }
if ( $x ge $y ) { print "$x は $y 以上\n";      }
if ( $x le $y ) { print "$x は $y 以下\n";      }

条件分岐

文字列として比較(特殊)

my $result = $x cmp $y;   # $x cmp $y の結果を代入
if ( $result == 0 ) {     # 条件1
  print "$x と $y は同じ\n";
}
elsif ( $result < 0 ) {   # 条件2
  print "$x は $y より小さい\n";
}
else {                    # すべての条件に当てはまらない
  print "$x は $y より大きい\n";
}

条件分岐

論理演算子一覧

my $x = 1;
my $y = 2;
if ( $x == 1 && $y == 2 ) {
  print "$x は 1 かつ $y は 2 です\n";
}
if ( $x == 2 || $y == 2 ) {
  print "$x は 2 または $y は 2 です\n";
}
if ( ! $y == 1 ) {
  print "$y は 1 ではありません\n";
}

配列

配列の基本

my @array = ('a', 'b', 'c'); # 配列の宣言と代入
print "$array[0]\n";  # a[改行] : 最初の要素
print "$array[1]\n";  # b[改行] : 2つめの要素
print "$array[-1]\n"; # c[改行] : 最後の要素
print "@{array}\n";  # a b c[改行] : 中身を表示
print '@{array}\n';  # @{array}\n : 展開されない
my $array = @array;  # スカラ変数と同じ名前でもOK
print "$array\n";    # 3[改行] : 配列の要素数

配列

配列の操作(No.1/2)

my @empty_array = ();
my @defined_only;
my @array = ('a', 'b', 'c');
push    @array, '最後';    # 最後の要素に加える
unshift @array, '最初';    # 最初の要素に加える
print "@array\n";         # 最初 a b c 最後[改行]
my $pop   = pop   @array; # 最後の要素を取り出す
my $shift = shift @array; # 最初の要素を取り出す
print "@array\n";         # a b c[改行]
print "$pop\n";           # 最後[改行]
print "$shift\n";         # 最初[改行]

配列

配列の操作(No.2/2)

my @array = ('a', 'b', 'c');
my @array2 = reverse(@array);  # 要素を逆並びにする
print "@array2\n";             # c b a[改行]
my @array3 = sort(@array2);    # 要素を順序良く並べる
print "@array3\n";             # a b c[改行]
my $str = join(":", @array);   # 要素を連結する
print "$str\n";                # a:b:c[改行]
my @array4 = split(/:/, $str); # 文字列を分割する
print "@array4\n";             # a b c[改行]

繰り返し

for文

for my $i (1 .. 10) { # 1 から 10 まで
  print "$i\n"; # 1[改行]2[改行]3[改行]...
}
my @array = ('a', 'b', 'c'); # 配列を定義
for my $item ( @array ) {    # 配列の要素
  print $item . "\n"; # a[改行]b[改行]
  if ($item eq 'b') { # $itemが「b」という文字列の場合
  last;             # ループを抜ける(終了する)
  }
}

繰り返し

while文

my $perl = '嫌い';
my $like = '好き';
while ( $perl ne $like ) {
  # 条件が真($perl と $like が違う)の場合はループ内へ
  print "Perlは${like}ですか?[y/N]>>>";
  chomp(my $in = <STDIN>);
  if ( $in eq 'y' || $in eq 'Y' ) {
    $perl = $like;
  }
}
# 条件が偽の場合はループの外へ
print "Perlは${perl}ですよね〜。\n";

perlbrewとcpanmをインストールしよう

インストールしてありますよね?

開発環境の構築

ModernなPerlの開発環境の構築方法

ModernなPerlの開発環境の構築方法

おさらい問題

おさらい問題

標準入力(STDIN)から値を5つ受け取って「受け取った値の全て」と「数値としての最大値」を表示するプログラムを作ってみよう

回答方法

  1. for文と配列を使って書いて実行してみよう
  2. (余裕があれば)「数値としての最小値」も表示してみよう
  3. (余裕があれば)数値として0が入力された場合にエラーを出すようにしよう
  4. (それでも時間があれば)ハッシュタグ「#Perl入学式」でツイートしてみよう

休憩

〜14:40

Perlを便利にする「モジュール」を使おう

最大値と最小値を求める

use List::Util qw(max min);
my @array = (2, 99, 87, 32, -11);
my $max = max(@array);
print $max . "\n"; # 99[改行]
my $min = min(@array);
print $min . "\n"; # -11[改行]

おさらい問題をmaxminを使って書きなおしてみよう!

モジュールとは

CPANとは

Wikipediaより

CPAN(シーパン、Comprehensive Perl Archive Network)とは、Perlのライブラリ・モジュールやその他のPerlで書かれたソフトウェアを集めた巨大なアーカイブで、世界中のサーバにその内容がミラーリングされている。再利用性・汎用性の高いモジュールが登録されており、Perlプログラマができるだけ車輪の再発明をせずに済むための支援環境となっている。登録モジュールの検索システムも提供されているため、Perlプログラマは望む機能を持ったモジュールを容易に入手することができる。

CPANとは

SEARCH CPAN(ウェブサイト)

CPANとは

ウェブ制作に使えるモジュール

CPANとは

ソーシャル関係に使えるモジュール

CPANとは

その他インターネット関係のモジュール

CPANとは

セキュリティ関係のモジュール

CPANとは

日付・時間操作を便利にするモジュール

CPANとは

地味に便利なモジュール

CPANとは

コマンドラインを便利にするモジュール

CPANとは

データの読み書きに使えるモジュール

CPANとは

CPANを活用するのに便利な本

CPANモジュールガイド

CPANとは

cpan(コマンド)

CPANとは

CPANについてのまとめ

cpanmで「モジュール」をインストールしよう

cpanmとは

cpanmの使い方

cpanmでモジュールをインストール

$ cpanm LWP::UserAgent
$ cpanm Data::Dumper::Concise

インストールに失敗したら

$ cpanm --notest --force LWP::UserAgent
$ cpanm --notest --force Data::Dumper::Concise

ウェブページを取得しよう

ウェブページを取得する

サンプルコード

use LWP::UserAgent;
use URI;
my $ua = LWP::UserAgent->new;
$ua->agent('perl-entrance/0.04');
my $url = URI->new('http://ja.wikipedia.org/wiki/Perl');
my $res = $ua->get($url);
die $res->status_line unless $res->is_success;
my $html = $res->decoded_content;
print "$html\n";

書いて実行してみよう!(お約束も忘れずに)

暇な人は「#Perl入学式」でツイートしよう!

コードの解説

何をしているのかだけを簡単に

より詳細な解説(No.1/4)

use LWP::UserAgent;
# 「LWP::UserAgent」というモジュールを使用
use URI;
# 「URI」というモジュールを使用

より詳細な解説(No.2/4)

my $ua = LWP::UserAgent->new;
# $uaという変数を定義し、
# LWP::UserAgentのオブジェクトを作成
$ua->agent('perl-entrance/0.04');
# $uaの「ユーザーエージェント」の名称を変更

より詳細な解説(No.3/4)

my $url = URI->new('http://ja.wikipedia.org/wiki/Perl');
# $urlという変数を定義し、URIのオブジェクトを作成。
my $res = $ua->get($url);
# $resという変数を定義
# $uaが$urlにアクセス(getリクエスト)し、
# その結果(レスポンス)を$resで受け取る
die $res->status_line unless $res->is_success;
# getリクエストが成功していなかったら(unlessはifの逆)
# エラー出力にステータスを表示して異常終了(die)

より詳細な解説(No.4/4)

my $html = $res->decoded_content;
# $htmlという変数を定義
# レスポンスの中身をPerlの内部形式にdecodeする
print "$html\n";
# レスポンスの中身を標準出力に出力

休憩

〜15:35

ウェブページのタイトルを抽出しよう

ウェブページのタイトルを抽出する

サンプルコード

my $title;
if ( $html =~ /<title>(.*?)<\/title>/ms ) {
  $title = $1;
}
else {
  print "titleタグがありません。\n";
}
print "$title\n";

先ほどの続きで書いて実行してみよう!

暇な人は(略

サンプルコードの解説

my $title;
if ( $html =~ /<title>(.*?)<\/title>/ms ) {
  # このif文の中身は「マッチング」と言います
  $title = $1;
  # マッチングの際にカッコを用いると、
  # その部分にマッチした文字列を利用できます
  # $titleに先ほどの「.*?」にマッチした文字列を代入します
}
# (以下略)

マッチング

簡単なマッチング

my $str = 'yes';
if ( $str =~ /y/ ) {
  print "$str には「y」が含まれています\n";
}
else {
  print "$str には「y」が含まれていません\n";
}

書いて実行してみよう!

マッチング

パターンマッチング(正規表現)

my $str = 'Yes';
if ( $str =~ /[yY]/ ) { # [...]の中身のいずれか1文字にマッチ
  print "$str には「y」または「Y」が含まれています\n";
}
if ( $str =~ /y/i ) { # iオプションは大文字小文字を無視してマッチ
  print "$str には「y」または「Y」が含まれています\n";
}

書いて実行してみよう!

マッチング

パターンマッチング(正規表現)の解説

マッチング

「.*?」とは何だったのか?

マッチング

マッチングのルール

my $str = "<title>1<title>2</title>3</title>";
$str =~ /<title>(.)<\/title>/;
print "1番目のマッチ:$1\n";      # 2
$str =~ /<title>(.*)<\/title>/;
print "2番目のマッチ:$1\n";      # 1<title>2</title>3
$str =~ /<title>(.*?)<\/title>/;
print "3番目のマッチ:$1\n";      # 1<title>2

書いて実行してみよう!

マッチング

「.*?」とは何だったのか?

マッチング

\(バックスラッシュ)

$str =~ /<title>(.)<\/title>/;

マッチング

デリミタ(delimiter)について

$str =~ m!<title>(.)</title>!;
$str =~ m|<title>(.)</title>|;
$str =~ m"<title>(.)</title>";
$str =~ m{<title>(.)</title>};

脱線

デリミタ(delimiter)について

my $delimiter = 'デリミタ';
my $str = "通常は\"のようにエスケープします。\n";
$str .= qq|qqを使うとエスケープ"なし"で大丈夫。\n|;
        # ダブルクォート同等
$str .= qq{変数(${delimiter})も展開されます。\n};
$str .= q!qだけの場合は、変数(${delimiter})や\nも展開されません。!;
        # シングルクォート同等
$str .= q|ただし、デリミタの文字(\|)を使う場合はエスケープが必要です。|;
print "$str\n";

書いて実行してみよう!

脱線

デリミタ(delimiter)について

my $str = "<div class=\"apple\">iPhone</div>\n";

my $str = qq{<div class="apple">iPhone</div>\n};

さらに脱線

$str .= 'str';
# ↓と同じ意味
$str  = $str . 'str';

ハッシュを使おう

ハッシュとは

ハッシュとは

代入と出力(スカラー)

my %nqounet; # 最初に「%」をつける
$nqounet{'name'} = 'Nobutaka Wakabayashi';
$nqounet{'born'} = '石川県';
print "$nqounet{'name'}\n";
print "$nqounet{'born'}\n";

右側を自分の情報に変えて書いて実行してみよう!

ハッシュとは

代入と出力(リスト)

my %hash1 = ('one', 'two', 'three', 'four');
my %hash2 = ('1', '2', '3', '4');
print "%hash1\n"; # %hash1[改行]
print %hash1; # threefouronetwo
print "\n";
print %hash2; # 1234
print "\n";

書いて実行してみよう!

ハッシュとは

代入と出力(よりハッシュらしく)

my %hash  = (
  'key1' => 'value1', # '=>'はファットカンマ
  key2   => 'value2', # ほぼ「,(カンマ)」と同じ意味
  # 左側の値を文字列として解釈するので、クォートしなくてもよい
);
print "$hash{key1}\n";   # value1[改行]
print "$hash{'key2'}\n"; # value2[改行]

書いて実行してみよう!

ハッシュとは

配列の不便そうなところ(無理矢理)

my @nqounet = (
  'nqounet',
  '38',
  'Perl',
);
print "twitter : $nqounet[0]\n";
print "age : $nqounet[1]\n";
print "lang : $nqounet[2]\n";

ハッシュとは

ハッシュの便利そうなところ(無理矢理)

my %nqounet = (
  twitter => 'nqounet',
  age     => '38',
  lang    => 'Perl',
);
for my $key ('twitter', 'age', 'lang') {
  print "$key : $nqounet{$key}\n";
}

ハッシュとは

中身を確認する方法

my %nqounet = (
  twitter => 'nqounet',
  age     => '38',
  lang    => 'Perl',
);
while ( my ($key, $value) = each %nqounet ) {
  # 「each」はハッシュのキーと値をペアで返す
  # whileを組み合わせて、すべての中身が確認できる
  print "$key : $value\n";
}

書いて実行してみよう!

休憩

〜16:50

データの中身を確認する

データの中身を確認する

簡単に見る方法はないのか?

もちろん、あります!

変数の中身を確認する

use Data::Dumper::Concise; # Dumperという関数を生成

my %nqounet = (
  twitter => 'nqounet',
  age     => '38',
  lang    => 'Perl',
);
print Dumper( \%nqounet );
# 変数の前に「\(バックスラッシュ)」をつける(解説は後ほど)

書いて実行してみよう!

たくさん情報を持った変数を作ろう

たくさんの情報を持ちたい

やりたいこと

たくさんの情報を持ちたい

配列を代入してみる

use Data::Dumper::Concise;
my @mails = (
  'nobu at nishimiyahara.net',
  'coworking at shin-osaka.in',
);
my @webs = (
  'http://nqou.net',
  'http://www.nishimiyahara.net',
  'http://www.shin-osaka.in',
);
my %nqounet = (
  name => 'nqounet',
  mail => @mails,
  web  => @webs,
);
print Dumper \%nqounet;

書いて実行してみよう!

たくさんの情報を持ちたい

中身を確認する

# 結果
{
  "coworking at shin-osaka.in" => "web",
  "http://nqou.net" => "http://www.nishimiyahara.net",
  "http://www.shin-osaka.in" => undef,
  mail => "nobu at nishimiyahara.net",
  name => "nqounet"
}

たくさんの情報を持ちたい

ハッシュは配列の一種

my @nqounet = ( # 「%」 を 「@」 に変更してみる
  name => 'nqounet',
  mail => @mails,
  web  => @webs,
);
print Dumper \@nqounet; # 「%」 を 「@」 に変更してみる
# 配列の場合も変数の前に「\(バックスラッシュ)」をつける(解説は後ほど)

変更して実行してみよう!

たくさんの情報を持ちたい

中身を確認する

# 結果
[
  "name",
  "nqounet",
  "mail",
  "nobu at nishimiyahara.net",
  "coworking at shin-osaka.in",
  "web",
  "http://nqou.net",
  "http://www.nishimiyahara.net",
  "http://www.shin-osaka.in"
]

たくさんの情報を持ちたい

階層構造を作る

my %nqounet = ( # 「@」 を 「%」 に戻す
  name => 'nqounet',
  mail => \@mails, # 変数の前に「\」をつける
  web  => \@webs,  # 変数の前に「\」をつける
);
print Dumper \%nqounet; # 「@」 を 「%」 に戻す

変更して実行してみよう!

たくさんの情報を持ちたい

# 結果
{
  mail => [
    "nobu at nishimiyahara.net",
    "coworking at shin-osaka.in"
  ],
  name => "nqounet",
  web => [
    "http://nqou.net",
    "http://www.nishimiyahara.net",
    "http://www.shin-osaka.in"
  ]
}

たくさんの情報を持ちたい

Dumperを使わずに表示してみる

for my $key ( keys %nqounet ) {
  print "$key : $nqounet{$key}\n";
}
# 結果(0x...の部分は違う場合もあります)
web : ARRAY(0x7fe5108275e8)
name : nqounet
mail : ARRAY(0x7fe510827648)

書いて実行してみよう!

リファレンス

様々なリファレンス

my $scalar = 'string';
my @array  = ('a', 'b', 'c');
my %hash   = (key1 => 'value1', key2 => 'value2');
my $scalar_ref = \$scalar; # スカラーのリファレンス
my $array_ref  = \@array;  # 配列のリファレンス
my $hash_ref   = \%hash;   # ハッシュのリファレンス
my $scalar_ref_direct = \'Perl';
my $array_ref_direct  = +['d', 'e', 'f'];
                        # 「+」は省略可能
my $hash_ref_direct   = +{ key => 'value' };
                        # 「+」は省略可能

書いてprintしてみよう!

デリファレンス

リファレンスをちゃんと表示する

# 「$nqounet{mail}」は配列のリファレンス
for my $mail ( @{$nqounet{mail}} ){
        # リファレンスを「@{...}」で囲う
    print "$mail\n";
}

様々なデリファレンス

スカラー

my $scalar     = 'string';
my $scalar_ref = \$scalar; # スカラーのリファレンス
print ${$scalar_ref};

書いて実行してみよう!

様々なデリファレンス

配列

my @array     = ('a', 'b', 'c');
my $array_ref = \@array;        # 配列のリファレンス
print join("\n", @{$array_ref}); # 配列全体をデリファレンス
print $array_ref->[0];  # 配列のリファレンスの最初の要素
print $array_ref->[1];  # 配列のリファレンスの2つめの要素
print $array_ref->[-1]; # 配列のリファレンスの最後の要素

書いて実行してみよう!

様々なデリファレンス

ハッシュ

my %hash = ( key1 => 'value1', key2 => 'value2' );
my $hash_ref = \%hash;
      # ハッシュのリファレンス
for my $key ( keys %{$hash_ref} ) {
      # ハッシュ全体をデリファレンス
  print "$key : $hash_ref->{$key}\n";
      # ハッシュの要素を表示する
}

書いて実行してみよう!

Perlの変数について整理

リファレンスについて整理

リファレンスは「スカラー値」

複雑なデータ構造

変数(ハッシュ)を定義

my @mails = (
    'nobu at nishimiyahara.net',
    'coworking at shin-osaka.in',
);
my @webs = (
    'http://nqou.net',
    'http://www.nishimiyahara.net',
    'http://www.shin-osaka.in',
);
my %nqounet = (
    name => 'nqounet',
    mail => \@mails,
    web  => \@webs,
);

書いて実行してみよう!

複雑なデータ構造

Dumperを使わずにピンポイントで表示

print $nqounet{web}->[2]; # http://www.shin-osaka.in
# %nqounetの「web」というキーの値が配列のリファレンス
# その配列のリファレンスをデリファレンスした3番目の値

print $nqounet{mail}->[0]; # nobu at nishimiyahara.net
# %nqounetの「mail」というキーの値が配列のリファレンス
# その配列のリファレンスをデリファレンスした最初の値

書いて実行してみよう!

もっと複雑なデータ構造

Dumperを使わずにピンポイントで表示

my %papix = (
  name => 'papix',
  mail => [],                   # 空の配列のリファレンス
  web  => ['http://papix.net'], # 配列のリファレンス
);
my $perl_entrance = { # ハッシュのリファレンス
  old_type => \%nqounet,
  new_type => \%papix,
};
print $perl_entrance->{new_type}->{web}->[0];
    # http://papix.net

続けて書いて実行してみよう!

省略の美学

「->(矢印演算子)」は部分的に省略可能

print $nqounet{web}->[2];
print $nqounet{web}[2];
# ブレースとブラケットの間の矢印は省略できる

print $perl_entrance->{new_type}->{web}->[0];
print $perl_entrance->{new_type}{web}[0];
# ブレース同士、ブラケット同士も同じ
print $perl_entrance{new_type}{web}[0]; # エラー
# %perl_entranceというハッシュの「new_type」をキーとする値を参照している

書いて実行してみよう!

変数(スカラー変数)のおさらい

my $str = 'これは文字列です';
my $num = 123;
print "文字列( $str )と数値( $num )\n";

配列の使い方のおさらい

my @array = ('a', 'b', 'c');
print "$array[0]\n";
print "@{array}\n";
for my $item ( @array ) {
    print "$item\n";
}

ハッシュの使い方のおさらい

my %hash  = (
    key1 => 'value1',
    key2 => 'value2',
);
print "key1 : $hash{key1}\n";
for my $key ( keys %hash ) {
    print "$key : $hash{$key}\n";
}

配列のリファレンス

my $array_ref = +['a', 'b', 'c']; # 「+」は省略可能
print "$array_ref->[0]\n";
print "@{$array_ref}\n";
for my $item ( @{$array_ref} ) {
    print "$item\n";
}

ハッシュのリファレンス

my $hash_ref  = +{ # 「+」は省略可能
    key1 => 'value1',
    key2 => 'value2',
};
print "key1 : $hash_ref->{key1}\n";
for my $key ( keys %{$hash_ref} ) {
    print "$key : $hash_ref->{$key}\n";
}

練習問題

練習問題

Dumperすると、以下のようになるような変数を作成してください

{
  luigi => {
    color => "green",
    initial => "L"
  },
  mario => {
    color => "red",
    initial => "M"
  }
}

Use a spacebar or arrow keys to navigate