インターネット技術特論
E:Ruby 山口 実靖 http://www.ns.kogakuin.ac.jp/~ct13140/inet/ インターネット技術特論E-2オブジェクト指向
• 謎の言葉の解説.以下の解説は不正確です. – メソッド:C言語の関数に近いもの – クラス:C言語の型に近いもの.ただし,int型の様 な小さなものでは無く,構造体. – インスタンス:C言語の変数に近いもの.型(構造体) が1個あったら,実体の変数は多数作れる. – オブジェクト:インスタンスのこと.あるいは,インスタ ンスとクラスの両方の意味.Ruby
インターネット技術特論E-4Ruby
• オブジェクト指向,スクリプト型(インタプリタ型)プ ログラミング言語. – まつもとゆきひろ氏によって作られた. – Ruby on Rails の成功などにより世界中で広く使わ れている. – 文字列処理が得意 – 発表当時(1990年代中頃), 文字列処理が得意であ るとして広く(?)普及していたPerlの代替としても注目 • http://www.ruby-lang.org/ja/ インターネット技術特論E-5Ruby の install
• Un*x系OSへのinstall – (1) アーカイブの入手 (下は,2010年10月現在最新版) • wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-p0.tar.bz2 – (2) 解凍,compile,&install• bunzip2 dc ruby1.9.2p0.tar.bz2 | tar xf -• cd ruby-1.9.2-p0/ • ./configure あるいは ./configure --prefix=/a/b/ruby • make • make install インターネット技術特論E-6
Ruby の install
• RedHat, Fedora, CentOSなら – yum install ruby
• 工学院大学のサーバにはインストール済み – www.ns.kogakuin.ac.jp (hout1) – green.ns.kogakuin.ac.jp インターネット技術特論E-7
補足(proxy設定)
• 工学院大学内でyumやwgetを使用するには, proxyの設定が必要. • 使用しているシェルの確認方法 – echo $SHELL • bashを使用している場合 export http_proxy=http://cache.cc.kogakuin.ac.jp:8080/ export https_proxy=http://cache.cc.kogakuin.ac.jp:8080/ export ftp_proxy=http://cache.cc.kogakuin.ac.jp:8080/ • csh, tcshを使用している場合setenv http_proxy http://cache.cc.kogakuin.ac.jp:8080/ setenv https_proxy http://cache.cc.kogakuin.ac.jp:8080/ setenv ftp_proxy http://cache.cc.kogakuin.ac.jp:8080/
インターネット技術特論E-8
最初のRubyプログラム
puts "Hello,World!" • 実行方法 – ruby hello.rb • 実行結果 – Hello,World!インターネット技術特論E-9
コメント
#記号から行末まではコメントとして無視される. # コメントです # この行もコメントです print "Hello¥n" #こんにちは # print "World!¥n" print "World!¥n" インターネット技術特論E-10埋め込みドキュメント
行頭に"=begin"がある行から,行頭に"=end" がある行までは,ドキュメント(コメント). print "hello¥n" =begin これ以下はコメントです. この行はコメントです. 複数行をまとめてコメントにできるので, 便利ですね:-) =end この行も含めて,ここまでコメントです. print "World!¥n" インターネット技術特論E-11コメント
• C言語の /* */ の様に,行の途中をコメントにす る機能はない インターネット技術特論E-12リテラル
• リテラル:ソースコード中に直接記述される定数 3 # 整数リテラル(3) 3.0 # 浮動小数点リテラル(3.0) "Hello" # 文字列リテラル(Hello) 'Hello' # 同上 ?a # 文字リテラル(a) /Hel+o/ # 正規表現リテラル(Hel+o) "と'は,完全に同一では無く,違いがある. 'の方が単純で,"の方が高機能. インターネット技術特論E-13リテラル (C言語のとの比較)
正規表現はC言語にない. 文字列は"でも'でもよい. 文字はC言語と似てもにつかない • C言語 3 3.0 "Hello" "Hello" 'a' 対応なし • Ruby 3 3.0 "Hello" 'Hello' ?a /Hello/ • C言語との比較 インターネット技術特論E-14文字列リテラル
• シングルクォート'で囲まれた文字列 • '記号は¥'と記述する. • ¥記号(バックスラッシュ記号)は¥¥と記述. puts 'What¥'s happened?'puts '¥¥1,000,000' – 特殊記号は上記2個のみ.他はそのまま • ダブルクォート"で囲まれた文字列 • ¥a=ベル ¥b=BS ¥n=改行 ¥s=空白 ¥t=TAB ¥"=" ¥¥=¥ など多機能. インターネット技術特論E-15
余談 : ¥
(円記号)
と \
(バックスラッシュ)
• 文字コード5C(92)に対して, – アメリカ人は(ASCIIでは)\(バックスラッシュ)記号を割り当てた. – 日本人(JIS)は¥を割り当てた. • 日本人が¥のつもりで作ったテキストファイルを英語OSで見ると,バ ックスラッシュに見える. – これは,文字化け? • MS-DOS以来,MS社OSではディレクトリの区切り文字に\を使用し てきた.日本語版では¥が区切り文字. • C言語でも,制御文字は文字コード5Cを使用. 結果,米国→制御文字は\ 日本→制御文字は¥ – ¥と\は同一として受け入れられた? インターネット技術特論E-16ヒアドキュメント
• 文字列の終端を指定し,長い文字列をソースコ ード内に記述する手法.インターネット技術特論E-17
ヒアドキュメント
a=<<HEREEND hello, world! HEREEND print a hello, world! 実行結果 朱記部の意味 <<記号から,HEREENDまでを 文字列リテラルと見なす. つまり,aに "hello,¥nworld!¥n" が代入される. HEREENDは自由に指定できる. インターネット技術特論E-18ヒアドキュメント
print <<XYZ This is a pen. XYZ This is a pen. 実行結果 x=<<Hoge ABC XYZ Hoge print x x=<<Hoge ABC XYZ Hoge#hello print x これら↓はNG. "Hogeが見つからない" インターネット技術特論E-19識別子
• 識別子:変数名,関数名(メソッド名),クラス名 • アルファベット,数字,_(アンダースコア)を使 用できる. – ただし,数字を先頭にすることはできない. • 変数名,メソッド名は先頭を小文字にする. • 定数名,クラス名は先頭を大文字にする インターネット技術特論E-20識別子
• 変数名x xYZ abc ab_cd _x a98 • 定数名 Max MIN • NG ab-c 98a インターネット技術特論E-21
予約語
• 次スライドの語は登録済みの予約語である – 予約語はクラス名,変数名などに用いることができ ない. – 接頭辞の$,@,@@を付ければ予約語とはみなされ ず使用できる.(接尾辞については後述) • また,前述の"行頭の=begin"と"行頭の =end"も,コメントとして特殊な扱いを受ける インターネット技術特論E-22予約語
• __LINE__ case ensure not then __ENCODING__ class false or true __FILE__ def for redo undef BEGIN define? if rescue unless END do in retry until alias else module return when and elsif next self while begin end nil super yield break インターネット技術特論E-23
変数の型
• Rubyは型付けが弱い // 変数宣言不要 x = 3; // xにInteger型の // 3が入った x = "Hello"; // xにString型の // "Hello"が入った. (中略) print x, "¥n" // ↑ここだけ読んでも, // xに何型の変数が // 入っているか不明 • C言語は型付けが強い int x, y; // 型明記の変数宣言が必須 // xには整数しか入れられない x = 3; //OK x = &y; //NG(警告) x = "hello"; //警告 (中略) printf("%d¥n", x); //↑途中がどうであろうと, // xには整数が入っているはず インターネット技術特論E-24変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入はポインタのコピー a = "Hello" b = a print "a=", a, " b=", b, "¥n" a.gsub!(/H/,"h") print "a=", a, " b=", b, "¥n" a = "World" print "a=", a, " b=", b, "¥n" a=Hello b=Hello a=hello b=hello a=World b=hello 実行結果インターネット技術特論E-25
変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" "Hello" 変数a インターネット技術特論E-26変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = a "Hello" 変数a 変数b インターネット技術特論E-27変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = a a.gsub!(/H/,"h") "hello" 変数a 変数b インターネット技術特論E-28変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = a a.gsub!(/H/,"h") a = "World" "hello" 変数a 変数b "World" インターネット技術特論E-29変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = "Hello" a.upcase!print "a=", a, " b=", b, "¥n" a=HELLO b=Hello 実行結果
インターネット技術特論E-30
変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー
a = "Hello" 変数a "Hello"
インターネット技術特論E-31
変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = "Hello" 変数a "Hello" 変数b "Hello" インターネット技術特論E-32変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = "Hello" a.upcase! 変数a "HELLO" 変数b "Hello"インターネット技術特論E-33
変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = a.clone a.upcase!print "a=", a, " b=", b, "¥n" a=HELLO b=Hello 実行結果
インターネット技術特論E-34
変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー
a = "Hello" 変数a "Hello"
インターネット技術特論E-35
変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" a.clone 変数a "Hello" "Hello" clone インターネット技術特論E-36変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = a.clone 変数a "Hello" "Hello" 変数b インターネット技術特論E-37変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – 代入は参照のコピー a = "Hello" b = a.clone a.upcase! 変数a "HELLO" "Hello" 変数b インターネット技術特論E-38変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – cloneは浅い(Shallow)コピー メンバ変数a メンバ変数b メンバ変数c "Hello" "World" "12345" 変数x インターネット技術特論E-39変数(参照,ポインタ) と 代入
• Rubyでは,すべての変数は参照,ポインタ – cloneは浅い(Shallow)コピー メンバ変数a メンバ変数b メンバ変数c "Hello" "World" "12345" 変数x メンバ変数a メンバ変数b メンバ変数c clone インターネット技術特論E-40変数(参照,ポインタ) と 代入
• 深い(deep)コピーとは メンバ変数a メンバ変数b メンバ変数c "Hello" "World" "12345" 変数xインターネット技術特論E-41
変数(参照,ポインタ) と 代入
• 深い(deep)コピーとは メンバ変数a メンバ変数b メンバ変数c "Hello" "World" "12345" 変数x メンバ変数a メンバ変数b メンバ変数c clone "Hello" "World" "12345" インターネット技術特論E-42変数,定数
• Rubyには5種類の変数(定数)がある. – ローカル変数:小文字で始まる – グローバル変数:$記号で始まる – インスタンス変数:@で始まる. – クラス変数:@@で始まる – 定数:大文字で始まる 例 age:ローカル変数 $age:グローバル変数 @age:インスタンス変数 @@age:クラス変数 Age:定数 インターネット技術特論E-43擬似変数
• 以下の7個はローカル変数のふりをした擬似変 数.値の変更ができない. – nil:空,未初期化.CのNULL,Javaの"ぬるぽ" – true,false:真偽の"真"と"偽" – self:現在実行中のメソッドが所属するオブジェク ト.C++,Javaのthis– __FILE__ __LINE__ __ENCODING__:ソース ファイルのファイル名,行数,エンコーディング インターネット技術特論E-44
サンプル00
gets print 実行方法ruby a.rb a.txt 実行結果 hello hello world! this is a pen. a.txt これは,あまりにも酷い? 余談:oneliner インターネット技術特論E-45
gets
• コマンドライン引数で指定されたファイルを順に 開き,1行ずつ読み込む.引数が無ければ標準 入力から読み込む. • 読み込む行が無くなるとnilを返す. • 読み込んだ値は,戻り値として返し,$_に代入 する. インターネット技術特論E-46サンプル01
gets print $_ 実行方法ruby a.rb a.txt 実行結果 hello hello world! this is a pen. a.txt 先ほどと同一のプログラム インターネット技術特論E-48
サンプル02
line = gets print line line = gets print line 実行方法ruby a.rb a.txt 実行結果 hello world! hello world! this is a pen. a.txt
インターネット技術特論E-49
文,式
• Rubyでは,文(式)はセミコロンまたは改行で区 切る. – C言語では,セミコロンで区切る. – 通常は,改行で区切る.1行1文. print "Hello¥n" print "World!¥n" – 1行に2文以上書きたければセミコロンを打つ.print "Hello¥n" ; print "World¥n"
インターネット技術特論E-50
メソッド呼び出し
• 驚くべきことに ( ) を省略できる. line = gets line = gets() print line print(line) インターネット技術特論E-51組み込み変数
• $!:最後の例外に関する情報 • $1,$2,$3..:最後のパターンマッチのn番目 の括弧にマッチした値. • $_:現在のスコープで最後にgetsなどで読み 込んだ文字列. • $.:最後に読んだ入力ファイルの行番号 • 他にも – $~ $& $` $' $+ $/ $¥ $, $; $< $> インターネット技術特論E-52組み込み定数
• $0:現在実行中のrubyスクリプト名 • $$:現在実行中のrubyプロセスのプロセスID • $stdin $stdout $stderr STDINSTDOUT STDERR:標準入力,標準出力,標準 エラー
• ARGV:コマンドライン引数の配列 – ARGV[0],ARGV[1]の形で使用. • ENV:環境変数を表すHash
• $-a TRUE FALSE ARGF RUBY_VERSION RUBY_RELEASE_DATE インターネット技術特論E-53
演算子
• :: • [] • ** • 単項- 単項+ ! ~ • * / % • + -• << >> • & • | ^ • > >= < <= • <=> == === != =~ !~ • && インターネット技術特論E-54配列
a = ["apple", "banana", "orange"] print a[1], "¥n"
# banana
a[1] = "melon"
# a が ["apple", "melon", "orange"] に
print a, "¥n" # applemelonorange print a.join(",") # apple,melon,orange インターネット技術特論E-55
配列
a = ["apple", 3, 12.3] # ↑型が一致していなくてもよい.すべてはオブジェクト. b = ["apple", ["banana","orange"], "melon"] # 配列もオブジェクト. b[1]は["banana","orange"]で, # b[1][1]は"orange" c = [1, [[2, 3], 4], 5] # c[1]は[[2, 3], 4] # c[1][0]は[2,3] # c[1][0][0]は2 # c[1][0][1]=30 などが可能 インターネット技術特論E-56配列 (Array型)
• 配列は,正確にはArray型のインスタンス • rubyではすべてがオブジェクト– a[i] a[i..j] a[i,n] – a.each do |x| ... end – a.length a.join(x)
– a.push(x) a.pop a.shift a.unshift(x) a.delete(x) – a.sort a.sort!
– a.reverse a.reverse!
インターネット技術特論E-57
ハッシュ (Hash)
h = Hash.new h[key] h[key] = value h.delete(key) h.each | k,v | ... end h.key?(k) , h.value?(v) h.keys, h.values http://www.ruby-lang.org/ja/man/html/Hash.html インターネット技術特論E-58Rubyでの真偽
• 偽 – false, nil • 真 – 上記以外 • 注意 – 他言語で偽となる 0 や "" は Ruby では真 インターネット技術特論E-59真偽値の例
a = true b = false print a, "¥n" print b, "¥n" true false 実行結果 インターネット技術特論E-60真偽値の例
a = (1<3) b = (3<1) c = nil print a, "¥n" print b, "¥n" print c, "¥n" true false nil 実行結果 インターネット技術特論E-61制御構造 if
if a0 then b0 elsif a1 then b1 else b2 end インターネット技術特論E-62ifの例0
if 1<3 then print "T¥n" else print "F¥n" end T 実行結果 インターネット技術特論E-63ifの例1
if 3<1 then print "T¥n" else print "F¥n" end F 実行結果 インターネット技術特論E-64ifの例2
x = true if x then print "T¥n" else print "F¥n" end T 実行結果インターネット技術特論E-65
ifの例3
x = false if x then print "T¥n" else print "F¥n" end F 実行結果 インターネット技術特論E-66ifの例4
x = (1<3) if x then print "T¥n" else print "F¥n" end T 実行結果 インターネット技術特論E-67ifの例5
x = (3<1) if x then print "T¥n" else print "F¥n" end F 実行結果 インターネット技術特論E-68ifの例6
x = nil if x then print "T¥n" else print "F¥n" end F 実行結果 インターネット技術特論E-69ifの例7
x = 0 if x then print "T¥n" else print "F¥n" end T 実行結果 インターネット技術特論E-70制御構造 unless
unless a then b0 else b1 end インターネット技術特論E-71修飾子 if, unless
print "hello" if a == 3 print "hello" unless a == 3以下と同じ if a==3 then
print "hello" end
unless a==3 then print "hello" end インターネット技術特論E-72
if 文の値
• ifが値を返せる – ブロックで最後に評価した値がif文の値となる a = 1 b = 3max = if b<a then a else b end print max, "¥n"
インターネット技術特論E-73
if 文の値
a = 1b = 3
max = if b<a then
print "a is larger¥n" a else print "b is larger¥n" b end print max, "¥n" b is larger 3 実行結果 インターネット技術特論E-74
if 文の値
male = true name = "Sane"print "Hi,", if male then "Mr." else "Ms." end, name, "¥n"
インターネット技術特論E-75
case
case x when v0 when v1, v2 when v3..v4 else end インターネット技術特論E-76case文の例
x = 5 case x when 0 print "zero¥n" when 1, 2print "one, two¥n" when 3..6
print "three to six¥n" when "hello" print "hello¥n" else print "other¥n" end インターネット技術特論E-77
繰り返し while
while 式0 do 文0 文1 end x = 0 while x<10 do print x, "¥n" x += 1 end while line=gets do print line end インターネット技術特論E-78繰り返し until
while 式0 do 文0 文1 end 例 x = 5 until x<0 do print x, "¥n" x -= 1 end インターネット技術特論E-79繰り返し for
for 変数 in 配列 do print i, "¥n" end for i in 20..30 do print i, "¥n" end ruby では,これは一般的では無い for i in [10,11,12] do print i, "¥n" end インターネット技術特論E-80繰り返し for
5.times do | i | print i, "¥n" end 0 1 2 3 4 実行結果インターネット技術特論E-81
イテレータ (反復子)
x = ["apple","banana","orange"] x.each do |fr| print fr,"¥n" end 赤字はメソッドeachの引数 インターネット技術特論E-82イテレータ (反復子?)
open("/tmp/a.txt","r") do | f | line = f.gets print line end f=open("/tmp/a.txt","r") line = f.gets print line f.close インターネット技術特論E-83ループ脱出
• break – ループ(while,until,for,イテレータ)から抜 ける – C言語のbreak • next – ループの残りを省略し,次のループに入る – C言語のcontinue • redo – ループの最初に戻る. インターネット技術特論E-84メソッド(関数)の定義
def メソッド名 (引数群) 本体 end インターネット技術特論E-85メソッド定義の例0
def pr_helo() print "Hello,World!¥n" end pr_helo pr_helo() インターネット技術特論E-86メソッド定義の例1
def pr_helo0 print "Hello,World!¥n" end def pr_helo1() print "Hello,World!¥n" end インターネット技術特論E-87メソッド定義の例2
def add(x, y) print x,"+",y,"=",(x+y),"¥n" return(x+y) end a = add(3,4) print a, "¥n" インターネット技術特論E-88クラスの定義
class クラス名 メソッド定義 メソッド定義 : endインターネット技術特論E-89
クラスの定義
• C++と異なり, – インスタンス変数に直接アクセスできない. メソッドの呼び出しのみ許される. – インスタンス変数,クラス変数の宣言がない • そもそも,全ての変数の宣言がない 初めて使用したときに変数は作られる. インターネット技術特論E-90クラスの定義
class Hoge def initialize end end x = Hoge.new インターネット技術特論E-91クラスの定義
class Hoge def initializeprint "Hoge is created¥n" end end x = Hoge.new y = Hoge.new z = Hoge.new インターネット技術特論E-92
クラスの定義 と 使用
class Hoge def initialize @x = 0 end def get return @x end def set(n) @x = n end def prin print @x, "¥n" end end x = Hoge.new x.prin # 0 x.set(3) x.prin # 3 print x.get, "¥n" # 3 インターネット技術特論E-93クラスの定義 と 使用
class Hoge def initialize @x = 0 end def get return @x end def set(n) @x = n end def prin print @x, "¥n" end end x = Hoge.new y = Hoge.new x.prin # 0 y.prin # 0 x.set(3) y.set(7) x.prin # 3 y.prin # 7 インターネット技術特論E-94クラスの定義
class Hoge def initialize @x = 0 @y = 0 end def get_x return @x end def get_y return @y end def inc @x += 1 @y += 10 end end インスタンス変数に自由に代入できないクラス インターネット技術特論E-95アクセス制限
private 同一インスタンスに対してのみ呼び出せる. レシーバはselfのみ. サブクラスのインスタンスであっても良い. protected 同一型のインスタンスに対してのみ呼び出せる. レシーバはselfでなくてもよい. public 誰でも呼び出せる. C++のprivate(サブクラスでの呼び出しNG)はない. インターネット技術特論E-96アクセス制限の仕方
class Hoge # デフォルトはpublic になっている def aaa end private # デフォルトがprivateになった def bbb end protected :aaa, :bbb #明示的変更 endインターネット技術特論E-97 class Hoge def me_abc print "abc¥n" end private def me_def print "def¥n" end public def me_ghi print "ghi¥n" end end ho = Hoge.new ho.me_abc #ho.me_def ← これはNG ho.me_ghi インターネット技術特論E-98 class Hoge def me_abc me_def # ← これはOK end private def me_def print "def¥n" end end ho = Hoge.new ho.me_abc # これはOK インターネット技術特論E-99
I/O
fi = File.open("a.txt", "r") while line=fi.gets do line.chomp! print "[", line, "]¥n" end fi.close インターネット技術特論E-100I/O
File.open("a.txt", "r") do | fi | while line=fi.gets do line.chomp! print "[", line, "]¥n" end end # ファイルは自動的に閉じる インターネット技術特論E-101I/O
File.open("a.txt", "w") do | fi | fi.print "hello¥n" fi.print "world¥n" end http://www.ruby-lang.org/ja/man/html/IO.html インターネット技術特論E-102例外
• エラー処理だらけのプログラムは読みづらい fp = fopen(...); if( fp==NULL ){ ... } ret = fseek(...); if( ret == -1 ){ ... } ret = hoge(...);if( ret == NULL ){ ... } インターネット技術特論E-103
例外
begin hoge fuga piyo rescue A => exp0 rescue B => exp1 else ensure end インターネット技術特論E-104例外
begin File.open("a.txt", "r") do | fi | while line=fi.gets do line.chomp! print "[", line, "]¥n" end endrescue Errno::ENOENT => exp print "Find not found!!¥n" print exp.message, "¥n" rescue => exp print "ouch!¥n" print exp.class, "¥n" print exp.message, "¥n" end
インターネット技術特論E-105
rescue
• rescue A => exp
– 例外 A が発生したらここに来る.
発生した例外オブジェクトに exp と名付ける.
• "=> exp" は省略可能."rescue A" と記す. 発生した例外オブジェクトは破棄してしまう. • "A"は省略可能."rescue => exp" 全ての例外を捕まえてしまう. • else – どのrescueも成り立たなかったらここを実行. • ensure – 例外を捕まえても,捕まえなくてもここを実行.