VirtualBoxを使っていてドメイン名の名前解決ができない場合の対処法です。
公式サイトのマニュアルに書いてあります。
Enabling DNS proxy in NAT mode
VBoxManage modifyvm "VM name" --natdnsproxy1 on
VirtualBoxを使っていてドメイン名の名前解決ができない場合の対処法です。
公式サイトのマニュアルに書いてあります。
Enabling DNS proxy in NAT mode
VBoxManage modifyvm "VM name" --natdnsproxy1 on
iOS6からinput type=fileでファイルを選択できるようになりました。
実際に使用してみて、PC(Chrome)での動作と異なる点として以下がありました。
なお、選択したファイルは第5世代iPod touchのスクリーンショット(.pngファイル)です。
1.fileオブジェクトのnameプロパティに本来のファイル名ではなくimage.jpgという名称がセットされている。
2.typeプロパティにimage/jpegがセットされている。(image/pngを期待していたのに。)
3.sizeプロパティに本来のサイズより少ない値がセットされている。
4.lastModifiedDateプロパティに現在時刻がセットされている。(ファイルの更新日を期待していたのに。)
上記の内容から、ローカルのファイルを選択した時点で画像に何らかの変換がかかっていることが分かります。そのまま読めば、pngからjpgへ変換していて、変換によってlastModifiedDateに現在時刻が設定されるのだと思います。
これによって困るのは次のような場合です。
・選択ファイルの名称や更新日を利用して何らかの処理をしようとしていた。
・厳密な色情報の一致が必要な処理。(画像の変換によって色情報が変化するため。)
ユーザーエージェントで判断するなどして異常な動作にならないようにするとよいと思います。
また、次のような情報を公開している方がいらっしゃいました。
iOS6でメガピクセル画像をCanvasに描画するとおかしくなってしまう件と、その対処
http://d.hatena.ne.jp/shinichitomita/20120927/1348726674
今回、選択したファイルの更新日が欲しかったのですが諦めました。Canvasへの描画がおかしくなる点については、上記サイトで公開されているライブラリを利用させて頂きました。
仮想マシンを起動しようとして、
$ vagrant up
を実行すると、最初の実行でなければ、以下のようなメッセージが出て最初に作った仮想マシンが起動しますが、
[default] VM already created. Booting if it's not already running…
何かの拍子でVagrantと既存の仮想マシンとの紐付けが削除されて、vagrant up
実行時に新たな仮想マシンを作成してしまうことがあります。
次のようなメッセージが出て新しい仮想マシンを作ってしまいます。
[default] Importing base box 'CentOS 6.3'…
既存の仮想マシンに接続したいので、これでは困ります。
ところで、仮想マシンの実体は、次のディレクトリにありました。
~/VirtualBox\ VMs/
既存の仮想マシンに加えて、意図せずに新たに作成されてしまった仮想マシンのファイルが見えます。
$ ls ~/VirtualBox\ VMs/ Hadoop_1359271283 Hadoop_1360995446
Vagrantは、仮想マシンとの紐付けをVagrantfile
と同じディレクトリに存在する、.vagrant
ファイルで管理しています。
まだ一度も起動していないなど、仮想マシンとの紐付けが無い場合はこのファイルがありません。
既に仮想マシンを作っているにも関わらず、新しい仮想マシンが作られてしまう場合は、このファイルが存在しない可能性があります。
そのため、.vagrant
を手動で作成し、紐付けを行います。
ファイルの中身はJSONになっており、紐付ける仮想マシンのUUIDを記述します。
UUIDは以下のコマンドで参照します。
$ VBoxManage list vms "Hadoop_1359271283" {931864ed-55a1-4986-9e8d-ad63eb7ae597} "Hadoop_1360995446" {6489a2af-eb76-4b89-a152-fc21077b761d}
二つ仮想マシンが存在し、最初の方を起動したいので、IDを以下のように.vagrant
に記述します。
{"active":{"default":"931864ed-55a1-4986-9e8d-ad63eb7ae597"}}
これで、vagrant up
で.vagrant
で記述した仮想マシンが起動するようになります。
なお、JSON中の“default”
は、デフォルトの仮想マシンを使う場合です。multi-VMの場合は設定した仮想マシンの名前を指定してください。
{ "active":{ "web":"931864ed-55a1-4986-9e8d-ad63eb7ae597", "app":"6489a2af-eb76-4b89-a152-fc21077b761d" } }
Chef Soloの本、入門Chef Solo - Infrastructure as Codeを読みました。
本書を読んで思った事や得られたことを箇条書きで書きました。
・実体験に基づいた内容
筆者がなぜChefを導入しようとしたのか?導入前はどうしていて、何が問題だったかが書いてあります。これが本書に説得力を持たせていると思います。
・サーバーの状態をあるべき状態へ収束させる
本書で何度も出てくる言葉です。
この言葉でChefのイメージが読む前よりもクリアになりました。読む前の私の中にあったこれの代わりの言葉は、「インフラ構築の自動化」でした。冪等性を保証するからこその言葉だと思います。私の書いたレシピは冪等性がないので何となく気持ち悪さを感じていましたが、Chefの思想から外れていることが明確に分かり、ちゃんとやろうと思いました。
・レシピを育てる
GitHubなどで公開されているレシピは何だか長々と書いてあって、自分が書いたのは数行しかないけど、本当にこれでいいんだろうか?というのが最初にレシピを書いたときの感想でした。筆者のレシピを育てていった過程が書いてあって、安心できました。
・自分で書くかサードパーティ製レシピを使うか
前から思っていたことですが、今までは深く考えずに勉強の意味で自分で書いていました。これについて筆者の意見が書いてあって参考になりました。
・Chef Serverについての誤解
Chef Serverは多数のクライアントにChefを実行するためのものぐらいにしか思っていませんでした。
なので、chef-solo + capistranoで十分だと思っていましたが、本書で紹介されているChef Serverの機能はとても魅力的で厨二心をくすぐられました。管理するサーバーが数台であっても(個人的な興味で)導入してみたいと感じたほどです。
・知らなかったプラグイン
便利なプラグインが紹介されていました。今までレシピのテストをする時に面倒に感じていたので役に立ちそうです。
内容とは関係ないですが、Kindle初めてだったのですが、電車でiPod touchで読んで、家でタブレットで読んでいて、現在読んでいる位置が同期されるのが便利でした。
内容は満足です。
プログラミング用のフォント、Rictyをインストールしてターミナルのフォントに設定します。
ホスト:OS X Mountain Lion 10.8.2
fontforgeをインストールする
sudo port install fontforge
Inconsolataをインストールする
http://levien.com/type/myfonts/inconsolata.htmlから、OpenType fileのリンクをクリックして、ダウンロードします。ダウンロードしたファイルをダブルクリックして、「フォントをインストール」をクリックします。
Migu 1Mをインストールする
http://mix-mplus-ipa.sourceforge.jp/ の、Miguダウンロードのページから、Migu 1Mをダウンロードします。圧縮ファイルを解凍して、出てきたttfファイルを全てダブルクリックして、「フォントをインストール」をクリックします。
Rictyをインストールする
git clone https://github.com/yascentur/Ricty.git
cd Ricty
sh ricty_generator.sh auto
ターミナルのメニューの、環境設定 > テキストタブ > フォントで、Ricty Regularを選択します。
フォントサイズは15ptにしました。
#4の続きです。
hello worldの削除と、文字の入れ替え(world helloと表示される)の処理を追加します。
main.js
(function($){ Backbone.sync = function(method, model, success, error){ success(); } var Item = Backbone.Model.extend({ defaults: { part1: 'hello', part2: 'world' } }); var List = Backbone.Collection.extend({ model: Item }); var ItemView = Backbone.View.extend({ tagName: 'li', events: { 'click span.swap': 'swap', 'click span.delete': 'remove' }, initialize: function(){ _.bindAll(this, 'render', 'unrender', 'swap', 'remove'); this.model.bind('change', this.render); this.model.bind('remove', this.unrender); }, render: function(){ $(this.el).html('<span style="color:black;">' + this.model.get('part1') + ' ' + this.model.get('part2') + '</span> <span class="swap" style="font-family:sans-serif; color:blue; cursor:pointer;">[swap]</span><span class="delete" style="cursor:pointer; color:red; font-familiy:sans-serif;">[delete]</span>'); return this; }, unrender: function(){ $(this.el).remove(); }, swap: function(){ var swapped = { part1: this.model.get('part2'), part2: this.model.get('part1') } this.model.set(swapped); }, remove: function(){ this.model.destroy(); } }); var ListView = Backbone.View.extend({ el: $('body'), events: { 'click button#add': 'addItem' }, initialize: function(){ _.bindAll(this, 'render', 'addItem', 'appendItem'); this.collection = new List(); this.collection.bind('add', this.appendItem); this.counter = 0; this.render(); }, render: function(){ var self = this; $(this.el).append("<button id='add'>Add list item</button>") $(this.el).append("<ul></ul>"); _(this.collection.models).each(function(item){ self.appendItem(item); }, this); }, addItem: function(){ this.counter++; var item = new Item(); item.set({ part2: item.get('part2') + this.counter }); this.collection.add(item); }, appendItem: function(item){ var itemView = new ItemView({ model: item }); $('ul', this.el).append(itemView.render().el); } }); var listView = new ListView(); })(jQuery);
3~5行目
Backbone.sync = function(method, model, success, error){
success();
}
this.model.destroy();
でBackbone.syncが呼ばれます。
21~24行目
events: {
‘click span.swap’: ‘swap’,
‘click span.delete’: ‘remove’
},
29~30行目
this.model.bind(‘change’, this.render);
this.model.bind(‘remove’, this.unrender);
33~36行目
render: function(){
$(this.el).html(‘<span style=”color:black;”>’ + this.model.get(‘part1’) + ‘ ‘ + this.model.get(‘part2’) + ‘</span> <span class=”swap” style=”font-family:sans-serif; color:blue; cursor:pointer;”>[swap]</span><span class=”delete” style=”cursor:pointer; color:red; font-familiy:sans-serif;”>[delete]</span>’);
return this;
},
38~40行目
unrender: function(){
$(this.el).remove();
},
42~48行目
swap: function(){
var swapped = {
part1: this.model.get(‘part2’),
part2: this.model.get(‘part1’)
}
this.model.set(swapped);
},
50~52行目
remove: function(){
this.model.destroy();
}
今回の変更はItemに関するものなので、ListViewの変更はありません。
以上でチュートリアルは終了です。
#3の続きです。
ItemModelの専用のビューを導入します。
main.js
(function($){
var Item = Backbone.Model.extend({
defaults: {
part1: 'hello',
part2: 'world'
}
});
var List = Backbone.Collection.extend({
model: Item
});
var ItemView = Backbone.View.extend({
tagName: 'li',
initialize: function(){
_.bindAll(this, 'render');
},
render: function(){
$(this.el).html('' + this.model.get('part1') + ' ' + this.model.get('part2') + '');
return this;
}
});
var ListView = Backbone.View.extend({
el: $('body'),
events: {
'click button#add': 'addItem'
},
initialize: function(){
_.bindAll(this, 'render', 'addItem', 'appendItem');
this.collection = new List();
this.collection.bind('add', this.appendItem);
this.counter = 0;
this.render();
},
render: function(){
var self = this;
$(this.el).append("<button id='add'>Add list item</button>")
$(this.el).append("<ul></ul>");
_(this.collection.models).each(function(item){
self.appendItem(item);
}, this);
},
addItem: function(){
this.counter++;
var item = new Item();
item.set({
part2: item.get('part2') + this.counter
});
this.collection.add(item);
},
appendItem: function(item){
var itemView = new ItemView({
model: item
});
$('ul', this.el).append(itemView.render().el);
}
});
var listView = new ListView();
})(jQuery);
14~23行目
var ItemView = Backbone.View.extend({
tagName: ‘li’,
initialize: function(){
_.bindAll(this, ‘render’);
},
render: function(){
$(this.el).html(‘‘+this.model.get(‘part1’)+’ ‘+this.model.get(‘part2’)+’‘);
return this;
}
});
return this;
とすることで、render()メソッドの戻り値からelプロパティを参照できるようにしています。
56~61行目
appendItem: function(item){
var itemView = new ItemView({
model: item
});
$(‘ul’, this.el).append(itemView.render().el);
}
ItemView.render().el
までではelプロパティは指定されていないため、描画位置は決まっていません。$(‘ul’, this.el).append()
の時点で位置が決定し描画されます。
次のチュートリアルではさらにイベントを追加し、モデルの変更がビューに反映される様子を見ます。
#2の続きです。
モデルとモデルのコレクションを導入します。コレクションへのモデルの追加をビューへ反映させます。
main.js
(function($){ var Item = Backbone.Model.extend({ defaults: { part1: 'hello', part2: 'world' } }); var List = Backbone.Collection.extend({ model: Item }); var ListView = Backbone.View.extend({ el: $('body'), events: { 'click button#add': 'addItem' }, initialize: function(){ _.bindAll(this, 'render', 'addItem', 'appendItem'); this.collection = new List(); this.collection.bind('add', this.appendItem); this.counter = 0; this.render(); }, render: function(){ var self = this; $(this.el).append("") $(this.el).append("
3~8行目
var Item = Backbone.Model.extend({
defaults: {
part1: ‘hello’,
part2: ‘world’
}
});
10~12行目
var List = Backbone.Collection.extend({
model: Item
});
23~24行目
this.collection = new List();
this.collection.bind(‘add’, this.appendItem);
32~38行目
var self = this;
$(this.el).append(“<button id=’add’>Add list item</button>”)
$(this.el).append(“<ul></ul>”);
_(this.collection.models).each(function(item){
self.appendItem(item);
}, this);
40~47行目
addItem: function(){
this.counter++;
var item = new Item();
item.set({
part2: item.get(‘part2’) + this.counter
});
this.collection.add(item);
},
49~51行目
appendItem: function(item){
$(‘ul’, this.el).append(“<li>” + item.get(‘part1’) + “ “ + item.get(‘part2’) + “</li>”);
}
次のチュートリアルでは、Itemモデルの専用のビューを導入します。
#1の続きです。
ボタンを押すとhello worldが増えていきます。
main.js
(function($){ var ListView = Backbone.View.extend({ el: $('body'), events: { 'click button#add': 'addItem' }, initialize: function(){ _.bindAll(this, 'render', 'addItem'); this.counter = 0; this.render(); }, render: function(){ $(this.el).append("") $(this.el).append("
6~8行目
events: {
‘click button#add’: ‘addItem’
},
17行目
$(this.el).append(“<button id=’add’>Add list item</button>”)
21~24行目
addItem: function(){
this.counter++;
$(‘ul’, this.el).append(“<li>hello world”+this.counter+”</li>”);
}
$(‘ul’, this.el)
はJQueryのセレクタで、this.elを起点にul要素を探します。
次のチュートリアルでは、モデルを使います。
Backbone.jsのチュートリアルをやりました。#1〜5まであります。
index.htmlは共通で、main.jsを変更していきます。
下の2つのファイルを作成してindex.htmlを開いてください。Backbone.jsによってhello worldが表示されます。
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>hello-backbonejs</title> </head> <body> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> <script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script> <script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.6/underscore-min.js"></script> <script src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script> <script src="main.js" type="text/javascript"></script> </body> </html>
main.js
(function($){ var ListView = Backbone.View.extend({ el: $('body'), initialize: function(){ _.bindAll(this, 'render'); this.render(); }, render: function(){ $(this.el).append("
3行目
var ListView = Backbone.View.extend({
Backbone.Viewはビューです。モデルの表示を表現しますが、今回の例では固定文字を出力するのみです。extendメソッドで独自のビューを定義します。
4行目
el: $('body'),
elは描画位置を指定するViewオブジェクトのプロパティです。ここではbody要素を指定しています。
6行目
initialize: function(){
initializeはインスタンス化された時に自動的に呼ばれるメソッドです。
7行目
_.bindAll(this, 'render');
bindAllはUnderscore.jsのメソッドです。renderメソッドをthis(この場合はView)に束縛します。Backbone 0.5.2以降はbindAllを使用する必要はなくなったとのこと。
(参考2)http://stackoverflow.com/questions/6079055/why-do-bindall-in-backbone-js-views
11〜13行目
render: function(){ $(this.el).append("<ul><li>hello world</li></ul>"); }
renderメソッドの定義です。body要素にhello worldを追加します。
16行目
var listView = new ListView();
定義したListViewをインスタンス化します。initializeがコールされhello worldが描画されます。
次のチュートリアルでは、DOMイベントのバインドを行います。