OpsWorksでのRailsアプリのデプロイ手順(1)
AWS Opsworks の使い方を説明します。
まずは静的なサイトを構築します。
動的なサイトについてはこちらを参照してください。
OpsWorksでのRailsアプリのデプロイ手順(2) http://d.hatena.ne.jp/seika_m/20150913
AWS
https://aws.amazon.com/jp/
公式ユーザーガイド
ステップ 2: 簡単なアプリケーションサーバースタックを作成する
http://docs.aws.amazon.com/ja_jp/opsworks/latest/userguide/gettingstarted-simple.html
Add Stack ボタンを押下します
(Stack は箱のようなもので、Stack の中にレイヤーとインスタンスを作ります)。
Nameに適当な名前を入れます
他はそのままの値でAdd Stack ボタンを押下します。
Layer type に Rails App Server を選択
Rails stack に nginx and Unicorn を選択
他はそのままの値でAdd Layer ボタンを押下します。
そのままの値でAdd Instance ボタンを押下します。
start を選択します。
メニューのStackの名前を選択してStackの画面に戻り、
(インスタンスの起動するまで10分ぐらいかかります。他の画面に移動しても大丈夫です。)
Name に適当な名前を入れます
Repository URL に
https://github.com/awslabs/opsworks-demo-rails-photo-share-app.git
を入力します。
値はそのままで
Deploy ボタンを押下します。
(Deploy 完了までは数分かかります。)
メニューのStackの名前を選択してStackの画面に戻り、
Public DNS を選択します。
A way to fix a problem "pydelicious.get_popular" doesn't work.
When I tried to work the following sample code in "Programming Collective Intelligence", an error occurred.
import pydelicious pydelicious.get_popular(tag='programming')
The error message was
[{'count': '', 'extended': '', 'hash': '', 'description': u'something went wrong', 'tags': '', 'href': '', 'user': '', 'dt': ''}]
I fixed 2 line of "pydelicious.py".
DLCS_RSS = 'http://del.icio.us/rss/'
to
DLCS_RSS = 'http://feeds.delicious.com/v2/rss/'
def get_popular(tag = ""): return getrss(tag = tag, popular = 1)
to
def get_popular(tag = ""): return getrss(tag = tag, popular = 0)
The problem was solved.
references:
https://delicious.com/rss
http://clintlalonde.net/2012/08/24/getting-a-rss-feed-for-a-delicious-tag/
download site of pydelicious.py
http://code.google.com/p/pydelicious/downloads/list
were, would, past simple...What comes after "I wish".
Introduction.
You can say
I wish I were a bird, I would fly to you.
But you can't say
I wish I would be a bird, I would fly to you.
be (am, are, is) don't take "would". simply uses "were".
normal verb takes "would". but not always.
For example.
incorrect: I wish I would have wings.
correct: I wish I had wings.
incorrect: I wish I would know the sky.
correct: I wish I knew the sky.
on the one hand.
correct: I wish I would fly to you.
what is different about?
This is different about "something to happen" and "something to be".
"something to be" means the state verb. have, know, like, love, believe...
"something to be" means the action verb. play, fly, run, swim... most of verb other than state verb.
conclusion
What comes after "I wish".
be (am, are, is) : were
state verb: past simple form of the verb
action verb: "would" + infinitive form of the verb
I wish I were a bird! I wish の後にくるもの
英語の本を読んでてI wish I were a bird.ってI wish I had been a bird.が正しいのではと思ったが、それだと過去の意味になってしまうらしい。
構文062「仮定法構文」その1「鳥だったらシリーズ」
I wish I were a bird, I would fly to you. ってなるのがまた。
I wish I would be a bird, I would fly to you. だと大変解りやすいのですが・・。
なお「翼があったら」は
× I wish I would have wings.
○ I wish I had wings.
同じく「空を知っていたら」は
× I wish I would know the sky.
○ I wish I knew the sky.
一方「飛んでいけたら」は
○ I wish I would fly to you.
状態動詞と動作動詞の違いらしい。
うっ・・はるか過去の記憶がよみがえる(英語の授業)・・。
つまりI wish の後に続くのは
be動詞は were or was、
状態動詞は動詞の過去形、
動作動詞はwould + 動詞の原型。
Gitの使い方メモ
すぐ忘れるのでメモする。
最初の登録
自分のPC
cd git 管理対象のフォルダ
git init
git add .
git commit -a -m "コメント"
git remote add origin 先ほど記録したURL
git push -u origin master
更新
add .
git commit -a -m "コメント"
git push -u origin master
ブランチ登録
(ブランチ登録)
git branch ブランチ名
(ブランチ切り替え)
git checkout ブランチ名
(リモートリポジトリにブランチ登録)
git push origin ブランチ名
(元のブランチに戻す)
git checkout master
2つ目のAndroidアプリを作りました
1つの端末で2人プレイができる簡単な連打ゲームです。
とにかく早くゲームを作りたかった・・。
アプリ名:ButtonRush Versus
Amazon Android アプリストア に登録しました。
http://www.amazon.co.jp/Shimamura-ButtonRush-Versus/dp/B014W0EQK8/
アイコンはClip Studioで作成しました。
このアプリのポイントはタイマー処理です。公式サイトを参考にしました。
http://developer.android.com/intl/ja/reference/android/os/CountDownTimer.html
(タイマー処理を公式サイトから抜粋)
new CountDownTimer(30000, 1000) { public void onTick(long millisUntilFinished) { mTextField.setText("seconds remaining: " + millisUntilFinished / 1000); } public void onFinish() { mTextField.setText("done!"); } }.start();
主なソースコードを下に載せます。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.github.fumio_shimamura.dice01" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.AppCompat.NoActionBar" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
MainActivity.java
package com.github.fumio_shimamura.dice01; import android.os.CountDownTimer; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AnalogClock; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { // プログレスバーの値 private int bar1value; private int bar2value; // スタートボタンの有効/無効を管理する private boolean onStart; // ゲーム中であることのフラグ。ゲームボタンの有効/無効を管理する。 private boolean onGame; public static final long TIME_TO_START = 2000; public static final long TIME_TO_FINISH = 5000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void changeBar1(View view){ if(!onGame){ return; } bar1value += 2; SeekBar bar = (SeekBar)findViewById(R.id.seekBar1); bar.setProgress(bar1value); //String str = String.valueOf(bar1value); //Toast.makeText(this, str, Toast.LENGTH_LONG).show(); } public void changeBar2(View view){ if(!onGame){ return; } bar2value += 2; SeekBar bar = (SeekBar)findViewById(R.id.seekBar2); bar.setProgress(bar2value); } // スタートボタン押下時の処理 public void startGame(View view){ if (onStart) { return; } SeekBar bar1 = (SeekBar)findViewById(R.id.seekBar1); SeekBar bar2 = (SeekBar)findViewById(R.id.seekBar2); bar1value = 0; bar2value = 0; bar1.setProgress(bar1value); bar2.setProgress(bar2value); // カウントダウン開始 new CountDownTimer(TIME_TO_START, 1000) { TextView tv = (TextView)findViewById(R.id.textView); public void onTick(long millisUntilFinished) { tv.setText("Ready..."); } public void onFinish() { tv.setText("Go!"); // ゲームスタートする playGame(); } }.start(); onStart = true; } // ゲーム中の処理 public void playGame(){ if(onGame){ return; } // カウントダウン開始 new CountDownTimer(TIME_TO_FINISH, 1000) { int count = 0; TextView tv = (TextView)findViewById(R.id.textView); public void onTick(long millisUntilFinished) { count += 1; if (count == 2) { tv.setText(" "); } else if (count > 2) { tv.setText(String.valueOf(millisUntilFinished / 1000)); } } public void onFinish() { if (bar1value > bar2value) { tv.setText("1P Win!"); }else if(bar2value > bar1value) { tv.setText("2P Win!"); }else { tv.setText("Draw!"); } onGame = false; onStart = false; } }.start(); onGame = true; } }
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity" android:background="@android:color/background_light"> <TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textView" android:textSize="25sp" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:textColor="@android:color/black" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_push" android:id="@+id/button1" android:layout_alignParentBottom="true" android:onClick="changeBar1" android:layout_alignParentStart="true" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_alignParentLeft="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_push" android:id="@+id/button2" android:layout_alignParentTop="true" android:onClick="changeBar2" android:layout_alignParentStart="true" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_alignParentLeft="true" /> <SeekBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/seekBar1" android:layout_alignParentStart="true" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_alignParentLeft="true" android:layout_below="@+id/textView" android:layout_marginTop="50dp" /> <SeekBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/seekBar2" android:layout_alignParentStart="true" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_alignParentLeft="true" android:layout_above="@+id/textView" android:layout_marginBottom="50dp" /> <Button style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_start" android:id="@+id/button_start" android:shape="oval" android:layout_centerVertical="true" android:layout_alignParentStart="true" android:layout_alignParentLeft="true" android:onClick="startGame"/> </RelativeLayout>
string.xml
<resources> <string name="app_name">ButtonRush Versus</string> <string name="hello_world">Press Start</string> <string name="action_settings">Settings</string> <string name="button_push"></string> <string name="button_start">Start</string> </resources>
初めてのAndroidアプリを作りました
以下サイトを参考にして、登録日時を表示する機能を加えたメモアプリです。
アプリ名:ListMemo
Androidアプリ開発入門
http://androidguide.nomaki.jp/html/memo_app/memo_app_main.html
Google Play に登録しました。
https://play.google.com/store/apps/details?id=com.github.fumio_shimamura.listmemo
なおアイコンは、はてなココのものを使用しました。
http://d.hatena.ne.jp/tikeda/20101215/1292412046
主なソースコードを下に載せます。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.github.fumio_shimamura.listmemo" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".EditActivity" android:label="@string/edit_activity_title" > </activity> </application> </manifest>
MainActivity.java
package com.github.fumio_shimamura.listmemo; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity { // ListView 用アダプタ SimpleAdapter mAdapter = null; // ListView に設定するデータ List<Map<String, String>> mList = null; // 日時+SPACE(YYYY/MM/DD HH:MM )の文字数は19 public static final int DATE_LENGTH = 19; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ListView 用アダプタのリストを生成 mList = new ArrayList<Map<String, String>>(); // ListView 用アダプタを生成 mAdapter = new SimpleAdapter( this, mList, android.R.layout.simple_list_item_2, new String [] {"title", "content"}, new int[] {android.R.id.text1, android.R.id.text2} ); // ListView にアダプターをセット ListView list = (ListView)findViewById(R.id.listView); list.setAdapter(mAdapter); // ListView のアイテム選択イベント list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick( AdapterView<?> parent, View view, int pos, long id) { // 日時+タイトルから日時を削除する String title_tmp = mList.get(pos).get("title"); String title = removeDateFromTitle(title_tmp); // 編集画面に渡すデータをセットし、表示 Intent intent = new Intent(MainActivity.this, EditActivity.class); intent.putExtra("NAME", mList.get(pos).get("filename")); //intent.putExtra("TITLE", mList.get(pos).get("title")); intent.putExtra("TITLE", title); intent.putExtra("CONTENT", mList.get(pos).get("content")); startActivity(intent); } }); // ListView をコンテキストメニューに登録 registerForContextMenu(list); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement // menu_main.xmlでidを定義している if (id == R.id.action_add) { // 編集画面への遷移処理 Intent intent = new Intent(MainActivity.this, EditActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); } @Override protected void onResume() { super.onResume(); // ListView 用アダプタのデータをクリア mList.clear(); // ここでファイルを読み込み、リスト表示処理を行う // アプリの保存フォルダ内のファイル一覧を取得 String savePath = this.getFilesDir().getPath().toString(); File[] files = new File(savePath).listFiles(); // ファイル名の降順でソート Arrays.sort(files, Collections.reverseOrder()); // テキストファイル(*.txt)を取得し、ListView用アダプタのリストにセット for (int i=0; i<files.length; i++) { String fileName = files[i].getName(); if (files[i].isFile() && fileName.endsWith(".txt")) { String title_tmp; String title = null; String content = null; // ファイルを読み込み try { // ファイルオープン InputStream in = this.openFileInput(fileName); BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); char[] buf = new char[(int)files[i].length()]; // タイトル(1行目)を読み込み //title = reader.readLine(); title_tmp = reader.readLine(); // ファイル名とタイトルを連結して日時+タイトルを作成する title = makeDateAndTitle(fileName,title_tmp); // 内容(2行目以降)を読み込み int num = reader.read(buf); if (num > 0) { content = new String(buf, 0, num); } // ファイルクローズ reader.close(); in.close(); } catch (Exception e) { Toast.makeText(this, "File read error!", Toast.LENGTH_LONG).show(); } // ListView用のアダプタにデータをセット Map<String, String> map = new HashMap<String, String>(); map.put("filename", fileName); map.put("title", title); map.put("content", content); mList.add(map); } } // ListView のデータ変更を表示に反映 mAdapter.notifyDataSetChanged(); } // ファイル名とタイトルを連結して日時+タイトルを作成する private String makeDateAndTitle(String filename, String title){ // ファイル名から日付を切り出す String file_date = filename.substring(0,8); // ファイル名から時刻を切り出す String file_time = filename.substring(9,13); // YYYY/MM/DD HH:MM + タイトルを返す return file_date.substring(0,4) + "-" + file_date.substring(4,6) + "-" + file_date.substring(6,8) + " " + file_time.substring(0,2) + ":" + file_time.substring(2,4) + " " + title; } // 日時+タイトルから日時を削除する private String removeDateFromTitle(String title){ // 先頭19文字は日時+SPACE(YYYY/MM/DD HH:MM )のため削除する。文字数は19。 return title.substring(DATE_LENGTH); } // コンテキストメニュー作成処理 @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) { super.onCreateContextMenu(menu, view, info); getMenuInflater().inflate(R.menu.main_context, menu); } // コンテキストメニュー選択処理 @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); switch(item.getItemId()) { case R.id.context_del: // [削除] 選択時の処理 // ファイル削除 if (this.deleteFile(mList.get(info.position).get("filename"))) { Toast.makeText(this, R.string.msg_del, Toast.LENGTH_SHORT).show(); } // リストからアイテム処理 mList.remove(info.position); // ListView のデータ変更を表示に反映 mAdapter.notifyDataSetChanged(); break; default: break; } return false; } }
EditActivity.java
package com.github.fumio_shimamura.listmemo; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; import android.widget.Toast; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; /** * Created by shima on 2015/09/02. */ public class EditActivity extends AppCompatActivity { // 保存ファイル名 String mFileName = ""; // 保存なしフラグ boolean mNotSave = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_edit); // タイトルと内容入力用の EditText を取得 EditText eTxtTitle = (EditText)findViewById(R.id.eTxtTitle); EditText eTxtContent = (EditText)findViewById(R.id.eTxtContent); // メイン画面からの情報受け取り、EditTextに設定 // (情報がない場合(新規作成の場合)は、設定しない) Intent intent = getIntent(); String name = intent.getStringExtra("NAME"); if (name != null) { mFileName = name; eTxtTitle.setText(intent.getStringExtra("TITLE")); eTxtContent.setText(intent.getStringExtra("CONTENT")); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_edit, menu); return true; } @Override protected void onPause() { super.onPause(); // ここでファイル保存処理を行う // [削除] で画面を閉じるときは、保存しない if (mNotSave) { return; } // タイトル、内容を取得 EditText eTxtTitle = (EditText)findViewById(R.id.eTxtTitle); EditText eTxtContent = (EditText)findViewById(R.id.eTxtContent); String title = eTxtTitle.getText().toString(); String content = eTxtContent.getText().toString(); // タイトル、内容が空白の場合、保存しない if (title.isEmpty() && content.isEmpty()) { Toast.makeText(this, R.string.msg_destruction, Toast.LENGTH_SHORT).show(); return; } // ファイル名を生成 ファイル名 : yyyyMMdd_HHmmssSSS.txt // (既に保存されているファイルは、そのままのファイル名とする) if (mFileName.isEmpty()) { Date date = new Date(System.currentTimeMillis()); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.JAPAN); mFileName = sdf.format(date) + ".txt"; } // 保存 OutputStream out = null; PrintWriter writer = null; try{ out = this.openFileOutput(mFileName, Context.MODE_PRIVATE); writer = new PrintWriter(new OutputStreamWriter(out,"UTF-8")); // タイトル書き込み writer.println(title); // 内容書き込み writer.print(content); writer.close(); out.close(); }catch(Exception e){ Toast.makeText(this, "File save error!", Toast.LENGTH_LONG).show(); } } // メニュー選択時の処理 @Override //public boolean onMenuItemSelected(int featureId, MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.action_del: // [削除] 選択処理 // ファイル削除 if (!mFileName.isEmpty()) { this.deleteFile(mFileName); } // 保存せずに、画面を閉じる mNotSave = true; this.finish(); break; default: break; } //return super.onMenuItemSelected(featureId, item); return super.onOptionsItemSelected(item); } }
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:background="#FFD5D5D5" tools:context=".MainActivity"> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/listView" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:background="#FFE3E3E3" android:divider="#FFD5D5D5" android:dividerHeight="8dp" /> </RelativeLayout>
activity_edit.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/eTxtTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_title" android:textSize="22sp" android:layout_marginBottom="5dip" android:inputType="text" /> <EditText android:id="@+id/eTxtContent" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_content" android:textSize="18sp" android:gravity="top|start" android:layout_below="@+id/eTxtTitle" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentBottom="true" /> </RelativeLayout>
string.xml
<resources> <!-- AndroidManifest.xml --> <string name="app_name">ListMemo</string> <string name="edit_activity_title">Edit</string> <!-- MainActivity.java --> <string name="msg_del">Deleted</string> <!-- EditActivity.java --> <string name="msg_destruction">Canceled</string> <!-- activity_edit.xml --> <string name="hint_title">Title</string> <string name="hint_content">Content</string> <!-- main_context.xml --> <string name="context_del">Delete</string> <!-- menu_edit.xml --> <string name="action_delete">Delete</string> <!-- menu_main.xml --> <string name="action_add">Add</string> </resources>