DNSサーバの種類とDNSサーバの受ける問い合わせの種類についてまとめました
参考のところに載せてるんですけど、DNSについて勉強する前に読みたかった資料です*1。もし、他の人がこの記事を見てDNSについてちょっと調べてみようと思ったら3分くらいは眺めてから調べ始めるとはかどると思います。
http://2014.seccon.jp/dns/dns_basics_in_30minutes.pdf
ただ、問い合わせの特徴によって覚えて区別つけるのもいいんですけど、基本的にどのプロトコルのアプリケーションやそれらのアプリケーションたるWebサービスなんかもサーバがクライアントから受けるリクエストによって挙動を変えるものだと考えると、上位から下位へ問い合わせを続ける過程で再帰的に動いて欲しいフルサービスリゾルバに飛んでくるリクエストが再帰問い合わせということになりわかりやすいのかな、と Webエンジニアは思いました。
特徴はどっちにしろ覚えないといけないんですけどね(苦笑)
DNS周りの情報は、後でDNSキャッシュポイズニングについて再帰問い合わせ周りの分も追加してやり直そうと思っているんですが、自分がググった限りJPRSの資料が一番はっきりしています。
ネットワークエンジニアとして(個人運営サイトらしいのですが、これでネットワーク勉強してました系のブログ記事とかでよく紹介されてた) => JPRSの資料(初心者網羅的な情報は多くないですが、専門家集団が出しているので概要であったり、個別トピックがすぱっとしてめっちゃわかりやすい) => @IT(個別の質問とかの記事がめっちゃ助かる) => BINDなど実装用ソフトのノウハウ系の記事、の順で巡回すると混乱が少ないのではないでしょうか。
*1:お約束としてある程度勉強してグーグル力が上がらないと当たれないんですね
DNSの概要と耐障害性、リソースレコードの読み方(BIND式)をまとめました
DNSキャッシュポイズニングについてまとめました
ネットワークの勉強をして色々挫折中。
とりあえず、外部連携するときにFTPとか色々クライアントかませるんだけど、そのトラブルシューティングや、サービスの中でつないでいる各種サーバへの接続設定にもこの辺の知識があると便利そうということだけわかってきた感じ。
ひとまず今日からノートに書いてあるよくわかってないことを1個ずつまとめていきますよっと。
スライドの中で紹介した Source port randomization
、最初に勉強したときの資料にはほとんど出てこなくて、それはもうベンダの方で対応してるから考えなくていいということなのか、とか、再帰的問い合わせ分からんとか壁にぶつかったりしていた。
あと、スライド中の偽造用、偽装用かもしれない...。
Support LibraryのNavigationViewでどこまでできるのか試してみる
久しぶりにサイドメニューのコードいじろうかと思ったのですが、デザインのカスタマイズ性の都合でサードパーティライブラリを使うのが辛く、ここから整理するよりSupport LibraryのNavigationViewを使って書き直した方が楽ではないか、と思ったので、どこまでできるのか試してみます。
内容
- ライブラリのバージョンについて
- 下記のコードを試す上で基本となるレイアウトなどのソースコード
- HeaderViewのレイアウトを変更する
- サイドメニューの項目を変更する場合
- サイドメニューの項目にバッジをつけたい場合
- 下に固定のfooterをつけたい場合
ライブラリのバージョンについて
gradleで指定していたバージョンは下記。
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:design:23.4.0' compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha3' }
下記のコードを試す上で基本となるレイアウトなどのソースコード
Android Studioに用意されているNavigation Drawer Activityのプロジェクトのものをほとんどそのまま利用しています。
一応見たいという方はこちらよりご確認ください。
HeaderViewのレイアウトを変更する
NavigationView.removeHeaderView(View view)
とNavigationView.addHeaderView(View view)
を使えば特に難しいことを考えずサクッと入れ替えられました。
fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // HeaderViewを変更できるテストとしてHeaderViewが1個以上あれば // HeaderViewを消すテスト if(navigationView.getHeaderCount() >= 1) { navigationView.removeHeaderView(navigationView.getHeaderView(0)); } else { navigationView.inflateHeaderView(R.layout.nav_header_main); } } });
サイドメニューの項目を変更する場合
一部の項目の表示/非表示にする場合。
boolean isMenuGroup1Visible = true; FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 一部のmenuの項目の表示/非表示を切り替えるテスト navigationView.getMenu().setGroupVisible(R.id.menu_group_1, !isMenuGroup1Visible); isMenuGroup1Visible = !isMenuGroup1Visible; } });
サイドメニューの項目をがらっと変えたい場合。
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // サイドメニューの項目をmenuリソースから生成し直す場合 navigationView.getMenu().clear(); navigationView.inflateMenu(R.menu.test); } });
<!-- test.xml --> <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery" /> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow" /> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools" /> </menu>
サイドメニューの項目にバッジをつけたい場合
menuリソースのitem要素の属性に、バッジの元となるWidgetのクラスとしてTextViewを指定して...とありましたが、この方法だと、どうも追加した要素の高さをうまく調整できなかったので、MenuItemCompat.setActionView(MenuItem menuItem, int layoutRes)
メソッドで、バッジ用に用意したレイアウトを与えて、そのレイアウトを変更してやる方がいじりやすそうでした。
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery" /> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow" /> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools" /> </menu>
<!-- nav_menu_badge.xml --> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:textColor="@android:color/white" android:id="@+id/badge_text" android:background="@color/colorAccent" android:padding="4dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
MenuItem galleryItem = MenuItemCompat.setActionView(navigationView.getMenu().findItem(R.id.nav_gallery), R.layout.nav_menu_badge); TextView badgeText = (TextView) galleryItem.getActionView().findViewById(R.id.badge_text); badgeText.setText("99"); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // バッジを消したり、内容を変更したりするテスト LinearLayout galleryBadge = (LinearLayout) MenuItemCompat.getActionView(navigationView.getMenu().findItem(R.id.nav_gallery)); TextView badgeText = (TextView) galleryBadge.findViewById(R.id.badge_text); if(badgeText.getText() == "99+") { MenuItemCompat.setActionView(navigationView.getMenu().findItem(R.id.nav_gallery), null); } else { badgeText.setText("99+"); } } });
下に固定のfooterをつけたい場合
NavigationView
の中にandroid:layout_gravity="bottom"
の指定をつけて要素を追加したらよさそうでした。
<!-- activity_main.xml --> <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:openDrawer="start"> <include layout="@layout/app_bar_main" android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer" > <TextView android:text="Footerのテスト" android:gravity="center" android:layout_gravity="bottom" android:background="@color/colorAccent" android:padding="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.design.widget.NavigationView> </android.support.v4.widget.DrawerLayout>
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState(); }
追加したFooterとかぶった部分についてスクロールさせたいときはどうするかについては、対処が若干微妙で、アイコン透明なものを用意した選択不可能なメニューをその部分に追加するのが自分が探した中で綺麗な方の解決方法でした....^^;
Mac OSにmecabをインストールしてnattoを利用してrubyからmecabを叩いてみる
ちょっとある程度の量の短文から単語の出現頻度を抽出する必要があり、さわったのでメモ。
Mac OSにHomebrewでmecabをインストールする
Homebrewを通して入れます*1。
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew install mecab $ brew install mecab-ipadic
mecabをrubyから叩きやすいようにnattoのgemを入れる
割と薄い感じのラッパーっぽいやつです。mecab-rubyでもよさそう。
参考:
$ gem install natto
ユーザー辞書を作る
普通の辞書だけだとインターネット業界の人間にとっては、単語が足りないので*2、はてなキーワードからユーザー辞書を作ってみます。
手順としては、
となります。
参考:
ユーザー辞書の元となるデータの取得
curl -L http://d.hatena.ne.jp/images/keyword/keywordlist_furigana.csv | iconv -f euc-jp -t utf-8 > keywordlist_furigana.csv
ユーザー辞書の元となるデータをCSVにする
表層形,左文脈ID,右文脈ID,コスト,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音
という行が並んだCSVを作っていきます。
例: 工藤,1223,1223,6058,名詞,固有名詞,人名,名,*,*,くどう,クドウ,クドウ
# http://qiita.com/ynakayama/items/388c82cbe14c65827769 の引用に近いですが... require 'csv' CSV.open("custom.csv", 'w') do |csv| original_data.each do |type, filename| next unless File.file? filename open('keywordlist_furigana.csv').each do |title| title.strip! next if title =~ %r(^[+-.$()?*/&%!"'_,]+) next if title =~ /^[-.0-9]+$/ next if title =~ /曖昧さ回避/ next if title =~ /_\(/ next if title =~ /^PJ:/ next if title =~ /の登場人物/ next if title =~ /一覧/ title_length = title.length if title_length > 3 score = [-36000.0, -400 * (title_length ** 1.5)].max.to_i csv << [title, nil, nil, score, '名詞', '一般', '*', '*', '*', '*', title, '*', '*', type] end end end end
CSVをユーザー辞書ファイルとしてコンパイルする
環境によって若干パスが違うので、注意。
/usr/local/Cellar/mecab/0.996/libexec/mecab/mecab-dict-index -d /usr/local/Cellar/mecab-ipadic/2.7.0-20070801/lib/mecab/dic/ipadic -u custom.dic -f utf-8 -t utf-8 custom.csv
ユーザー辞書ファイルをmecabの設定ファイルに追加する
nattoのドキュメント見てもユーザー辞書をその場で登録する感じの説明が見当たらなかったのでmecabの設定ファイルにユーザー辞書のパスを追加します。
# /usr/local/etc/mecabrc に下記の行を追加 userdic = /Users/woshidan/path/to/custom.dic
nattoを使ってmeacbを叩いてみる
require 'natto' irb(main):001:0> require 'natto' => true irb(main):002:0> nm = Natto::MeCab.new => #<Natto::MeCab:0x007fd4431c0948 @model=#<FFI::Pointer address=0x007fd4442c90e0>, @tagger=#<FFI::Pointer address=0x007fd444300e10>, @lattice=#<FFI::Pointer address=0x007fd444300ea0>, @libpath="/usr/local/Cellar/mecab/0.996/lib/libmecab.dylib", @options={}, @dicts=[#<Natto::DictionaryInfo:0x007fd4431f3cf8 @filepath="/usr/local/lib/mecab/dic/ipadic/sys.dic", charset=utf8, type=0>], @version=0.996> irb(main):003:0> nm.parse("はじめてのMecab") => "はじめて\t副詞,一般,*,*,*,*,はじめて,ハジメテ,ハジメテ\nの\t助詞,連体化,*,*,*,*,の,ノ,ノ\nMecab\t名詞,固有名詞,組織,*,*,*,*\nEOS\n" irb(main):004:0> puts nm.parse("はじめてのMecab") はじめて 副詞,一般,*,*,*,*,はじめて,ハジメテ,ハジメテ の 助詞,連体化,*,*,*,*,の,ノ,ノ Mecab 名詞,固有名詞,組織,*,*,*,* EOS => nil
natto, あるいは、mecab-rubyについて、出力形式は他にも良さげなオプションがあった気がしますが、ひとまずこういう感じで。
*1:Yosemite以上にバージョンアップしていたので、自宅のPCのbrewが壊れており http://qiita.com/sue738/items/7ab03ecc9f6fcf37408d http://qiita.com/riocampos/items/b27952faa24524e2919f http://himenaotaro.hatenablog.com/entry/2016/02/14/105251の記事にお世話になりました
Google App Scriptでセルを扱う
諸々の集計業務を担当することになって、コピペを効率化しようと思ってGoogle App Scriptを調べたのでまとめます。
内容
- 特定のセルの値を取得
- 特定のセルに値を貼り付け
- 他のファイルのソースコードを参照するときの手順
- 確認用ダイアローグを出す
- シートを開いたときに行う処理
- 参考
特定のセルの値を取得
// 単一の値を取得 SpreadsheetApp.getActive().getSheetByName("SHEET_NAME").getRange("A1").getValue(); // 現在アクティブなシートを取得する場合 SpreadsheetApp.getActiveSpreadsheet()).getRange("A1").getValue(); // 特定の範囲の中の値を取得する場合 // 2次元配列が帰ってきます SpreadsheetApp.getActive().getSheetByName("SHEET_NAME").getRange("A1:B6").getValues();
特定のセルに値を貼り付け
// 単一のセルに貼り付けというのはなく、範囲から範囲への貼り付けとなる var rangeToCopy = sheet.getRange('A:A'); var targetToCopy = sheet.getRange('B1'); // 貼り付け範囲か、一番左上のセルを指定するようにしておく rangeToCopy.copyTo(targetToCopy); // 形式のみ, 値のみのオプションについて rangeToCopy.copyTo(targetToCopy, {formatOnly:true}); // 形式のみ rangeToCopy.copyTo(targetToCopy, {contentsOnly:true}); // 値のみ // 2次元配列を特定の範囲へ貼り付け var copyValues = [[1, 2], [3, 4]]; SpreadsheetApp.getActive().getSheetByName("SHEET_NAME").getRange("A1:B2").setValues(copyValues);
他のファイルのソースコードを参照するときの手順
- 新しいプロジェクトを作成して分割したいソースコードを貼る
- 1のプロジェクトに対して、
ファイル > 版で管理
から、他のプロジェクトに公開するバージョンのコメントを入れて保存 - 2のプロジェクトのソースコードを参照したいプロジェクトを開いて、
リソース > ライブラリ
を選択 - 3で開いたメニューの下の方に、2のプロジェクトのURLの一部
https://script.google.com/macros/d/SomeLooooongRandomString/edit?ui...
のSomeLooooongRandomString
の部分を入れる - 入力した文字列が正しければ、2のプロジェクト名が3のメニューに現れるので、2のプロジェクトを利用する側で使うバージョンと、2のプロジェクトの関数などの前につく識別子を入力して、「保存」を押す
- 2のプロジェクトを利用する側で、5で決めた識別子を頭につけて2のプロジェクト内の関数を利用する
確認用ダイアローグを出す
// メッセージだけでる Browser.msgBox("メッセージが出ます"); // OK/キャンセルのボタンがついたダイアローグが出る Browser.msgBox("これからシートを編集しますか?", Browser.Buttons.OK_CANCEL); // 選択されたボタンを取得 var selections = Browser.msgBox("これからシートを編集しますか?", Browser.Buttons.OK_CANCEL); // キャンセルボタンをクリックした場合は"cancel" Browser.msgBox(selections);
シートを開いたときに行う処理
// シートを開いたときにダイアローグを出す function onOpen(){ Browser.msgBox("これからシートを編集しますか?", Browser.Buttons.OK_CANCEL); } // シートを開いたときに上部にメニューを追加する function onOpen() { var sheet = SpreadsheetApp.getActiveSpreadsheet(); var entries = [ { name : "シートの上部にに追加するメニュー内の項目の名前", functionName : "その項目を選択したとき起動する関数" } ]; sheet.addMenu("シートの上部に追加するメニューの名前", entries); }
参考
- http://itinfo.popotoo.com/gas/39/
- http://www.bmoo.net/archives/2012/07/314383.html
- http://www.bmoo.net/archives/2012/03/313107.html
- http://qiita.com/moonstruckdrops@github/items/d791bc7f0b7a2c2e6b5d
- http://www.bmoo.net/archives/2012/03/312958.html
- http://qiita.com/shibukawa/items/8fee715232e12f183698
結局なのですが、普通にGoogle Spread Sheetの関数を使ってCSVインポートからのコピペ前の整形作業用の単純なシートを何枚か作ったらそれだけで大幅に時間が短縮されてしまい、Google App Scriptの動作が遅かったため、2日程度で0からほとんど動くところまで書いたのに導入までできなかったのが残念です...。
暇なときにもう少し手直ししてリベンジしたい...。
Spinnerのレイアウトをコードで変更する
スタイルを利用した指定がうまく動かなかったり見つけるまでにちょっと時間がかかったりしたので、まあ適当にメモ。
android:id="@android:id/text1"
と@android:id/text1
がidに指定されたTextViewだけのレイアウトリソースを用意- Spinnerの要素をセットする
ArrayAdapter
の引数に渡す - ドロップダウン用のレイアウトは、
ArrayAdapter.setDropDownViewResource
メソッドの引数に渡す
Adapterに手動で要素を追加しているのは、利用する時にスピナーの要素が動的に変わっていたからです。
また、Spinnerの要素の先頭に画像などをセットしたい場合は、BaseAdapter
を継承してgetView
メソッドをオーバーライドして用います。
setContentView(R.layout.activity_main); ArrayAdapter<String> adapter = new ArrayAdapter(this, R.layout.item_in_list); adapter.add("One"); adapter.add("Two"); adapter.add("Three"); adapter.setDropDownViewResource(R.layout.item_in_drop_down_list); AppCompatSpinner spinner = (AppCompatSpinner) findViewById(R.id.imageFolderNameSpinner); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { } @Override public void onNothingSelected(AdapterView<?> parent) { } });
<!-- res/layout/activity_main.xml --> <?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.example.woshidan.myapplication.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"> <android.support.v7.widget.AppCompatSpinner android:id="@+id/imageFolderNameSpinner" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.v7.widget.Toolbar> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" android:src="@android:drawable/ic_dialog_email" /> </android.support.design.widget.CoordinatorLayout>
<!-- item_in_list.xml --> <?xml version="1.0" encoding="utf-8"?> <TextView android:id="@android:id/text1" android:textSize="18dp" android:padding="8dp" android:textColor="#0f0" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="marquee" android:background="#fff" android:textAlignment="inherit" xmlns:android="http://schemas.android.com/apk/res/android" />
<!-- item_in_drop_down_list.xml --> <?xml version="1.0" encoding="utf-8"?> <TextView android:id="@android:id/text1" android:textSize="18dp" android:padding="8dp" android:textColor="#f00" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="marquee" android:textAlignment="inherit" xmlns:android="http://schemas.android.com/apk/res/android" />
スタイルで指定できるはずなんだけどなぁ。