ドメイン取りました

http://ororog.org を取得した。
色々調べたところ、無料でドメインを設定してくれるところがあるっぽいので、いくつか試してブログ部分が移行できるか試したい。
ホストとしては、次の2つを試す

有名

  • netlify

調べてたら知った。CI とかできて便利そう。

ブログツールとしては hugo を試す。
hatena みたいに web だけで完結しないので、更新がめんどくなるかもしれないしそうでもないかもしれない。

Requests + BeautifulSoup で html から form データの雛形作成他

Requests と BeautifulSoup は忘れた頃に使って何度も調べるのでメモ。小ネタ。

Requests を使ってログイン処理をするときはだいたいこんな処理をかく。

s = requets.Session()
r = s.get('http://example.com/login')
soup = BeautifulSoup(r.content, 'html.parser')
payload = {
  'id': 'id',
  'password': 'password'
}
s.post('http://example.com/login', data=payload)

payload の部分がこれくらいシンプルならいいけど、csrf token とかをつけて送る場合に BeautifulSoup を使って token 部分を抜き出す必要がある。そんなときはだいたい以下のようなコードを書いて payload の雛形を作る

内包表記ver

payload = {
    input['name']: input['value'] if input.has_attr('value') else ''
    for input in soup.select('form input')
    if input.has_attr('name')
}

for でシンプルに書くとこんな感じ

payload = {}
for input in soup.select('form input'):
    if not input.has_attr('name'):
        continue
    value =  input['value'] if input.has_attr('value') else ''
    payload[input['name']] = value

あとはこの payload に適当に id/pass を詰め込んで post すればよい。

その他メモ

  • BeautifulSoup はdict の ように in を使って要素があるか問い合わせてはダメ('value' in input みたいな)。has_attr を使う。
  • Cookie とか使うなら Session を使う。
  • Session の save / load は pickle でいけそう
import requests, requests.utils, pickle
session = requests.session()
with open('somefile', 'w') as f:
    pickle.dump(session, f)
with open('somefile') as f:
    session = pickle.load(f)
  • findAll ? find_all ? どっちやねん > find_all らしい (最近のpythonのスタイルに従う)

python - beautifulsoup findAll find_all - Stack Overflow

AtCoder ABC 105 D

python に慣れるため久しぶりにプロコンをやってみた。今の AtCoder になってから初だと思う。

D: Candy Distribution - AtCoder Beginner Contest 105 | AtCoder

code

from collections import defaultdict

N, M = map(int, input().split())
A = list(map(int, input().split()))

Amod = defaultdict(int)
sum_mod = 0
for v in A:
    sum_mod = (sum_mod + v) % M
    Amod[sum_mod] += 1

sum_mod = 0
ans = 0
for v in A:
    ans += Amod[sum_mod]
    sum_mod = (sum_mod + v) % M
    Amod[sum_mod] -= 1

print(ans)

解き方、感想

0 .. r (r = 0 .. N) の範囲の和の mod を hash に覚えておく。
0 .. l で l を動かして、0 .. r の和のmodから 0..l の 和の mod を引いて、mod が 0 になるようなもの (hash[ 0..l の和のmod] で個数がすぐに出せる)を足していく感じ。

python は慣れてないけど、defaultdict ないと面倒くさそう。
他の人のコードみて勉強せな。

  • AtCoder は気軽に他の人のコード見れない?topcoder は見れるから勉強しやすい。
  • AtCoder の解説は結構あっさりしてて、わかる人向けの解説って感じがする(解いたけど解説読んでもよくわからない…)。動画を見ればいいのかな。

emacs vue-mode で構文チェックする領域がおかしくなったの対処方

vue-mode で書いていると構文チェックする領域がおかしくなるときがある。vue-mode の、というより mmm-mode で発生する現象なのかもしれない。
具体的には

広告を非表示にする

(小ネタ) BetterTouchTool で右ALT、 左ALT の使い分け

自分は右ALTをほとんど使わないので、右ALT を修飾キーに使えたら便利だな〜と思って調べたら、普段から使ってる BetterTouchTool にその機能があった。

使い方はこう
Add New Shortcut... を押して、左下に出てくる歯車アイコンをクリック
f:id:ororog:20180808204802p:plain

ここでDifferentiate between ... にチェックを入れると左右ALTが別になる。
f:id:ororog:20180808204849p:plain

自分は Mac の Ctrl + PNFB による移動ができないとき、いちいちアローキーを触っていたが、これでだいぶストレスが改善された。もっと早く知っていれば…

ちなみに、Key Repeat も設定できる。
この部分。
f:id:ororog:20180808205822p:plain

Vue で動的にコンポーネントを追加

Vue で動的にコンポーネントを追加したい

よくある TODO アプリで言うと、ボタンを押したらTODO を追加したい。
UIとしたらこんな感じ
f:id:ororog:20180806191238p:plain
TODO追加ボタンを押すたびにコンポーネントを追加したい。

new するやり方(正しくないやり方)

先に書いておくとこのやり方はたぶん正しくないが、最初にこのやり方で調べてしまったので書いておく。

TodoItem を次のように定義する。

<template>
<li class="todo-item">{{text}}</li>
</template>

<script>
export default {
  name: 'TodoItem',
  props: {
    'text': String
  }
}
</script>

これをボタンが押されるたびに追加する。

TodoList の方はこう

<template>
<div class="todo-list">
  <div>
    <ul ref="todo-list">
    </ul>
  </div>
  <form v-on:submit.prevent="onSubmit">
    <textarea v-model="text"/>
    <input type="submit" value="TODO追加"/>
  </form>
</div>
</template>

<script>
import TodoItem from './TodoItem'
import Vue from 'vue'

export default {
  name: 'BadTodoList',
  components: {
    'todo-item': TodoItem
  },
  data () {
    return {
      text: ''
    }
  },
  methods: {
    onSubmit () {
      let clazz = Vue.extend(TodoItem)
      let instance = new clazz({
        propsData: {
          text: this.text
        }
      }).$mount()
      this.$refs['todo-list'].appendChild(instance.$el)
      this.text = ''
    }
  }
}
</script>

<style scoped>
.todo-list {
    text-align: left;
}
</style>

ポイントは、Vue.extend。Vue のコンポーネントはインポートしただけでは class の設計図の状態で、new できないようだ。そこで Vue.extend することで new できる形になる。
また、new しただけではまだ dom は作られていないので、$mount() をよんで上げることで実体化する。実体化したコンポーネントのdom は $el で参照できるので、それを appendChild してやればよい

data を使うやり方(正しそうなやり方)

そもそも、todo を vue のデータに乗っけないで自分で管理するのはおかしい。なので、以下のやり方が正しいはず。

<template>
<div class="todo-list">
  <div>
    <ul>
      <todo-item v-for="todo in todos" v-bind="todo" />
    </ul>
  </div>
  <form v-on:submit.prevent="onSubmit">
    <textarea v-model="text"/>
    <input type="submit" value="TODO追加"/>
  </form>
</div>
</template>

<script>
import TodoItem from './TodoItem'

export default {
  name: 'TodoList',
  components: {
    'todo-item': TodoItem
  },
  data () {
    return {
      text: '',
      todos: []
    }
  },
  methods: {
    onSubmit () {
      this.todos.push({
        text: this.text
      });
      this.text = ''
    }
  }
}
</script>

<style scoped>
.todo-list {
    text-align: left;
}
</style>

v-for として todo-item を呼び出して、todo 自体は array で管理する。
なんとなくだけど、前半のやり方は他のライブラリを呼び出す用途以外では基本的に間違っている気がする。

Vue で Uncaught RangeError: Maximum call stack size exceeded

VueJs でコンポーネントを作っていたら真っ白なページが表示されている。
コンソールを見るとこんなエラーが出ていた。

Uncaught RangeError: Maximum call stack size exceeded
    at Watcher.get (vue.esm.js?efeb:3156)
    at new Watcher (vue.esm.js?efeb:3131)
    ....

何が原因かと小一時間悩んだ結果、コンポーネントの中で自分自身を呼び出していたのが原因だった。
例えば

<template>
  <ErrorComponent></ErrorComponent>
</template>

<script>
export default {
  name: 'ErrorComponent'
}
</script>

内部で ErrorComponent(自分自身) を呼び出さなければ解決。