数を並び替えた最大値(Go言語)

正の整数のリストを与えられたとき、数を並び替えて可能な最大数を返す関数を記述せよ。例えば、[50, 2, 1, 9]が与えられた時、95021が答えとなる。

1時間以内に解けなければプログラマ失格となってしまう5つの問題が話題に | ソフトアンテナブログ

 
ここRuby で解いたものを、Go でもやってみました。
problem1.go

package main
import "fmt"
import "strconv"

func remove(ar []int, i int) []int {
    tmp := make([]int, len(ar))
    copy(tmp, ar)
    return append(tmp[0:i], tmp[i + 1:]...)
}

func permutation(ar []int) [][]int {
    var result [][]int
    if len(ar) == 1 {return append(result, ar)}
    for i, a := range ar {
        for _, b := range permutation(remove(ar, i)) {
            result = append(result, append([]int{a}, b...))
        }
    }
    return result
}

func join(ar []int) (st string) {
    for _, n := range ar {
        st += strconv.Itoa(n)
    }
    return
}

func solve(ar []int) int {
    max := 0
    for _, a := range permutation(ar) {
        n, _ := strconv.Atoi(join(a))
        if n > max {max = n}
    }
    return max
}

func main() {
    fmt.Println(solve([]int{50, 2, 1, 9}))    //=>95021
}

Ruby の Module 覚え書き

module Example
  def a
    output "inner"
  end

  def output(st)
    puts st
  end
end

include Example
output "outer"    #=>"outer"
a                 #=>"inner"

include すればモジュール内のメソッドがふつうに使える。

module Example
  def a
    output "inner"
  end

  def output(st)
    puts st
  end
  module_function :a, :output
end

Example.a         #=>"inner"
output "outer"    #=>NoMethodError

include しないなら、module_function の指定をするなどしないと呼べない。その際、メソッド内部で呼ばれているメソッドも、module_function の指定をしないと呼べない。なお、module_function の指定をしても、include すれば上と同じように呼べる。
 
自分でこんな解決策も考えた。
obelisk.hatenablog.com
 
定数と Proc を使うという手もある。

module Example
  def a
    Output.("inner")
  end
  module_function :a
  
  Output = ->(st) {puts st}
end

Example.a                    #=>"inner"
Example::Output.("outer")    #=>"outer"
Output.("outer")             #=>NameError

Output.() は外から呼び出そうと思えば呼び出せるが、名前空間を作る目的なら充分に感じる。

Linux Mint 19 へのアップグレード

20181007133946
 
まず、ディスプレイマネージャが LightDM になっているかの確認が必要なようです。わたしの場合は

$ cat /etc/X11/default-display-manager

/usr/sbin/mdm だったので、変更が必要でした。

$ apt install lightdm lightdm-settings slick-greeter
$ apt remove --purge mdm mint-mdm-themes*
$ sudo dpkg-reconfigure lightdm

で、PC を再起動します。すると、ディスプレイマネージャが LightDM に切り替わっています。

そして

$ apt install mintupgrade
$ mintupgrade check

でエラーが出なければ、Mint 19 へアップグレード可能ということらしいです。

あとは

$ mintupgrade upgrade

でアップグレードが始まります。

ありゃ、エラー出まくり。

dpkg: error processing package gconf2 (--configure):
 dependency problems - leaving triggers unprocessed
dpkg: dependency problems prevent processing triggers for gconf2:
 gconf2 depends on dbus-x11; however:
  Package dbus-x11 is not configured yet.

Processing was halted because there were too many errors.
E: Sub-process /usr/bin/dpkg returned an error code (1)

とか。さて、ここに従って

$ sudo dpkg --configure -a
$ sudo apt-get install -f

してみる。しかし下のコマンドで何も起きない。なのでエイヤッと

$ apt upgrade
$ apt dist-upgrade

する。どうやらうまくいったみたいだ。

再起動で Linux Mint 19 を立ち上げる。スタート時のログインを省略。キーリングのパスワードを無効にする。
ログアウトからの自動ログインは簡単にできる方法がまだ見つかっていない。

third-party PPA が消えてしまったので、インストール前に選択して保存していた Upgrade-Backup ディレクトリから PPA を復元する(いや、迂闊だった。あぶないところだったな)。インストール時にエラーが出なければ、自動で更新されていたのかも知れない。

Mint 18 のときの不具合である、新しいカーネルでの画面のちらつきと日本語入力(Mozc)の起動の問題は、Mint 19 では出なくなった。画面のちらつきがなくなったのは、ディスプレイマネージャの変更によるのかも知れない。(結局サスペンド復帰のトラブルがあって、最新のカーネルは使えないことがわかった。)


※参考
kledgeb.blogspot.com
nyakki-yossi.hatenablog.com

このブログのデザイン

ベースはオフィシャルテーマの Life

CSS

body {
    background-color: lightyellow;
    font-family: "メイリオ", serif;
}
.entry-content p {
    margin:  9px 0;
}
.page-index #blog-title {
    margin: 0px;
    padding-bottom: 0;
}
div#blog-title-inner {
   text-align: left;
    border-bottom: 1px dashed #BDC4CB;
    line-height: 1em;
}
h1#title a {
    color: peru;
    font-style: italic;
    font-size: 26pt;
    text-shadow: darkgray 3px 3px 4px;
    margin-left: 30px;
}
div#container {
    background-color: lightyellow;
    width: 100%;
}
div#content {
    background-color: lightyellow;
}
div#content-inner {}
article.entry {
    border: 1px solid lightgreen;
    padding: 10px;
    background-color: #FFFBE0;
}
div.date {
    text-align: left;
}
div.date a {
    color: black;
    font-size: 13pt;
    font-weight: bold;
    color: black;
    margin-left: 28px;
}
h1.entry-title {
    background-color: lightyellow;
    text-shadow: silver 2px 2px 3px;
    border: 1px solid peru;
    border-left: 9px solid peru;
    text-align: left;
    margin-left: 20px;
    margin-right: 20px;
    padding-left: 20px;
    font-size: 1.6em;
    line-height: 1.6em;
}
header.entry-header {
   margin-bottom: 15px;
}
div.entry-content {
    background-color: white;
    border: 1px solid lightgreen;
    margin: 0 20px;
    max-width: none;
    padding: 10px;
    line-height: 1.4em;
    font-size: 0.95em;
}
div.categories {
    text-align: left;
    margin-bottom: 1px;
    padding: 2px;
    padding-left: 28px;
}
article.entry {
    margin-bottom: 40px;
}

.entry-content a.keyword {
    border-bottom: 1px dotted transparent;
}
a.keyword:hover {
    border-bottom-color: lightgreen;
} 
@media (min-width:1020px) {.entry-content pre {
    margin: 0 0;
    font-family: "Ubuntu Mono", "Courier New", Consolas, monospace, sans-serif;
    font-size: 1em;
}}
.entry-content code {
    font-family: "Ubuntu Mono", "Courier New", Consolas, monospace, sans-serif;
}
h3 {
    border: solid lightgreen;
    border-width: 0px 0px 1px 7px;
    padding-left: 10px;
}
blockquote {
    background-color: #F7F8F9;
    margin: 0;
}
@media (min-width: 1020px) {
.entry-content blockquote {
    margin: 0;
}}
@media (min-width:1020px) {
.page-entry .entry-title {
    font-size: 1.6em;
    line-height: 1.6em;
}}
@media (min-width: 1020px) {
.entry-content h3 {
    font-size: 115%;
}}


footer.entry-footer {
    max-width: none;
    margin: 0 20px;
}
.hatena-urllist li {
    padding: 0.2em 0;
}
div.hatena-module a {
    color: #5f9a41;
}

img.large {
    width: 100%;
}
img.half {
    width: 50%;
}
img.golden {
    width: 62%;
}
img.height-golden {
    width: 46%;
}

 
フッタ HTML。

<script type="text/javascript">
    var ndlist = document.querySelectorAll("div.entry-content a"); 
    for (var i = 0; i < ndlist.length; i++) {
      if (ndlist[i].innerText != "続きを読む") {
          ndlist[i].setAttribute("target", "_blank");
          ndlist[i].setAttribute("style", "color: #5f9a41;");
      }
    }
</script>

<script type="text/javascript">
    var nodes = document.querySelectorAll('a.entry-title-link');
    for (var j = 0; j < nodes.length; j++) {
        var url = nodes[j].getAttribute('href');
        var a = document.createElement("a");
        a.setAttribute("href", 'http://b.hatena.ne.jp/entry/' + url);
        a.setAttribute("target", "_blank");
        a.innerHTML = '<img src="http://b.hatena.ne.jp/entry/image/' + url + '">';
        nodes[j].appendChild(a);
    }
</script>

うんこな電子メール(1)

こんにちは!

おそらくあなたが推測したように、あなたのアカウント*********@yahoo.co.jpは、私があなたからそれをあなたに伝えたように、ハッキングされました。

私は国際的なハッカーグループの一員です。
2018年7月23日から2018年9月17日まで、あなたが訪問した成人のウェブサイトを通じて、作成したウイルスに感染しました。
これまでのところ、あなたのメッセージ、ソーシャルメディアアカウント、メッセンジャーにアクセスできます。
さらに、これらのデータを完全に減衰させました。

私たちはあなたの小さな秘密を知っています...ええ、あなたはそれらを持っています。 私たちはあなたの行為を見て、ポルノのウェブサイトに記録しました。 あなたの味はとても変わっています。

しかし、重要なことは、時にはあなたのウェブカメラであなたを録画し、あなたが見たものと録画を同期させることです!
私はあなたの友人、親戚、あなたの親密な人にこのビデオを表示することに興味がないと思う...

Bitcoinウォレットに$550を転送する: 19fbzcVjCXSwoCjCfKtjRVHaVrghY7ZmDX
私はそれ以降、あなたの "データ"をすべて消去することを保証します:D

このメッセージを読むとタイマーが始まります。 あなたは上記の金額を支払うのに48時間を要します。

送金が完了すると、データは消去されます。
そうでない場合は、感染した瞬間に、録画されたすべてのメッセージとビデオが自動的にあなたのデバイス上にあるすべての連絡先に送信されます。

常にあなたのセキュリティについて考えるべきです。 このケースでは秘密を守るように教えてくれることを願っています。
自分を大事にして下さい。

下らんヤツらだな。いい加減にしておけ。

UEFI と grub あたりのメモ

nort-wmli.blogspot.comここを参考に…。
 

$ su
パスワード: 
tomoki-VJF152 tomoki # cd /boot/efi
tomoki-VJF152 efi # ls
BCD.LOG  EFI  boot-sav
tomoki-VJF152 efi # cd EFI
tomoki-VJF152 EFI # ls
Boot  Microsoft  VAIO  ubuntu
tomoki-VJF152 EFI # ls Boot
bootx64.efi
tomoki-VJF152 EFI # ls Microsoft
Boot
tomoki-VJF152 EFI # ls VAIO
Boot
tomoki-VJF152 EFI # ls ubuntu
fw  fwupx64.efi  grub.cfg  grubx64.efi  mmx64.efi  shimx64.efi
tomoki-VJF152 EFI # ls Microsoft/Boot
BCD           bg-BG         el-GR  hr-HR  memtest.efi  ro-RO       tr-TR
BCD.LOG       boot.stl      en-GB  hu-HU  nb-NO        ru-RU       uk-UA
BCD.LOG1      bootmgfw.efi  en-US  it-IT  nl-NL        sk-SK       zh-CN
BCD.LOG2      bootmgr.efi   es-ES  ja-JP  pl-PL        sl-SI       zh-HK
BOOTSTAT.DAT  cs-CZ         et-EE  ko-KR  pt-BR        sr-Latn-CS  zh-TW
Fonts         da-DK         fi-FI  lt-LT  pt-PT        sr-Latn-RS
Resources     de-DE         fr-FR  lv-LV  qps-ploc     sv-SE
tomoki-VJF152 EFI # ls VAIO/Boot
BCD           bootmgr.efi  es-ES  ja-JP        pl-PL     sl-SI       zh-HK
BOOTSTAT.DAT  cs-CZ        et-EE  ko-KR        pt-BR     sr-Latn-CS  zh-TW
Fonts         da-DK        fi-FI  lt-LT        pt-PT     sr-Latn-RS
Resources     de-DE        fr-FR  lv-LV        qps-ploc  sv-SE
bg-BG         el-GR        hr-HR  memtest.efi  ro-RO     tr-TR
boot.stl      en-GB        hu-HU  nb-NO        ru-RU     uk-UA
bootmgfw.efi  en-US        it-IT  nl-NL        sk-SK     zh-CN
tomoki-VJF152 EFI # man grub-install | less -X
GRUB-INSTALL(8)         System Administration Utilities        GRUB-INSTALL(8)

NAME
       grub-install - install GRUB to a device

SYNOPSIS
       grub-install [OPTION...] [OPTION] [INSTALL_DEVICE]

DESCRIPTION
       Install GRUB on your drive.

       --compress[=no,xz,gz,lzo]
              compress GRUB files [optional]

       -d, --directory=DIR
              use  images  and modules under DIR [default=/usr/lib/grub/<plat‐
              form>]

       --fonts=FONTS
              install FONTS [default=unicode]

       --install-modules=MODULES
              install only MODULES and their dependencies [default=all]

       -k, --pubkey=FILE
              embed FILE as public key for signature checking

       --locale-directory=DIR use translations under DIR
              [default=/usr/share/locale]

       --locales=LOCALES
              install only LOCALES [default=all]

       --modules=MODULES
              pre-load specified modules MODULES

       --themes=THEMES
              install THEMES [default=starfield]

       -v, --verbose
              print verbose messages.

       --allow-floppy
              make  the  drive  also  bootable  as  floppy  (default  for  fdX
              devices). May break on some BIOSes.

       --boot-directory=DIR
              install  GRUB images under the directory DIR/grub instead of the
              boot/grub directory

       --bootloader-id=ID
              the ID of bootloader. This option is only available on  EFI  and
              Macs.

       --core-compress=xz|none|auto
              choose the compression to use for core image

       --disk-module=MODULE
              disk  module  to  use  (biosdisk or native). This option is only
              available on BIOS target.

       --efi-directory=DIR
              use DIR as the EFI System Partition root.

       --force
              install even if problems are detected

       --force-extra-removable
              force installation to the removable media path also. This option
              is only available on EFI.

       --force-file-id
              use identifier file even if UUID is available

       --label-bgcolor=COLOR
              use COLOR for label background

       --label-color=COLOR
              use COLOR for label

       --label-font=FILE
              use FILE as font for label

       --macppc-directory=DIR use DIR for PPC MAC install.

       --no-bootsector
              do not install bootsector

       --no-nvram
              don't  update  the  `boot-device'/`Boot*'  NVRAM variables. This
              option is only available on EFI and IEEE1275 targets.

       --no-rs-codes
              Do not apply any reed-solomon  codes  when  embedding  core.img.
              This option is only available on x86 BIOS targets.

       --no-uefi-secure-boot
              do  not  install  an image usable with UEFI Secure Boot, even if
              the system was currently started using it. This option  is  only
              available on EFI.

       --product-version=STRING
              use STRING as product version

       --recheck
              delete device map if it already exists

       --removable
              the installation device is removable. This option is only avail‐
              able on EFI.

       -s, --skip-fs-probe
              do not probe for filesystems in DEVICE

              Usage: grub-install [OPTION...] [OPTION] [INSTALL_DEVICE]

       Install GRUB on your drive.

       --compress[=no,xz,gz,lzo]
              compress GRUB files [optional]

       -d, --directory=DIR
              use images and modules under  DIR  [default=/usr/lib/grub/<plat‐
              form>]

       --fonts=FONTS
              install FONTS [default=unicode]

       --install-modules=MODULES
              install only MODULES and their dependencies [default=all]

       -k, --pubkey=FILE
              embed FILE as public key for signature checking

       --locale-directory=DIR use translations under DIR
              [default=/usr/share/locale]

       --locales=LOCALES
              install only LOCALES [default=all]

       --modules=MODULES
              pre-load specified modules MODULES

       --themes=THEMES
              install THEMES [default=starfield]

       -v, --verbose
              print verbose messages.

       --allow-floppy
              make  the  drive  also  bootable  as  floppy  (default  for  fdX
              devices). May break on some BIOSes.

       --boot-directory=DIR
              install GRUB images under the directory DIR/grub instead of  the
              boot/grub directory

       --bootloader-id=ID
              the  ID  of bootloader. This option is only available on EFI and
              Macs.

       --core-compress=xz|none|auto
              choose the compression to use for core image

       --disk-module=MODULE
              disk module to use (biosdisk or native).  This  option  is  only
              available on BIOS target.

       --efi-directory=DIR
              use DIR as the EFI System Partition root.

       --force
              install even if problems are detected

       --force-extra-removable
              force installation to the removable media path also. This option
              is only available on EFI.

       --force-file-id
              use identifier file even if UUID is available

       --label-bgcolor=COLOR
              use COLOR for label background

       --label-color=COLOR
              use COLOR for label

       --label-font=FILE
              use FILE as font for label

       --macppc-directory=DIR use DIR for PPC MAC install.

       --no-bootsector
              do not install bootsector

       --no-nvram
              don't update the  `boot-device'/`Boot*'  NVRAM  variables.  This
              option is only available on EFI and IEEE1275 targets.

       --no-rs-codes
              Do  not  apply  any  reed-solomon codes when embedding core.img.
              This option is only available on x86 BIOS targets.

       --no-uefi-secure-boot
              do not install an image usable with UEFI Secure  Boot,  even  if
              the  system  was currently started using it. This option is only
              available on EFI.

       --product-version=STRING
              use STRING as product version

       --recheck
              delete device map if it already exists

       --removable
              the installation device is removable. This option is only avail‐
              able on EFI.

       -s, --skip-fs-probe
              do not probe for filesystems in DEVICE

       --target=TARGET
              install GRUB for TARGET platform [default=i386-pc]

       --uefi-secure-boot
              install  an  image usable with UEFI Secure Boot.  This option is
              only available on EFI and if the  grub-efi-amd64-signed  package
              is installed.

       -?, --help
              give this help list

       --usage
              give a short usage message

       -V, --version
              print program version

       Mandatory  or  optional arguments to long options are also mandatory or
       optional for any corresponding short options.

       INSTALL_DEVICE must be system  device  filename.   grub-install  copies
       GRUB  images  into  boot/grub.   On some platforms, it may also install
       GRUB into the boot sector.

REPORTING BUGS
       Report bugs to <bug-grub@gnu.org>.

SEE ALSO
       grub-mkconfig(8), grub-mkimage(1), grub-mkrescue(1)

       The full documentation for grub-install is maintained as a Texinfo man‐
       ual.   If  the info and grub-install programs are properly installed at
       your site, the command

              info grub-install

       should give you access to the complete manual.

grub-install (GRUB) 2.02~beta2-36November12017nuxmint1         GRUB-INSTALL(8)

 

UEFIブートローダを壊したら

sda1 が ESP だったら(これは調べないといけない)

# mount /dev/sda1 /mnt
# grub-install --target=x86_64-efi --efi-directory=/mnt --bootloader-id=grub

とかかな…。

現在の自分の VAIO の ESP は /dev/sdb2 のようだ。つまり Windows 側。Linux の方の ESP で boot しているのではなかったのだな。Windows の方に GRUB を放り込んでいいのかな。というか、いまそうなっているのだからいいらしい。なお、VAIOBIOS を立ち上げるには [F3] または [F4] を押しながら電源を入れる。

/dev/sda1 が空なので、上の方法で grub-install してみる。しかし /boot/efi が変わらないので、変わりはない。ただ、今度は Windows の方が /dev/sda になった。

/etc/fstab を編集する。

#UUID=1A82-8B7B  /boot/efi       vfat    umask=0077      0       1
UUID=A7F6-B2DF /boot/efi fat32 defaults 0 1

次を実行。

# mount /dev/sdb1 /boot/efi

これではうまくいかない。ちょっと怖いのでこれ以上はやめておく。
 

Python でフィボナッチ数列

最初の100個のフィボナッチ数のリストを計算する関数を記述せよ。定義では、フィボナッチ数列の最初の2つの数字は0と1で、次の数は前の2つの合計となる。例えば最初の10個のフィボナッチ数列は、0, 1, 1, 2, 3, 5, 8, 13, 21, 34となる。

1時間以内に解けなければプログラマ失格となってしまう5つの問題が話題に | ソフトアンテナブログ

 
コード。

def g():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b
i = g()

def fib(n):
    return [next(i) for _ in range(n)]
    
print(fib(100))

ジェネレータと内包表記を使ってみた。
 
obelisk.hatenablog.com

Ruby のクラスメソッド、特異クラスのインスタンス変数

Ruby Gold合格できました。感想と振り返り - 気軽に楽しくプログラムと遊ぶ
ここでちょっとオッと思ったのでメモ。
 

class MyClass
  @v = 1
  def foo
    @v      #=>nil
  end
  
  class << self
    @v = 2
    # 特異クラスへのメソッド定義はクラスメソッド定義
    def foo
      @v    #=>1
    end
  end
end

p MyClass.foo      #=>1
p MyClass.new.foo  #=>nil

こうなるわけですね。

ではと疑問に思うのだが、ここでの @v = 2 の値を取り出すことができるのか。この場所で p self をやると #<Class:MyClass> となるが、これの意味するところは、self のクラスは Class で、そのインスタンスが MyClass ということである。繰り返すが、これが self なわけだ。ということは、MyClass.singleton_class.instance_variable_get(:@v) をすれば 2 を得ることができる。

ということは、

class MyClass
  class << singleton_class
    def foo
      @v
    end
  end
end

p MyClass.singleton_class.foo    #=>2

で OK ですね!

Qiita のデザインパターンまとめがおもしろかった

qiita.comおもしろかったので自己流にメモしておく。
 

Template Method

日記を書いて、複数のフォーマットで出力することを考える。日記の内容は、タイトルと何行かの本文、フォーマットは HTML とプレーンテキスト。

class Diary
  def initialize(title, text)
    @title = title
    @text = text
  end
  
  def output_diary
    output_title
    output_body_start
    output_body
    output_body_end
    puts
  end

  def output_title
    raise 'Called abstract method: output_title'
  end

  def output_body
    raise 'Called abstract method: output_body'
  end

  def output_body_start
  end

  def output_body_end
  end
end

class HTMLReport < Diary
  def output_title
    puts "<title>#{@title}</title>"
  end

  def output_body
    @text.each do |line|
      puts "<p>#{line}</p>"
    end
  end

  def output_body_start
    puts '<body>'
  end

  def output_body_end
    puts '</body>'
  end
end

class PlainReport < Diary
  def output_title
    puts "***#{@title}***"
  end

  def output_body
    @text.each do |line|
      puts "***#{line}***"
    end
  end
end


title = "2018/9/13"
text = ["今日は本屋へ行った。", "夜、デザインパターンのお勉強がおもしろかった。"]

diary1 = HTMLReport.new(title, text)
diary1.output_diary

diary2 = PlainReport.new(title, text)
diary2.output_diary

継承を使う。Diary クラス内の空のメソッドは、PlainText では使わないのでこうなっている。これを「フック・メソッド」という。もちろん、共通の処理があればここで処理すればよい。
結果。

<title>2018/9/13</title>
<body>
<p>今日は本屋へ行った。</p>
<p>夜、デザインパターンのお勉強がおもしろかった。</p>
</body>

***2018/9/13***
***今日は本屋へ行った。***
***夜、デザインパターンのお勉強がおもしろかった。***

 

Strategy

Template Method は、同じレポートなのにフォーマットごとにちがったオブジェクトを作らねばならない。なので、フォーマットを表すクラスを使えば、Diary オブジェクトは同じで済む。

class Diary
  attr_reader :title, :text
  attr_writer :formatter    #集約

  def initialize(title, text, formatter)
    @title = title
    @text = text
    @formatter = formatter
  end

  def output_diary
    @formatter.output(self)     #委譲
  end
end

class HTMLFormatter
  def output(report)
    puts "<title>#{report.title}</title>"
    puts '<body>'
    report.text.each do |line|
      puts "<p>#{line}</p>"
    end
    print "</body>\n\n"
  end
end

class PlainTextFormatter
  def output(report)
    puts "***#{report.title}***"
    report.text.each do |line|
      puts "***#{line}***"
    end
    puts
  end
end


title = "2018/9/13"
text = ["今日は本屋へ行った。", "夜、デザインパターンのお勉強がおもしろかった。"]

diary = Diary.new(title, text, HTMLFormatter.new)
diary.output_diary

diary.formatter = PlainTextFormatter.new
diary.output_diary

レポートを表すオブジェクトはひとつ(diary)で済んでいる。また、フォーマットのクラスは共通の output メソッドをもっていて、Ruby 流のダッグタイピングを使っている。
 

Observer

オブジェクトの状態が変ったら、他所(Observer)へ通知する。通知する場所は自由に追加、削除できる。

class Man
  def initialize(name)
    @name = name
    @observers = []
  end
  
  def wake_up(time)
    @time = time
    notify_observers
  end
  attr_reader :name, :time
  
  # それぞれのオブザーバーに変更を通知
  def notify_observers
    @observers.each do |observer|
      observer.update(self)
    end
  end

  # オブザーバーの追加
  def add_observer(observer)
    @observers << observer
  end

  # オブザーバーの削除
  def delete_observer(observer)
    @observers.delete(observer)
  end
end

class School
  def update(man)
    puts "#{man.name}ですが、#{man.time}に起きました。いまから行きます。"
  end
end

class NewYork
  def update(man)
    puts "Good morning (?) from #{man.name}. Current time is #{man.time} in Kyoto."
  end
end


tomoki = Man.new("Tomoki")

tomoki.add_observer(School.new)
tomoki.add_observer(NewYork.new)

tomoki.wake_up("8:00")

目が覚めたときに Observer(School と NewYork)に現在時刻と名前を通知する。Observer は共通の update メソッドをもっていればよい。ここで通知を受けたときの処理をする。
結果。

Tomokiですが、8:00に起きました。いまから行きます。
Good morning (?) from Tomoki. Current time is 8:00 in Kyoto.

 

Composite

部品から全体を組み立てる。その中で、一日の外出時間を計算してみる。

class Task
  attr_reader :name
  def initialize(name)
    @name = name
  end

  # 所要時間を返すメソッド
  def get_time_required
    0
  end
end

class CompositeTask < Task
  def initialize(name)
    super(name)
    @sub_tasks = []
  end

  def add_sub_task(task)
    @sub_tasks << task
  end

  def remove_sub_task(task)
    @sub_tasks.delete(task)
  end

  def get_time_required
    @sub_tasks.inject(0) {|time, task| time + task.get_time_required}
  end
end


class Library < Task
  def initialize
    super("図書館")
  end
  
  def get_time_required
    20
  end
end

class BookStore < Task
  def initialize
    super("本屋")
  end
  
  def get_time_required
    15
  end
end

class MisterDonut < Task
  def initialize
    super("ミスタードーナツ")
  end
  
  def get_time_required
    10
  end
end

class ReadBook < Task
  def initialize
    super("読書")
  end
  
  def get_time_required
    45
  end
end

class FoodCourt < CompositeTask
  def initialize
    super("フードコート")
    add_sub_task(MisterDonut.new)
    add_sub_task(ReadBook.new)
  end
end

class AEON < CompositeTask
  def initialize
    super("イオンモール")
    add_sub_task(BookStore.new)
    add_sub_task(FoodCourt.new)
  end
end

class OneDay < CompositeTask
  def initialize
    super("今日一日")
    add_sub_task(Library.new)
    add_sub_task(AEON.new)
  end
end

puts OneDay.new.get_time_required    #=>90

Task クラスがいちばん小さい単位。それを CompositeTask クラスで組み立てるだけ。Task クラスを継承しているものを「葉」、CompositeTask クラスを継承しているものを「コンポジット」という。get_time_required メソッドが共通である。それぞれのクラスでは独自のメソッドを他にもってもよい。

記録メディアをまるごとコピーする(Linux)

正確にはコピーではなくて、パーティション情報も含めてメディア(例えば USBメモリ)をまるごとクローンする。

$ sudo dd if=/dev/sdc of=/dev/sdd

みたいな感じ。ただし、この場合だと sdc よりも sdd の容量が多いか同じである必要がある。それから、本当は bs オプションを使った方がいいらしい。

sdd の方が容量が多い場合、sdd の余った部分は Gparted で元のパーティションにマージする。


※参考
ddとGPartedを使ってOSの乗ったドライブを新しいドライブへ移動する
ddコマンドのbsサイズ