| @ブログ

75 件ほどあった tech.portalshit.net の記事を取り込んだ。実家に住んでいた 10 年前に始めた技術ブログで、最初は Rails 製の Mephisto 、その次に Jekyll で構築した。まだ GitHub Pages の仕組みが存在する前で、自前で用意したさくら VPS に git push すると自動でビルドして記事が公開されるような仕組みを作ったりしてた。

職業プログラマーになろうとしてもがいてた頃にやってたブログで、いま読み返すと「頑張ってたんだな」感があっていなたい記事が多い。

だいぶ放置していて、いまは S3 で静的サイトとして公開していたのでそのまま放置でもよかったが、 10 年前と違って何でも一カ所にまとめて書いておきたいという気持ちが強くなって取り込むことにした。ブログはトピックを混ぜずに一つのトピックにフォーカスした方がよいと 10 年前は考えていたのだけど、最近の世の中のブログ記事の読まれ方は変わってきていて、一人の人のブログをフィードリーダーに登録して読むというより、 SNS をだら見していて流れてきた記事を適当に消費するというスタイルに変わってきているので、一つのブログに一つのテーマという書き分けは不要になったと感じる。

tech.portalshit.net を取り込んだおかげで Archive ページのグラフに占める技術記事の割合が増えた。

Tech category Bar extension

ちなみに取り込みは以下のようなコードを書いて SQL の INSERT 文に変換した。

require 'yaml'
require 'pathname'

files = Dir.glob(File.join(__dir__, '_posts', '*.markdown'))
files.each do |file|
  content = File.read(file)
  _, header, body = content.split('---')
  header_yml = YAML.load(header)
  title = header_yml['title']
  tags = header_yml['category']
  tags = tags.is_a?(Array) ? tags.map(&:downcase) : [tags&.downcase]
  slug = Pathname.new(file).basename.to_s.sub(/\d{4}\-\d{2}\-\d{2}\-(.+?)\.markdown/, '\1').gsub('_', '-')
  body = body.strip.gsub(/\n/, "\\n").gsub('\'', '\'\'')
  created_at = File.birthtime(file).to_s.sub(' +0900', '')
  updated_at = File.mtime(file).to_s.sub(' +0900', '')
  puts <<~EOS
    INSERT INTO entries(title, user_id, category_id, slug, markup, type, draft, body, frozen_tag_list, created_at, updated_at) VALUES('#{title}', 1, 6, '#{slug}', 'redcarpet', 'Post', 0, '#{body}', '#{tags.join(',')}', '#{created_at}', '#{updated_at}');
  EOS
end

| @ブログ

Chart Tooltip

Archive ページにこだわってしまう理由、グラフを表示させてみて(ブログ過去記事をカテゴリーごとに集計してグラフ化 - portal shit!)何となくわかった気がする。過去記事ページというのはブログの書き手にとってはアクティビティダッシュボードなのだ。ジョギング系アプリ使ってる人なら記録をあとから振り返ることがあると思う。それと同じで、自分が過去にどのくらいの頻度、密度でブログを書いていたかを自分は知りたいと思うのだろう。その用途に適しているのが過去記事ページというわけで、 Archive ページの使い勝手の改善は自分のブログアクティビティをふり返りやすくしたいという欲求の表れだったのだと思う。

ちなみにグラフを作ってみたことで、 2006 年頃に異常な数の記事を書いていたことがわかったし、かなり内容のない記事(新聞やテレビを見た感想)ばかり書いていたことがわかって興味深かった。 2007 年からは記事の数が減るが、これは Twitter を使い始めたからだと思う。2009 年頃、病気療養を終えて就職しようとしているあたりからプログラミング関係の記事の数が増え、実家を出て福岡のブラック企業に勤め始めてからは記事数が減った。

あまり ASP 型のブログを使ったことがないのでよく分からないが、こういうカテゴリーごとの Chart 機能はないような気がする。一時期、ダイエット日記を書いていたはてなブログにはアクセス解析機能とアクセス数の統計機能はあったが、自分のブログアクティビティを振り返る機能はないと思う( PRO になればあるのかもしれない)。

自己満足的なブログの書き手にとっては、どれだけ読まれたかももちろん気になるけど、どれだけ書いたかも重要なのではないかと思う。読まれたかというのは結果であり、書いたかというのはプロセスというか、自分の頑張りだ。仕事をする上では結果にフォーカスしなければ意味がないけど(使われない機能を作ってリリースするのは自己満足)、ブログは趣味なのだからプロセスの部分(自分の頑張り)が可視化される仕組みがあってもよいと思う。

| @技術/プログラミング

Chart

Rechars という React のチャートライブラリを利用して、 Archive ページにカテゴリーごとに記事を集計してグラフ化する機能を作った。

グラフの Bar にカーソルを載せると Tooltip が表示されて、具体的な件数がわかる。

Chart Tooltip

カテゴリごとに表示・非表示を切り替えることも可能。グラフ下のカテゴリー名( Legend )をクリックして切り替えられる。

Chart Show-Hide Toggle

ただし残念なことに Bar を非表示にしたときに Legend の表示を変化させるのが難しくてできていない。

仕事で使ってる Looker とか Redash であれば Legend をクリックして表示・非表示を切り替えることができ、それに連動して Legend の色をトーンダウンさせたりする機能が付属しているが、利用した Recharts にはその機能がなかった。 Bar の表示・非表示切り替えも標準サポートされていなかったので、 GitHub の Issue の情報を頼りに無理矢理実装した。

コードはこんな感じ。結構汚い Hack で、 Bar の表示・非表示を、表示用のキー文字列に空白を追加するかしないかで切り替えている。

  // クリックされたアイテムが `this.state.disabled` 配列の中にすでに存在していれば除外し、
  // 存在してなければ追加する
  selectBar(event) {
    let dataKey = event.dataKey.trim()
    if (this.state.disabled.includes(dataKey)) {
      this.setState({ disabled: this.state.disabled.filter(item => item !== dataKey) })
    } else {
      this.setState({ disabled: this.state.disabled.concat([dataKey]) })
    }
  }

  render() {
    return (
      <ResponsiveContainer height={500}>
        <BarChart
          data={this.state.data}
          margin={{
            top: 20, right: 20, left: 0, bottom: 20,
          }}
          style={{ fontSize: '14px' }}
        >
          <CartesianGrid strokeDasharray="3 3" />
          <XAxis dataKey="year" />
          <YAxis />
          <Tooltip labelStyle={{ color: '#000', fontWeight: 'bold' }} itemStyle={{ margin: '0 2px 0 4px', padding: '0' }} />
          {// Legend クリック時のコールバックに `this.selectBar` を指定する }
          <Legend onClick={this.selectBar} />
          {/*
            `this.state.categories` 配列と `this.state.disabled` 配列の内容を比較し、
            `this.state.disabled` に追加済のカテゴリーは dataKey に空白を追加することで非表示に
          */}
          {this.state.categories.map((category, index) => {
            let dataKey = this.state.disabled.includes(category) ? category + " " : category
            let color = this.colors[index % this.colors.length]
            return(<Bar key={index} dataKey={dataKey} stackId="a" fill={color} />)
          })}
        </BarChart>
      </ResponsiveContainer>
    );
  }

| @技術/プログラミング

react-select-before-after.jpg

一個前の記事のキャプチャにあるように、従来テキストリンクだった年とカテゴリーの選択をセレクトボックスにした。 git log -S したところ去年( 2019 年)の 11 月頃に変更を行ったみたいだ。もうそろそろ 2020 年になろうとしていて、 2005 年からやっていて年の数が 16 個になろうとしていてさすがに多すぎると思ったので整理のためにセレクトボックス化してコンパクトにした。

利用したのは React Select というパッケージで、色々カスタマイズできるみたいだけど面倒だったので素のまま使ってる。

Archives ページのリファクタリング のときのように、子コンポーネントのイベントをトリガーに親コンポーネントの setState() を呼び出すような作りになっている。作るときは結構難儀したけどおかげでスマートフォンで見たときも年やカテゴリーだけでファーストビューが埋まるということがなくなった。

react-select-smartphone-view.jpg

現在のコードをまるっと貼り付けるとこんな感じ↓。

子コンポーネント(年のセレクトボックス)

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import Select from 'react-select'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router-dom'

import history from './history'

class YearSelect extends Component {
  constructor(props) {
    super(props)
    this.state = {
      data: [],
      selectedOption: null
    }
    this.handleChange = this.handleChange.bind(this)
  }

  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  async loadYearSelectFromServer() {
    const request = await fetch('/archives/years.json')
    const response = await request.json()
    this.setState({ data: response })
  }

  componentDidMount() {
    this.loadYearSelectFromServer()
  }

  handleChange(selectedOption) {
    const year = selectedOption ? selectedOption.value : null
    if (year) {
      this.props.history.push(`/archives/${year}`)
    } else {
      this.props.history.push("/archives")
    }
    this.setState(
      { selectedOption },
      () => { this.props.update(year) }
    )
  }

  render() {
    const options = this.state.data.map(year => {
      return { value: year, label: year }
    })
    return (
      <div className="year-list">
        <Select
          value={this.state.selectedOption}
          onChange={this.handleChange}
          options={options}
          placeholder="Year"
          isClearable
        />
      </div>
    )
  }
}

const YearList = withRouter(YearSelect)

export default YearList

親コンポーネント( App.js )

import React, { Component } from 'react'
import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom'

import YearList from './YearList'
import CategoryList from './CategoryList'
import Archives from './Archives'

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      category: null,
      year: null,
      length: 0
    }
    this.updateCategory = this.updateCategory.bind(this)
    this.updateYear = this.updateYear.bind(this)
    this.setLength = this.setLength.bind(this)
  }

  updateCategory(category) {
    this.setState({ category })
  }

  updateYear(year) {
    this.setState({ year })
  }

  setLength(length) {
    this.setState({ length })
  }

  render() {
    return(
      <Router history={history}>
        <div className="archive-filter">
          <YearList update={this.updateYear} />
          <CategoryList update={this.updateCategory} activeCategory={this.state.category} />
          <div className="entry-length"><p>{this.state.length} entries</p></div>
        </div>
        <Switch>
          <Route
            exact path="/archives"
            render={(props) =>
              <Archives
                category={this.state.category}
                setLength={this.setLength}
                {...props}
              />
            }
          />
          <Route
            path="/archives/:year(\d{4})"
            render={(props) =>
              <Archives
                category={this.state.category}
                setLength={this.setLength}
                year={this.state.year}
                {...props}
              />
            }
          />
        </Switch>
      </Router>
    )
  }
}

export default App

| @技術/プログラミング

Archives ページ記事絞り込み

Archives ページに記事数を表示するようにした。一昨日、年を未指定の場合は全件読み込むようにしたので Archives ページを訪れると総記事数が確認できるようになった。年やカテゴリーで絞り込むと絞り込み後の件数を確認できる。カテゴリーごとの記事の偏り具合が確認できて便利。

さらにカテゴリーのセレクターは記事件数順でソートするようにした。これまでは categories.id でソートしていたため、件数の多いカテゴリーがセレクトボックスの下の方に埋もれたりしていてあまり良い絞り込み体験ではなかった。

こうしてカテゴリーごとに記事を絞り込んでみてみると、意外と違和感のある分類になっていることに気がつく。記事のカテゴリーに関してはあまり意味ないというか分類が難しいものもあると思う。ブログというカテゴリーに分類してみたものの、実際の記事内容はプログラミング寄りだったりして、読者が読みたい記事を探す際の指針とはなり得ないなと思う。 TF-IDF のような機械的な関連判定が記事のグルーピングには有効だと思う。勝手にカテゴリー付けしてくれたら便利だと思う。

技術的な話をすると、選択したカテゴリーで記事を絞り込む都合上、件数のカウントはフロントエンドで行う必要があった。実は 2 年くらい前の Archives ページにも絞り込み時の件数表示機能はあったのだが、当時は React の機能を活用できておらず、記事の絞り込みは Virtual DOM の操作ではなく CSS の display: none; でやっていて jQuery と大差なかった。記事の絞り込みを React の機能を使ってやるようになってから件数の表示ができていなかったのをできるようにしたのが今回というわけだ。

お爺さんコンポーネントで定義した関数をひ孫コンポーネントまで伝搬させて、結果が変わるとお爺さんコンポーネントの state が書き変わる。ちょっと setState() を使いすぎていて微妙に画面がチラつく( state を更新するたびにレンダリングが行われるため)。もっとうまいやり方があるのかもしれない。

これをやるにあたってこれまで関数として実装していたコンポーネントをクラス化した。 return() の前処理でやっていたゴニョゴニョを componentDidMount() に移す必要が出たが、実は componentDidUpdate() でもやらなければならなかったり、 componentDidMount() 時にはまだ props が渡されてきてないので componentDidUpdate() で実行する必要があったりと、結構ハマりどころがあった。コンポーネントはなるべくクラス化するのが格好いいような気がしていたけど、凝ったことをやる必要がないコンポーネントは関数のままの方がよいと思った。この辺も改めて React はよくできていると感心する。

| @散財

iPhone 11 表面

親父にあげていた iPhone 6 のバッテリーが寿命のようで、 iPhone 7 を譲るために新しい iPhone を買った。 iPhone 11 の 128GB にした。 88000 円くらい。魅惑のオリコローン、 24 回払い分割金利手数料無料で購入した。 iPhone 7 は 2016 年末に買ったのでまるまる 3 年使った。

外観と Face ID

ごっついレンズが複数付いた外観は好きになれなかった。 iPhone 11 Pro は高すぎて買えなかったが外観的にも個人的に受け入れられなかった。 iPhone 11 のレンズ二つの外観もいびつに見えたが、いまさら iPhone XR を買うのは何だかなという感じなので消極的に iPhone 11 を選んだ。

iPhone 11 背面

ケースを付けるかは迷った( iPhone 7 はケースを付けない状態が一番使いやすかった)が、結局付けた。ケースを付けないとレンズの出っ張りが邪魔で、背面を下にしてテーブルに置いたときに安定しない(ガタガタする)。レンズ面の出っ張り対策としてケースは必要だと思った。ケースは Amazon で評価のよかった以下を騙されたと思って買ったけど実際とても良かった(サクラレビューではないようだった)。

ホームボタンと Touch ID のないモデルは初めてで、 Face ID は Apple Pay の支払時に不便かなと懸念していたが、スリープボタンをダブルタップして読み取り機にかざす前に Face ID 認証すればよいのでかえって便利になった。 NFC 認証のスピードも速くなっている気がする(コンビニのレジでもたつくことがなくなった)。

Face ID になってよかったことに、スクリーンプロテクターが全面を覆い隠せるようになったことがある。 Touch ID 方式だとホームボタンは指紋認証のために覆うことができず、スクリーンプロテクターに妙な穴が開いてたりしていて不格好だった。全面を覆えるものを買ったがとても良い。何もはっつけていないみたいに見える。

スクリーンプロテクターは以下のものを買った。貼り付け時に貼り付け位置を失敗しないようにサポートするプラスチックの枠が付いていてスーパー便利だった。これまで位置ずれを気にしながら貼っていたのがバカみたいだった。

重い

iPhone 11 、とにかく重い。調べたところ 194g のようだった1。 iPhone 7 は138g だったみたいなので 56g くらいしか重くなってないのに随分重く感じる。検証機として会社から借りてる Pixel 3a に比べても重い。 50g の差がスマートフォンでは決定的な違いになるんだなと思った。

iPhone 11 と Pixel 3a

電池のもち

重くなったおかげか、バッテリー容量が増えていて電池がとてもよくもつようになった。 iPhone 7 はバッテリーを一度 Apple Store で交換してもらったが、それでもヘビーに使うと一日電池がもたなかった。 iPhone 11 で不意に電池切れになって困った、ということは起こりそうにない。

写真

写真に関しては、日中に撮れる写真の画質は iPhone 7 の頃と大差ないと感じる。もっと綺麗な写真が撮れるかなと思ったけどそうでもなかった。ポートレートモードも試したが、ぼかし処理が甘くて(特に物撮り)被写界深度的に「そこ違うんだけどな」というところがぼけてしまったりする。一眼で撮るのには及ばない。

広角レンズはおもしろい。室内や街並みなどは広角で撮ると楽しい。

街並み

川や道路の大きさ、スケール感が伝わる。

博多川 リバレイン通り

室内

店内の壁一面に手書きのいろんなメニューが貼ってある面白定食屋の様子。店内は広くなく、標準のカメラでは到底壁一面の様子などを写すことはできないが、広角レンズで撮影することができた。

定食屋店内 定食屋店内

ナイトモード

ナイトモードもなかなかおもしろい。 NIKON Z6 を買って最近のカメラの夜景撮影能力に感動していたが、 iPhone 11 のカメラで撮る夜景も大分すごい。以下は近所の山に夜景を撮りに行ったやつの比較。

街の夜景

Z6 で撮った写真は三脚に固定して撮っている。一方 iPhone は手持ち。これはすごい。

今山から見る今宿( NIKON Z6 で撮影)

今山から見る今宿( iPhone 11 で撮影)

夜の踏切

Z6 は ISO 感度が 51200 まで上がってしまってノイズだらけになってしまっている。 iPhone 11 の方は ISO 800 で撮って補正しているのでノイズが少ない。

今宿の踏切( NIKON Z6 で撮影)

今宿の踏切( iPhone 11 で撮影)

こんな感じで、ミラーレスカメラと同等の、状況次第ではミラーレス以上に綺麗な夜景写真が撮れてしまう。画像補正処理技術の向上すごい。


最初は「う〜ん」と思っていた iPhone 11 の外観や重さだけど、使っていくうちに広角レンズの便利さや電池のもちの良さなど、 iPhone 11 の良さがしみじみとわかってきた。値段は iPhone 11 Pro ほどには高くないし、買ってよかったなと思える端末でした。便利。

| @WWW

Temple wall at Hakata

ヒトデさんのブログを読んでGoogleの広告設定を共有してメンバー間でつながるプロジェクトに参加した

Google の広告設定のページにアクセスすると Google からどういう属性として認識されているかがわかり、それを共有して遊ぼうというもの。 Scrapbox はタグ付けが簡単なので人と人の関連性が表現しやすい。

おもしろかったので、普段使ってる三つの Google アカウントでそれぞれでどういう結果になるかやってみた。

個人アカウント

iPhone の Safari でも自宅の Mac でもログインしててよく使うアカウント。ただ最近は Google 検索をあまり使わないようになって、検索には DuckDuck Go を使うようにしている。 #企業向けテクノロジー #業種:_ヘルスケア業界 #業種:_テクノロジー業界 あたりが入っているのがおもしろい。前職が B2B の SaaS / クラウドソーシング企業だったこと、現職がアウトドア関連の企業であることを反映してそう。

#35~44_歳 #男性 #Anova_Culinary #TechAcademy_[テックアカデミー] #Mynavi #Amazon #American_Express #Aha! #Wantedly #Fujitsu #Bic_Camera #Yodobashi_Camera #Kakaku.com #SoftBank_Telecom #Apple_iOS #Mac_OS #SF_映画、ファンタジー映画 #SF_番組、ファンタジー番組 #TV_ゲーム、PC_ゲーム #アウトドア #アクション映画、アドベンチャー映画 #アニメ、漫画 #アメリカン_フットボール #イベント情報 #インディーズ音楽、オルタナティブ_ミュージック #ウェブデザイン、開発 #エクストリーム_スポーツ #オーディオ機器 #オフィス、ビジネスソフトウェア #お祝い、ギフト、祝祭日用グッズ #カメラ #カメラ_レンズ #カメラ、写真機材 #クーポン、割引サービス #クラウドストレージ #クラシック音楽 #グルメ食品、特別食 #クレジット_カード #ゲーム機 #コーヒー_メーカー、エスプレッソ_マシン #コーヒー、紅茶 #コミック、アニメーション #コメディ映画 #コンピュータ_コンポーネント #コンピュータ_ドライブ、ストレージ #コンピュータ_ハードウェア #コンピュータ_モニター、ディスプレイ #コンピュータ、電化製品 #コンピュータ周辺機器 #コンピュータ用メモリ #サイクリング #サッカー #ジャズ #ショッピング #スポーツ #スポーツ衣料 #スマートフォン #ソーシャル_ネットワーク #タブレット_PC #ダンス、電子音楽 #ツアー旅行 #デジタル一眼レフ_カメラ #テレビ、ビデオ、動画 #テレビドラマ #ドキュメンタリー番組、ノンフィクション番組 #トラック、バン、SUV #ニュース #バー、クラブ、ナイトライフ #ハイキング、キャンプ #ハッチバック #ビーチ、島 #ビジネス_サービス #ビジネス_ニュース #ビジュアル_アート、デザイン #ファースト_フード #ファッション、スタイル #フィットネス用品 #フォーク、伝統音楽 #ブランド品、高級品 #ブルース #プログラミング #ペット #ボート #ホームの自動化 #ポップ_ミュージック #マセラティ #ラグビー #ラップトップ、ノートパソコン #ランニング、ウォーキング #リフォーム #レストランのレビュー、予約 #レンタカー、タクシー #ロック_ミュージック #ワールド_ミュージック #飲食店 #映画 #音楽、オーディオ #価格比較 #家庭 #家電 #会計、財務ソフトウェア #確定申告、税務 #学歴:_学士号 #環境に優しい生活、環境問題 #企業向けテクノロジー #業種:_ヘルスケア業界 #業種:_テクノロジー業界 #銀行 #携帯電話 #芸術写真、デジタル_アート #芸能ニュース #個人ブログ、サイト #佐賀 #財務プランニング、マネジメント #山岳、スキー_リゾート #仕事 #子育て、育児 #子供の有無:_子供なし #子供服 #自動車 #自動車販売 #室内装飾、内装 #写真、画像の共有 #写真の印刷サービス #写真編集ソフト #社員数:_中規模雇用者(従業員数:_250~999_人) #授乳用品、離乳食用品 #住宅所有状況:_住宅所有 #書籍、文学 #商品レビュー、価格比較 #食器洗い機 #世界のニュース #世帯収入:_高 #政治 #送金・決済システム、サービス #大学 #都市交通 #投資 #東京 #動画編集ソフトウェア #日本 #配偶者の有無:_既婚 #美容、フィットネス #表計算ソフトウェア #舞台芸術 #福岡 #分散コンピューティング、クラウド_コンピューティング #宝石、アクセサリー #旅行 #料理、レシピ #量販店、デパート #腕時計

趣味アカウント

昔はよく使っていたが最近はあんまり使ってない。主に Mac で使ってた。いまは YouTube でのみこのアカウントを使ってる。

#35~44_歳 #男性 #SF_映画、ファンタジー映画 #SF_番組、ファンタジー番組 #アメリカン_フットボール #イベント情報 #ギター #クイズ番組 #クラシック音楽 #グルメ食品、特別食 #コーヒー、紅茶 #コミック、アニメーション #コンピュータ_ハードウェア #コンピュータ、電化製品 #ショッピング #スポーツ #ソーシャル_ネットワーク #テレビ、ビデオ、動画 #テレビドラマ #トーク番組 #ニュース #バスケットボール #ビジネス_サービス #ビジュアル_アート、デザイン #フィットネス #ヘヴィメタル #ペット #ホームの自動化 #ポップ_ミュージック #ラグビー #リアリティ番組 #リフォーム #ロック_ミュージック #ワールド_ミュージック #映画 #音楽、オーディオ #家族向けテレビ番組 #学校、教室関連用品 #環境に優しい生活、環境問題 #業種:_テクノロジー業界 #芸能ニュース #子供の有無:_3_要素 #自動車 #自動車販売 #室内装飾、内装 #社員数:_小規模雇用者(従業員数:_1~249_人) #住宅所有状況:_住宅所有 #書籍、文学 #商品レビュー、価格比較 #食料品小売業 #世帯収入:_平均以上 #政治 #都市交通 #東アジアの音楽 #配偶者の有無:_既婚 #美容、フィットネス #舞台芸術 #服飾 #分散コンピューティング、クラウド_コンピューティング #野球 #料理、レシピ #量販店、デパート

仕事用アカウント

会社の Gsuite のアカウント。 Chrome の Canary Channel で利用していて、個人アカウントとは明確に使い分けてる。仕事関係の検索やサイト閲覧はほぼほぼこのブラウザーで行っている。仕事用アカウントなので買い物とか趣味の検索はほとんどしない。どうも消費に結びつく検索をしないと世帯収入が低く出る模様。逆に個人アカウントでは頻繁に消費に関係する検索を行っているので世帯収入が高いと判定されてるっぽい。また個人的な用途に使わないので年代を特定できず、 25〜54_歳 という扱いになってるのも面白い。

#25~54_歳 #男性 #Apple_iOS #TV_ゲーム、PC_ゲーム #アウトドア #アクション映画、アドベンチャー映画 #アメリカン_フットボール #エクストリーム_スポーツ #オーディオ機器 #オフィス、ビジネスソフトウェア #カメラ、写真機材 #クーポン、割引サービス #クラウドストレージ #グルメ食品、特別食 #クレジット_カード #コミック、アニメーション #コンピュータ_ハードウェア #コンピュータ、電化製品 #ショッピング #スポーツ #スマートフォン #ソーシャル_ネットワーク #テレビ、ビデオ、動画 #テレビドラマ #ニュース #ハイキング、キャンプ #ビジネス_サービス #ビジュアル_アート、デザイン #ファッション、スタイル #フィットネス #ブランド品、高級品 #ペット #ホームの自動化 #ラグビー #ランニング、ウォーキング #飲食店 #映画 #音楽、オーディオ #価格比較 #家庭 #家電 #学校、教室関連用品 #学歴:_学士号 #企業向けテクノロジー #起業準備 #業種:_テクノロジー業界 #携帯電話 #芸術写真、デジタル_アート #芸能ニュース #犬 #山岳、スキー_リゾート #子供の有無:_子供なし #自動車 #自動車販売 #室内装飾、内装 #社員数:_中規模雇用者(従業員数:_250~999_人) #住宅所有状況:_住宅所有 #書籍、文学 #商品レビュー、価格比較 #世帯収入:_平均以下 #送金・決済システム、サービス #都市交通 #配偶者の有無:_既婚 #美容、フィットネス #舞台芸術 #服飾 #分散コンピューティング、クラウド_コンピューティング #旅行 #料理、レシピ