# WEBスキルチェック(第一回)
WEBシステム開発の世界へようこそ。
社会人1年目の皆様の最初の仕事はシステムを学ぶことです。学んだ内容を活かして2年目以降の業務に活かしてください。
このスキルチェックでは、1年目に学んで身につけて欲しい内容を並べました。現時点ですべてできる必要はありませんが、来年にはできるようになりましょう。チェック結果は採点して公表します。学習計画に活用して下さい。また、同様の内容のスキルチェックを毎月行います。忘れてしまわないよう、反復練習していきましょう。
## スキルチェックの準備
後半の課題に取り組む前に以下リンク先の必須項目が必要になります。
[スキルチェックの準備](https://hackmd.io/@tamura2004/S1yZqr0a_)
## ターミナルへの接続
演習を始めましょう。ブラウザからlinuxサーバに接続して操作を行います。Google Chromeか、Microsoft Edgeを立ち上げて、urlに`http://doc.sofia3dd.net`と入力してください。
別途、初期接続用ユーザーIDとパスワードが連携されているはずですので、確認して下さい。
`login:`と表示されるので、キーボードから初期接続用ユーザーIDを入力して`enter`キーを押してください。続けて、`Password:`と表示されるので続けてパスワードを入力して`enter`を押してください。
以下のような画面が表示されたら成功です。
この`$`で終わる行をプロンプトと呼びます。
```
1bd3c44dac78 login: [ユーザー名]
Password: [パスワード]
..省略..
eban@1bd3c44dac78:~$
```
## ターミナル画面の操作
何か不具合が発生してやり直したくなった場合、ブラウザのリロードボタンを
おすか、`ctrl+r`キーを押して画面の再読み込みを行ってください。
再度ログイン画面になるか、中央に白いボタンで`CONNECT`と表示されるので
それを押してください。ログイン直後からやり直すことができます。
## ターミナル画面の設定
画面上でマウスを右クリックすると、設定メニューを表示させることができます。
現在、`Normal`にチェックマークがついていますが、`Reverse`を選択してみましょう。
画面が黒字に白文字に変更されました。
## その他の注意
文字を入力をする際に日本語入力モードになっていると思わぬ挙動になることがあります。
慌てずに英数モードに切り替えるか、再読み込みをしましょう。
## linuxの基本的なコマンド
英文字でコマンド文字列を入力して、エンターキーを押すことにより、コマンドを実行することができます。
`[enter]`はエンターキーを押すことを表します。以降の説明では省略します。`$`の後ろをキーボードで入力して、`[enter]`を押してください。
```bash
$ whoami[enter]
[ユーザー名]
$ pwd[enter]
/home/guest
```
`whoami`は現在のユーザーを表示します。
`pwd`は現在のディレクトリを表示します。
## ユーザーIDの作成
演習に使用する自分のIDを作成します。IDは事前準備で作成した、githubのIDと同じものにして下さい。
```bash
$ sudo adduser [githubと同じユーザーID]
[sudo] password for [初期ユーザーID]:
```
初期ユーザーIDのパスワードを入力します。
ユーザーが作成された後、新しいユーザー用のパスワードの入力が求められますので、同じものを2回入力します。
```bash
Enter new UNIX password:
Retype new UNIX password:
```
追加情報の入力が5回求められますが、すべて`enter`で構いません。
最後に確認を求められるので、yを押して`enter`キーを押します。
```
Full Name[]:
...
Other []:
Is the information correct? [Y/n]
$ exit
```
`exit`コマンドでログオフします。
画面中央に`Connect`のボタンが表示されるので、クリックして新しく作成したユーザーでログインします。
新しいユーザーでログインしているか、コマンドで確認してみましょう。
```
$ whoami
[新しいユーザー]
$ pwd
/home/[新しいユーザー]
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
```
## ファイルとディレクトリの操作
課題提出用のディレクトリを作成し、基本的な操作を試してみましょう。
`mkdir`はディレクトリを作成します。`ls -la`は現在のディレクトリの内容を一覧表示します。短縮形として`ll`コマンドもあります。`cd`コマンドは、現在のディレクトリを変更(移動)します。
```
$ mkdir submit
$ ls -la
$ ll
```
## tabキー補完
`cd su`まで入力したら、`[tab]`キーを押してみましょう。`cd submit`まで補完されました。このように、`[tab]`キーを押すと、現在のディレクトリの中で、先頭が一致するものを探して補完してくれます。
```
$ cd su[tab]
$ cd submit
$ pwd
$ ll
```
この後、コマンドにより出力される内容は、テキスト上では省略される場合があります。
`touch`コマンドは、そのファイルが無ければ空の状態で作成します。ファイルが存在すれば何もしません。
一つしかディレクトリがない状態で`[tab]`を押すと、その一つが補完されます。
```
$ mkdir 001
$ cd [tab]
$ cd 001
$ ll
$ touch empty.txt
$ ll
```
課題:001/empty.txt(1点)
---
この後、課題:[番号]/[ファイル名](点数)と出てきた場合、提出物として採点対象になります。
各自のsubmitディレクトリ直下の[番号]のディレクトリ内にファイル名で保存して下さい。
ファイルの場所、ファイル名、内容が全て正しい場合採点されます。
---
## ファイルの作成
様々なファイルの作成方法を試してみましょう。
`echo`コマンドは、引数をそのまま出力します。単独ではあまり使い道はありませんが、`>`や`>>`などリダイレクトと組み合わせると、ファイルにその内容を保存することができます。`>`は上書きで保存し、`>>`は追加で保存します。`cat`はテキストファイルの内容を出力します。`cat -n`とオプションを付けると、行番号が付与されます。
```
$ echo hello
hello
$ echo hello > hello.txt
$ cat hello.txt
$ echo hello >> hello.txt
$ cat hello.txt
$ cat -n hello.txt
```
課題:001/hello.txt(1点)
ファイルが作成されたことを確認する`ll`コマンドなどは表示していませんが、この後も含めて自由に利用してかまいません。提出物ファイル以外は、自由に内容を変更したり、ディレクトリやファイルを作成してもかまいません。
## ヒストリ機能
また、同じような入力を繰り返し行う場合`ヒストリ機能`が便利です。上矢印キーを何回か押してみましょう。今まで入力した内容が表示されます。左右キーでカーソルを移動させるか、`ctrl+a`でカーソルを先頭に移動させることができます。修正して`enter`を押すと、再度実行することができます。
実行せずに中断するときは`ctrl+c`を押して下さい。
# ヒアドキュメント
`cat`ファイルと、`ヒアドキュメント`を組み合わせることにより、複数行のファイルを作成することもできます。下の操作の`<<EOF`がヒアドキュメントの開始を表します。その後、EOFと入力されるまでの複数行の内容が出力され、リダイレクトでファイルに保存されています。
`cp`コマンドはファイルのコピーを行います。
```
$ cat <<EOF > three.txt
1
2
3
EOF
$ cat three.txt
$ cp three.txt clone.txt
```
課題:001/three.txt(2点)
課題:001/clone.txt(1点)
## ファイルの参照
`seq`コマンドは連番の数字を出力します。リダイレクトしてファイルに保存すると、テストデータの作成などに利用でき便利です。
```
$ seq 10
$ seq 100 > hundred.txt
```
`wc`コマンドはファイルの行数、単語数、文字数を出力します。`wc -l`とした場合、行数のみ出力します。`|`はパイプといいます、リダイレクトと似ていますが、ファイルの保存するのではなく、次のコマンドに処理を渡します。パイプは2段以上つなげることもできます。
```
$ wc hundred.txt
$ cat hundred.txt | wc
$ cat hundred.txt | wc -l
$ cat three.txt | wc -l
```
`head`コマンドと`tail`コマンドは、ファイルの先頭、末尾の一部を表示できます、`-n 文字数`と数字を出力すると、表示する行数を指定できます。
```
$ head hundred.txt
$ tail hundred.txt
$ head -n 3 hundred.txt
$ tail -n 3 hundred.txt
```
課題:001/hundred.txt(2点)
`head`と`tail`を組み合わせると、ファイルの途中の一部を、行数を指定して取り出すことができます。パイプを多段につないで処理を行うときには、ヒストリと組み合わせて、一部ずつ追加しながら実施すると、見通し良く作業することができ、何か不具合が発生したときも発見しやすくなります。これは、この後のプログラミングなどでも同様です。
```
$ cat -n hundred.txt
$ cat -n hundred.txt | head
$ cat -n hundred.txt | tail
$ cat -n hundred.txt | head -n 50 | tail -n 3
$ cat -n hundred.txt | head -n 50 | tail -n 3 > middle.txt
```
課題:middle.txt(3点)
下のように操作すると`cp`コマンドでエラーになります。`-r`が付いていないので、ディレクトリは処理できない・・・のようなメッセージです。
```
$ pwd
$ cd ..
$ pwd
$ cp /home/problem/002 .
np: -r not specified; omitting directory
```
上矢印でヒストリを呼び出して再実行しましょう。修正箇所が行の最初のほうにある場合、一度`ctrl+a`でカーソルを左端に移動させたのち、修整箇所まで移動すると便利です。
```
$ cp -r /home/problem/002 .
$ cd 002
$ wc log.txt
$ head log.txt
$ tail log.txt
```
`cp`コマンドのコピー先として`.`を指定しています。これはカレントディレクトリ=現在のディレクトリを示します。
## ログの取り扱い
wcの結果を見ると、`log.txt`は約27万行あります。また、head,tailのコマンドで見た内容の形式が違います。実はこのファイルは、あるシステムの状態を記録した`ログ`ですが、途中まで、年、月、日、時、分、秒の記録(タイムスタンプ)が欠落しているのです。
次の課題は、タイムスタンプがある行(後半部分)のみ残したファイルを作成することです。先頭から人間の目と手で調べても良いですが、随分と時間がかかりそうです。10行あたり1秒で調べたとしても、27000秒=7時間以上かかります。時間を無駄にしてはいけません。処理時間を減らす工夫をしましょう。
繰り返し使用する機能を`関数`として登録することができます。`line`コマンドを登録しましょう。今まで説明のあった機能により、指定した番号から10行の内容を、行番号付きで表示します。
```
$ function line() {
cat -n log.txt | head -n $1 | tail
}
$ line 130000
```
変化があった場所は、1行目以上、27万行以下のどこかです。あたりを付けて、半分の13万を試しました。この行はタイムスタンプを含みますから、1行目以上、13万行以下に範囲が絞りこめました。このようにして、区間を半分にしながら絞り込みを行ってみましょう。
```
$ line 70000
$ line 100000
$ line 80000
$ line 90000
$ line 85000
$ line 88000
$ line 89000
$ line 89500
$ line 89800
$ line 89900
$ line 89950
```
合計11回の操作で特定できました。27000回に比べれば随分減りましたね。
これは`二分探索`と呼ばれるアルゴリズムの考え方です。`データベース`の`インデックス`と呼ばれる高速化技法も同じ考えを利用しています。
どのような考え方で高速化しているか、なぜ速くなるのか、実感しておいてください。この後、色々な技法を学ぶ時の考え方の基本になります。
それでは、`log.txt`から、タイムスタンプを持つ行だけを取り出し、`target.txt`として保存してください。この課題は、先ほどの調査の結果および、いままで見たコマンドの組み合わせで対応できます。1行ずらしてしまわないように注意しましょう。課題ファイルの行数を`wc`などで確認して、検証すると良いでしょう。
課題:002/target.txt(10点)
## 条件付き行出力
新しい課題用フォルダ003を作成して、ログファイルのコピーを行っています。最初に作成したsubmitディレクトリの配下に、001,002,003の3つのディレクトリが並んで存在しているでしょうか。
`grep`コマンドは、指定した単語を含む行のみ出力します。空白文字を含む場合、""で単語を囲う必要があります。
```
$ cd
$ cd submit
$ mkdir 003
$ cd 003
$ cp ../002/log.txt .
$ cat log.txt | grep 2019 | head
$ cat log.txt | grep "2019 " | head
```
`-E`オプションにより`正規表現`を利用することができます。`正規表現`の知識は是非別途学んで欲しいところですが、ここでは、行の先頭を表す`^`の利用法を紹介するにとどめます。
```
$ cat log.txt | grep -E "^2019" | head
$ cat log.txt | grep -E "^2019 8" | head
```
ログファイルは空白区切りで、行の先頭から、年、月、日、時、分、秒、url、IPアドレス、応答時間、状態と並んでいます。2019/9/1 8:00 から 2019/10/10 20:59までの行を、range.txtとして保存してください。
課題:003/range.txt(10点)
この課題はターミナル操作で行うには少々厄介です。プログラムやデータベースで処理をしたほうが、わかりやすくできるでしょう。
次の課題では、このログファイルの処理をデータベースを利用して実施してみましょう。
# データベース
作業用ディレクトリを作成し、ファイルをコピーしたのち、`sqlite3`というデータベースを起動します。プロンプトの形が変わったことを確認してください。受け付けられるコマンドの種類も違いますので注意してください。
```
$ pwd
/home/[user]/submit/003
$ cd ..
$ pwd
$ mkdir 004
$ cd 004
$ cp ../002/target.txt .
```
幾つかディレクトリとファイルを作成してきましたので、一旦全体を見渡してみましょう。`-R`オプションで、配下のすべてを表示できます。また`~`はホームディレクトリを示します。
```
$ ll ~ -R
```
では、データベースの対話型環境を立ち上げます。
```
$ sqlite3 my.db
```
先頭が`.`で始まるコマンドは、データベースの設定そのものを操作します。`.show`コマンドは現在の設定を確認します。`.separator`は区切り文字を変更します。
```
> .show
> .separator " "
> .show
```
## テーブルの作成
最初は何もテーブルがありません。`.tables`コマンドを入力して確認しましょう。
```
> .tables
```
`create table`文は、`テーブル`を作成します。テーブルはデータベースにおける情報の入れ物です。先頭が`.`でないコマンドは、`SQL`言語です。コマンドの末尾に`;`が必ず必要です。
```
> create table log (y,m,d,hh,mm,ss,url,ip,res,state);
```
作成できたでしょうか。もう一度`.tables`文を入力してください。
```
> .tables
log
```
また、テーブルの内容を確認したい場合は、`.schema`コマンドを利用します。スキーマと呼びます。大文字で表示されている部分は予約語です。
```
> .schema
CREATE TABLE log (y,m,d,hh,mm,ss,url,ip,res,state);
```
打ち間違いがあったら、テーブルを消して`create table`からやり直しましょう。テーブルを消したい場合`drop table log;`コマンドを利用します。
`select`文で、条件を指定してデータを取得することができます。`from`句でテーブルを指定します。`*`は、行全体を取得することを示します。
```
> select * from log;
```
最初は空のテーブルですから、何も出力はありません。`.import`コマンドで、先に作成したtarget.txtファイルを読み込みましょう。`count`関数は件数を求めることができます。10万件を超えますので、内容を確認する際には`limit`句で取得行数の制限をしましょう。`head`に似ていますね。
この環境でも、矢印によるヒストリ機能が利用できます。
```
> .import target.txt log
> select count(*) from log;
> select * from log limit 5;
```
## レコードの参照
テーブルの行一つ一つを`レコード`と言います。すべてのレコードは同じ`フィールド`(列)を持ちます。`where`句を利用すると、フィールドの条件を指定できます。`grep`を思い出しましょう。
```
> select * from log where url = 'doc.tokyo.com' limit 5;
```
`avg`関数は平均値を、`max`関数は最大値を求めることができます。`group by`句を使用すると、集計する区分を指定できます。指定がない場合、テーブル全体が対象になります。
```
> select avg(res) from log;
> select max(res) from log;
> select url,avg(res) from log group by url;
```
集計操作はデータベースが得意とするところです、ターミナルで実現することは不可能ではありませんが、かなりトリッキーな方法が必要になります。(興味のある人は"シェル芸"で検索してみましょう)
組み合わせると、条件を指定した範囲で、集計範囲を指定して情報を取得することができます。`order by`句は並べ替えを行い、`desc`指定で逆順(大きい順)ソートになります。
```
> select y,m,d,url,avg(res) from log
> where url = 'doc.tokyo.com'
> group by y,m,d,url order by avg(res) desc;
```
このように長いSQLは、途中で改行することができます。`;`が出現するまでの間が一つのSQLのコマンドと見なされます。
## 課題
`.output`コマンドを使用すると、`select`の取得結果をファイルに保存できます。
`.quit`コマンドは、データベースからターミナルに戻ります。
```
> .output output.txt
> select y,m,d,url,avg(res) from log where url = 'doc.tokyo.com' group by y,m,d,url order by avg(res) desc;
> .quit
$ ls -la
```
課題:004/output.txt(30点)
sqlでは`order by`で並び順を変更しました。ターミナルでは`sort`コマンドにパイプ経由で渡すことで実現できます。
```
$ cat output.txt | head
$ cat output.txt | sort | head
```
# プログラム
今までの課題を、プログラムからも行ってみましょう。対話型操作が可能であり、初学者に向いている`ruby`言語を使用します。
## 準備
提出用ディレクトリとファイルの準備をします。
```
$ cd
$ cd submit
$ mkdir 005
$ cd 005
$ cp ../002/log.txt .
```
## 対話型コンソールの起動
`irb`コマンドで、対話型画面を立ち上げましょう。ここで入力したコマンドは、`ruby`言語の命令と解釈されて、結果の値が表示されます。電卓代わりに使用することもできますね。
```
$ pwd
/home/[user]/submit/005
$ irb
irb(main):001:0> _
```
## 数値の扱い
数値関係の操作を一通りやってみましょう。プロンプトや出力結果は省略しており、テキストには表示していません。xという変数に、初期値15を代入して、四則演算を行っています。割り算が切り捨てになっていることに注意。
```
> x = 15
> x + 10
> x * 10
> x - 10
> x / 10
```
四則演算以外の計算も試してみます。`%`は剰余、`gcd`は最小公倍数、`lcm`は最大公約数です。powはべき乗ですが、2番目の引数での剰余を表示します。いずれも、暗号関係の処理をするときに使用します。
```
> x % 10
> x.gcd(12)
> x.lcm(12)
> x.pow(100000,1000000007)
```
今までの操作を通じて、xの値は15のままで変更ありません。以下のような複合代入演算子を使用すると、演算をするとともに左辺の値を変更できます。
```
> x += 1
> x %= 5
```
## 文字列
変数には文字列を値として持たせることもできます。`to_s`メソッドは、変数の値を文字列に変更します。同じ演算でも、結果が異なることを確認してください。
```
> s = x.to_s
> s + s
> s * 10
```
## 配列(ベクトル)
次は配列です。添え字でアクセスする変数の集合として考えるより、ベクトルとして一つのものとして扱えるようになりましょう。色々なシステム技術要素を学ぶ際の、最初に乗り越える意識の転換の一つです。
`first`はターミナルでの`head`、データベースでの`limit`と同じです。`last`は`tail`と同じですね。値を省略した場合、10件ではなく1件になります。
`size`は件数、sum`は合計、`max`は最大値になります。
```
> a = [1,2,3]
> a.size
> a.sum
> a.max
> a.min
> a.first
> a[0]
> a.first(2)
```
配列の後にカギ括弧を付けて数字を1つ書いた場合、その番号の要素の値が取り出されます。要素番号の先頭はゼロです。数字を二つ並べた場合、最初の数字は開始位置、次の数字は取り出す要素の個数になります。開始位置がマイナスの場合、末尾からの順番になります。
```
> a[0,2]
> a.last(2)
> a[-2,2]
> a[1,1]
```
平均値を求めるには以下のように行います。
```
> a.sum / a.size
```
大きいほうから2つ足した値を求めるには、以下のようにすることもできます。全体の合計から最小値を引いています。
```
> a.sum - a.min
```
ターミナルでの`seq`のような連番を作る方法もあります。`to_a`は変換可能なものを配列に変換します。時刻を表す`Time`クラスの値も、配列に変換可能です。
```
> (1..100).to_a
> Time.new.to_a
```
ターミナルの`grep`や、データベースの`select`に相当するメソッドは、`select`です。数式と組み合わせると「1から100までの数字の中で、10で割った余りが2以下」のような条件で選択が行えます。`{ |v| ~}`は`ブロック`と呼ばれます。配列の要素それぞれへの演算を定義します。
```
> b = (1..100).to_a.select { |v| (v % 10) <= 2 }
> b
```
## ファイル出力
配列の内容をファイルに出力してみましょう。`File`クラスの`open`メソッドで書き込み用ファイルを準備します。"w"は書き込み可能であることを示します。
`puts`メソッドは、`put string`の略称です。文字列としてファイルに書き出します。書き込みが終わったら、`close`で利用を終了します。
```
> file = File.open("less.txt","w")
> file.puts b
> file.close
```
さて、ターミナルに戻って書き込み結果を確認したいですが、`exit`で終了すると、今までの変数の内容が失われてしまいます。一時中断機能を使いましょう。`ctrl+z`を押してください。ターミナルに戻ります。
```
(ctrl+z)
[1] stopped irb
$ pwd
$ ll
$ cat less.txt
```
stoppedと表示されて、停止されていることが確認できます。番号を覚えておいてください。確かにファイルが書き込まれていることが確認できました。では`ruby`の対話環境に戻りましょう。
`jobs`コマンドは、バックグラウンドで停止中のプロセスの一覧を表示します。`fg`コマンドは、`foreground`の略で、停止中のプロセスを、活動状態にして前面に持ってきます。その際、先ほど覚えた番号を使用します。
fgコマンドのあと、プロンプトが表示されないなら、`[enter]`を押してみて下さい。
```
$ jobs
[1] stopped irb
$ fg %1
irb
(enter)
>
```
## ファイル入力
それでは、ログファイルを配列に読み込みましょう。`File`クラスの`readlines`メソッドを利用すると、ファイルを読み込んで1行づつ配列にできます。末尾の`;nil`は、この10万件を画面に表示しないためのおまじないです。もし画面に延々と取得結果が表示され続けてしまったら、`ctrl+c`で中断しましょう。
```
> lines = File.readlines("log.txt"); nil
```
ターミナルの時と同じように、先頭、末尾、中間の行を取り出すことができます。先ほど説明したように、カギ括弧を使用することもできます。
```
> lines[0]
> lines.first
> lines[-1]
> lines.last
> lines[89950,20]
```
ターミナルと同じく、`grep`を利用することもできます。`/tokyo/`は正規表現です。
```
> lines.grep(/tokyo/).last(10)
```
さて、前半と後半の区別ですが、そもそも列数が異なるのでした。各行を、文字列ではなく、さらに配列にして持つと列数を確認することができます。文字列を空白区切りで配列に変更するには、`split`コマンドを利用できます。配列にしてしまえば、`size`で列数を確認できます。
```
> lines.first.split
> lines.first.split.size
4
> lines.last.split
> lines.last.split.size
10
```
それでは、変数`target`に、空白で区切った場合列数が10になる行を`lines`から選択して保存しましょう。それを、ファイル`target.txt`として保存してください。
課題:005/target.txt(10点)
## 標準入力から読み込んでの実行
対話型環境を終了してターミナルに戻ります。プログラムをファイルとして作成し、ターミナルから実行してみましょう。
最初に、以下の内容のデータファイルを、ファイル名`input.txt`で作成します。
```
6
1 2 3 4 5 6
```
次に、以下の内容のファイルを、`main.rb`として作成します。`gets`はパイプ等で渡された標準入力から1行分文字列として読み込みます。`to_i`は数値に変換しています。`map(&:to_i)`は、`map { |v| v.to_i }`の省略形です。`join`は配列を、区切り文字を指定して結合し、文字列にします。
```:ruby
n = gets.to_i
a = gets.split.map(&:to_i)
puts n * 10
puts a.join(",")
```
実行してみましょう。
```
$ cat input.txt | ruby main.rb
60
1,2,3,4,5,6
```
配列に読み込みたい要素が、縦に並んでいるときはどうでしょうか。
以下の内容に`input.txt`を変更しましょう。
```
3
1
3
2
```
プログラム`main.rb`を以下のように変更します。
```:ruby
n = gets.to_i
a = Array.new(n) {
gets.to_i
}
puts n * 10
puts a.join("@")
```
実行して確認しましょう。
## 時間の取り扱い
対話型環境で確認してみましょう。`Time`クラスを利用すると、変数に時間の値を設定できます。過去が小さい、未来が大きいとして、不等号を利用することもできます。コマンドの後に置いたif文は、条件が成立した場合だけ実施することを示します。
```
$ irb
> from = Time.new(2019,9,1,8,0,0)
> to = Time.new(2019,10,10,21,0,0)
> puts "yes" if from < to
> puts "no" if from > to
```
## 課題
target.txtから、2020-01-02 09:00:00から2020-02-10 20:59:59までの行を抜き出し、time.txtとして保存してください。
課題:time.txt(7点)
ヒント:以下の??の部分を考えてみましょう。
```:ruby
from = ??
to = ??
while line = gets
y,m,d,hh,mm,ss,url,ip,res,state = line.chomp.split
time = Time.new(y,m,d,hh,mm,ss)
puts line if from <= time && time < to
end
```
## その他の言語仕様の確認
以下の二つのチュートリアルに取り組みましょう。
- [try ruby](https://try.ruby-lang.org/)
- [20分で始めるruby](https://www.ruby-lang.org/ja/documentation/quickstart/)
## プログラム課題への取り組み
このスキルチェックで説明したことと、チュートリアルの内容を思い出しながら、リンク先のバーチャルコンテストの問題を提出して下さい。
- [バーチャルコンテスト](https://kenkoooo.com/atcoder/#/contest/show/0aa05f4e-d591-4238-9eae-dcea3fbe4973)
課題:A問題(各1点x3=3点)
課題:B問題(各5点x2=10点)
課題:C問題(10点)
コンテストの問題には、解説へのリンクがあります。解き方がわからない場合、解説は見てもかまいません。解説を読んで理解することも、身につける技術の一つです。
ですが、誰かの書いたソースコードをそのまま書き写すことは不正とみなします。学習上悪影響しかありません、やらないで下さい。
## 課題が終了したら
完了したことを、質疑応答用slackへ報告して下さい。
ここで学んだような知識は、継続して利用し続けないと、あっという間に忘れてしまいます。毎日取り組めるものを何か見つけて、習慣化するようにしてください。
このスキルチェックは、月1回のペースで実施します。