tag:blogger.com,1999:blog-23503320975029367242024-03-13T21:42:07.782+09:00眠いめもphpとかwebサービスとかandroidとかiosとかAnonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.comBlogger49125tag:blogger.com,1999:blog-2350332097502936724.post-84101259641443014112016-06-03T22:58:00.002+09:002016-06-03T22:58:27.800+09:00letsencryptのerror: ImportError: No module named interfaceletsencryptを導入後しばらくほっといたらエラー発生してた。<br />
http://blog.fspm.jp/2016/03/ec2amazon-linuxletsencryptsslhttpsnginx.html<br />
<br />
エラー内容は<br />
<pre>
Automated renewal failed:
Creating virtual environment...
Installing Python packages...
Installation succeeded.
Traceback (most recent call last):
File "/root/.local/share/letsencrypt/bin/letsencrypt", line 7, in <module>
from certbot.main import main
File "/root/.local/share/letsencrypt/local/lib/python2.7/dist-packages/certbot/main.py", line 11, in <module>
import zope.component
File "/root/.local/share/letsencrypt/local/lib/python2.7/dist-packages/zope/component/__init__.py", line 16, in <module>
from zope.interface import Interface
ImportError: No module named interface
</pre><br />
<br />
この2ヶ月程の間にlib名がletsencrypt -> certbotへ変わったりしてる。<br />
<br />
原因はこれ。<br />
https://github.com/certbot/certbot/issues/2823<br />
<br />
解決策は<br />
<pre class="brush:bash"># unset PYTHON_INSTALL_LAYOUT
</pre><br />
<br />
pipのupgradeとか、python2.6, 2.7とかなんも関係なかった、、、Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-74664388221370319212016-03-17T16:54:00.000+09:002016-03-17T16:54:06.165+09:00Chatworkのメッセージ記法リスト(2016.3.16時点)<blockquote>チャットワークのメッセージ記法は、HTMLタグの< >のように[ ]とブラケット(角括弧)文字にてタグ表記され、 単独のタグとして[tagname:value]や[tagname attr=value]と表記される場合と、[tagname]...[/tagname]のように開始タグと終了タグとで囲む表記があります。<br />
<a href="http://developer.chatwork.com/ja/messagenotation.html"><cite>http://developer.chatwork.com/ja/messagenotation.html</cite></a><br />
</blockquote><br />
<br />
<h3>使いそう</h3><br />
<table><tr>
<th>tag</th>
<th>desc</th>
</tr>
<tr>
<td>[hr]</td>
<td>罫線(横のライン)</td>
</tr>
<tr>
<td>[info][title]見出し[/title]内容[/info]</td>
<td>タスク追加や概要編集した際の様なinfo boxが投稿される</td>
</tr>
<tr>
<td>[code]...[/code]</td>
<td>メッセージ記法を無視して入力したテキストがそのまま表示される+code highlighting</td>
</tr>
</table><br />
<br />
<h3>使わなそうだけど有効ぽいもの</h3><br />
<table><tr>
<th>tag</th>
<th>desc</th>
</tr>
<tr>
<td>[preview id=****** ht=150]</td>
<td>アップロードした画像を表示。idは数値、htはheight?不明</td>
</tr>
<tr>
<td>[To:{account_id}]</td>
<td>宛先</td>
</tr>
<tr>
<td>[rp aid={account_id} to={room_id}-{message_id}]</td>
<td>返信</td>
</tr>
<tr>
<td>[qt aid={account_id} time={timestamp}]...[/qt]</td>
<td>引用。[引用 aid=228520]...[/引用]の様にqtを引用に置き換えたり、timeを省略してもおk</td>
</tr>
<tr>
<td>[picon:{account_id}]</td>
<td>アカウントアイコン</td>
</tr>
<tr>
<td>[piconname:{account_id}]</td>
<td>アイコン+名前</td>
</tr>
</table><br />
<style>table, td, th {border: 1px solid #000; border-collapse: collapse;}</style><br />
<br />
ユーザIDに適当な値を入れるとそのユーザのアイコンや名前が表示される(存在すれば)。これはそういう仕様なのかな。<br />
<br />
<h3>参考</h3><ul><li><a href="http://help.chatwork.com/hc/ja/articles/203127904-%E6%8A%95%E7%A8%BF%E3%81%AB%E8%A3%85%E9%A3%BE%E3%81%AF%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%81%8B-">http://help.chatwork.com/hc/ja/articles/203127904-投稿に装飾はできますか-</a><br />
<li><a href="http://developer.chatwork.com/ja/messagenotation.html">http://developer.chatwork.com/ja/messagenotation.html</a><br />
</ul>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-87115783912454745592016-03-05T01:56:00.000+09:002016-04-20T21:40:09.322+09:00EC2(Amazon Linux)をletsencryptでSSL(https)証明書設定(nginx利用)<br />
<h3>Install letsencrypt - インストール</h3><br />
めんどくさいのでrootで。<br />
<br />
<pre class="brush:bash"># git clone https://github.com/letsencrypt/letsencrypt /usr/local
# cd letsencrypt
# ./letsencrypt-auto --help
</pre><br />
<br />
<br />
<h3>Edit nginx conf (for letsencrypt) - letsencryptからの確認アクセス用設定</h3><br />
<pre class="brush:bash"># vi /etc/nginx/conf.d/virtual.conf (or site-availables ... etc)
---
server {
listen 80;
server_name example.jp;
location '/.well-known/' {
default_type "text/plain";
root /tmp/letsencrypttmp;
}
location / {
return 301 https://$host$request_uri;
}
}
</pre><br />
<br />
<br />
<h3>Get certificates - 証明書取得</h3><br />
<pre class="brush:plain"># mkdir /tmp/letsencrypttmp
# /path/to/letsencrypt-auto certonly --webroot -w /tmp/letsencrypttmp -d example.com --agree-tos
</pre><br />
Error が出た。<br />
<pre class="brush:bash">Downloading zope.interface==4.1.3 (141K)...
Downloading mock==1.0.1 (818K)...
Downloading acme==0.4.2 (95K)...
Downloading letsencrypt==0.4.2 (199K)...
Downloading letsencrypt-apache==0.4.2 (99K)...
You are using pip version 6.0.8, however version 8.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Processing /tmp/peep-xGHlQg/argparse-1.4.0-py2.py3-none-any.whl
Installing collected packages: argparse
Successfully installed argparse-1.4.0
You are using pip version 6.0.8, however version 8.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Processing /tmp/peep-uCy7pg/pycparser-2.14.tar.gz
Installing collected packages: pycparser
Running setup.py install for pycparser
Build the lexing/parsing tables
Successfully installed pycparser-2.14
You are using pip version 6.0.8, however version 8.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Processing /tmp/peep-ee_aNB/cffi-1.4.2.tar.gz
Installing collected packages: cffi
Running setup.py install for cffi
building '_cffi_backend' extension
gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -DUSE__THREAD -I/usr/include/python2.7 -c c/_cffi_backend.c -o build/temp.linux-x86_64-2.7/c/_cffi_backend.o
c/_cffi_backend.c:2:20: fatal error: Python.h: No such file or directory
#include <Python.h>
^
compilation terminated.
error: command 'gcc' failed with exit status 1
</pre><br />
python2.7用のライブラリが欠けてるらしい。<br />
<a href="https://community.letsencrypt.org/t/redhat-centos-6-x-users-need-python-2-7/2190">https://community.letsencrypt.org/t/redhat-centos-6-x-users-need-python-2-7/2190</a><br />
<br />
<pre class="brush:bash"># yum install python27-devel python27-pip python27-setuptools python27-virtualenv
</pre><br />
今回はpython27-virtualenvが欠けているだけだった。<br />
<br />
最初のコマンドを再実行。以下の結果が出ればOK。/etc/letsencrypt配下にそれぞれファイルが保存される。<br />
<br />
<pre class="brush:plain">IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/example.jp/fullchain.pem. Your cert
will expire on 2016-06-02. To obtain a new version of the
certificate in the future, simply run Let's Encrypt again.
- If you like Let's Encrypt, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
</pre><br />
<br />
<pre class="brush:plain">cert.pem(証明書)
chain.pem(中間証明書)
fullchain.pem(cert.pem + chain.pem)
privkey.pem(秘密鍵)
</pre><br />
<br />
<br />
<br />
<h3>Setting nginx SSL - nginxでSSL設定</h3><br />
<br />
<pre class="brush:bash"># vi /etc/nginx/conf.d/virtual.conf (or site-availables ... etc)
---
server {
listen 443 ssl;
ssl on;
ssl_certificate /etc/letsencrypt/live/example.jp/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.jp/privkey.pem;
server_name example.jp;
# ~~~(略)
}
</pre><br />
reloadでSSLが動く<br />
<pre class="brush:bash"># /etc/init.d/nginx reload
</pre><br />
<br />
<br />
<h3>Set auto update script - 自動更新</h3><br />
/path/to/update.sh<br />
<pre class="brush:bash">#!/bin/sh
if ! /usr/local/letsencrypt/letsencrypt-auto renew --force-renew > /var/log/letsencrypt/renew.log 2>&1 ; then
echo Automated renewal failed:
cat /var/log/letsencrypt/renew.log
exit 1
fi
/etc/init.d/nginx reload
</pre><br />
crontabとかに登録。毎月2日4:30。どのくらいのペースで実行すればいいんだろう。<br />
<pre class="brush:bash"># crontab -e
30 04 02 * * /home/xxxx/letsencrypt/update.sh
</pre><br />
<br />
セットアップのためになんどもrenewしてたら多すぎって怒られた。5回目くらいからかな。<br />
<br />
<br />
<br />
<h4>参考</h4><ul><li><a href="https://letsencrypt.org/getting-started/">https://letsencrypt.org/getting-started/</a><br />
<li><a href="https://letsencrypt.jp/usage/">https://letsencrypt.jp/usage/</a><br />
</ul>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-22639660855269426052015-01-26T16:53:00.001+09:002015-01-26T16:53:48.759+09:00cake3.0.0-beta から cake3.0.0-RCへのmigrationbeta2ぐらいからRCで結構細かく変わってきている。<br />
<br />
<br />
<h3>config/bootstrap.php</h3>load()で.phpをつけてはいけなくなった。<br />
<pre class="brush:diff">- Configure::load('app.php', 'default', false);
+ Configure::load('app', 'default', false);
</pre><br />
<br />
<h3>config/routes.php</h3>RoutingのCase insensitiveの設定方法が変わった。<br />
<pre class="brush:diff">+ Router::defaultRouteClass('InflectedRoute');
// Router::extensions(['html', 'json', 'txt']); <-- あとこれはRCで追加されたわけではないけどbeta3位で追加しないと動かなかった。
</pre>
<h3>config/app.php</h3>'path'でpathを指定する必要が出てきた。
<pre class="brush:php"> 'debug' => [
'className' => 'Cake\Log\Engine\FileLog',
+ 'path' => LOGS,
'file' => 'debug',
'levels' => ['notice', 'info', 'debug'],
],
</pre>
<h3>src/Model/Table/*Table.php</h3>メソッド名が変わった。古いvalidatePresenceは使用不能に。
<pre class="brush:php">- ->validatePresence('name', 'create')
+ ->requirePresence('name', 'create')
</pre>
<h3>validationタイミングの変更?</h3>validation指定のタイミングの変更。
<pre class="brush:php">// old
$entity = $table->newEntity([/* some entity data array */]);
$table->save($entity, ['validate' => false]);
// new
$entity = $table->newEntity([/* some entity data array */], ['validate' => false]);
$table->save($entity);
</pre>これはRCからなのか詳しく見てないけど'validate' => 'someMyValidation'みたいな指定が出来るようになったっぽい。<br />
<br />
<br />
他にもbakeがplugin化してたりなんか色々あるぽいけど、RCから使い出すならその辺は気にせず使える。<br />
ライブラリ自体の修正でなくてskeletonで作成したPHPテンプレに互換性が無くなると対応めんどい。<br />
Zend Frameworkのノリでbetaからstableまでそんな変わらんだろと思ってたけどちょこちょこ変わる。<br />
<br />
3.0.0もRCなのでもう変わることはないかな〜。今くらいから使いはじめるのがベストではないかと思われる。<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-78680020612853789252014-12-16T23:44:00.000+09:002014-12-16T23:44:54.161+09:00Xcode6でOrganizerからValidate ArchiveするとiTunes Store operation failed. The network connection was lost.になって進まない。Provisioning Profileを変えても駄目で、Xcode5の事例で出てたrestartも駄目で開発機再起動も駄目で何度やっても弾かれるしどうしようもなくなってたが、Application loaderを使うことで解決。<br />
<a href="https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide_Jpn/Chapters/SubmittingTheApp.html#//apple_ref/doc/uid/TP40014483-CH33-SW8">https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide_Jpn/Chapters/SubmittingTheApp.html#//apple_ref/doc/uid/TP40014483-CH33-SW8</a><br />
<br />
Organizerでipaにexportして(Save for iOS App Store Deployment)、Application Loaderからアップロードするとそのままアップロード出来た。<br />
<br />
<br />
というか、新生TestFlightはなぜあんな処理に時間かかるのか。アップロード完了してからアクティブになるまでひどい時だと30分くらいかかる。Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-80734681256234916642014-12-04T18:07:00.002+09:002014-12-04T18:10:05.291+09:00単一Fragmentを表示するActivityの共通化全画面想定のFragmentをActivityで取り回したい場合。AaaFragment, BbbFragmentに合わせてAaaActivity, BbbActivityとか作るのは面倒なのでActivityのWrapperを共通化。<br />
<br />
Fragmentは public static XxxFragment newInstance(Bundle args);を実装している想定。<br />
画面遷移時は、FragmentからならWrapperActivity.openFragmentActivity(getActivity(), SecondFragment.class, secondFragmentsArguments); という感じで行える。<br />
<br />
<pre class="brush:java">package hoge.fuga.activities;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;
import android.view.View.OnClickListener;
import jp.arithmetic.arithmusic.R;
import jp.arithmetic.arithmusic.model.FragmentReplacer;
public class WrapperActivity extends Activity {
public static final String TAG = "WrapperActivity";
public static final String ARGS_FRAGMENT = "app-fragment";
/**
* 1つのFragmentを全面に表示する共通化Activity
* @param fromActivity
* @param clazz
* @param args
*/
public static void openFragmentActivity(Activity fromActivity, Class<? extends Fragment> clazz, Bundle args) {
// setup bundle
if (args == null) {
args = new Bundle();
}
args.putString(ARGS_FRAGMENT, clazz.getName());
// setup intent
Intent i = new Intent(fromActivity, WrapperActivity.class);
i.putExtras(args);
// start activity
fromActivity.startActivity(i);
}
/**
* close
* @param fromActivity
*/
public static void closeFragmentActivity(Activity fromActivity) {
fromActivity.finish();
}
public static void closeToStartActivity(Activity fromActivity) {
Intent i = new Intent(fromActivity, SomeStartActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
fromActivity.startActivity(i);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_empty_container);
// intentパラメータ優先
Bundle args = (getIntent() != null) ? getIntent().getExtras() : savedInstanceState;
if (args == null) {
throw new RuntimeException("Wrapper: Empty arguments");
}
// 呼び出しFragment特定、初期化
String className = args.getString(ARGS_FRAGMENT);
if (className == null || className.isEmpty()) {
throw new RuntimeException("Wrapper: Empty class name");
}
Fragment f = null;
try {
Class<?> clazz = Class.forName(className);
Method newInstance = clazz.getMethod("newInstance", Bundle.class);
f = (Fragment)newInstance.invoke(null, args);
replaceFragment(f);
} catch (ClassNotFoundException e) {
e.printStackTrace();
finish();
} catch (NoSuchMethodException e) {
e.printStackTrace();
finish();
} catch (IllegalAccessException e) {
e.printStackTrace();
finish();
} catch (IllegalArgumentException e) {
e.printStackTrace();
finish();
} catch (InvocationTargetException e) {
e.printStackTrace();
finish();
}
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
closeFragmentActivity(this);
} else {
super.onBackPressed();
}
}
public void replaceFragment(Fragment f) {
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.empty_container, f)
.commit();
}
}
</pre>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-24184294417974919302014-11-17T16:14:00.001+09:002014-11-17T16:15:53.287+09:00AndroidでBlur effect要はiOS7以降のBlur effectぽいことをしたい場合。<br />
・<a href="https://github.com/kikoso/android-stackblur">android-stackblur</a>を使う。<br />
・RenderScriptはradiusがMAX25までしか設定できないぽいので期待しない。<br />
・Eclipse想定<br />
<br />
<br />
<h3>StackBlurライブラリの開発プロジェクトへのインストール</h3>・<a href="http://blog.kotemaru.org/2014/04/02/android-ndk-setup.html">NDK導入</a><br />
・stackblurをDLして、StackBlurディレクトリをプロジェクトimport。<br />
・プロジェクトのコンテキストメニューから、Build Project<br />
・libsディレクトリ配下にビルド成果物ができるので、まるっと開発プロジェクトのlibs配下にコピー<br />
※stackblurのrenderscript8.jarでの競合が無ければIs Libraryでの追加でも大丈夫かも。<br />
<br />
<br />
<h3>利用例</h3><pre class="brush:java">StackBlurManager _stackBlurManager = new StackBlurManager(orig);
_stackBlurManager.processNatively(radius);
Bitmap blurred = _stackBlurManager.returnBlurredImage();
</pre><br />
<h3>利用例:Dialogで使う場合</h3>Dialogに背景画像設定する場合は、DialogのWindow層に設定。<br />
>そうするとDialogの位置とサイズが崩れる。styleで色々設定しても駄目。<br />
>なのでAlertDialogは諦めて自前でCustomViewを作る必要がある。<br />
>それも含めたベースのDialogFragment<br />
<br />
/hoge/fuga/AbstractDialogFragment.java<br />
<pre class="brush:java">package hoge.fuga;
import com.enrique.stackblur.StackBlurManager;
import hoge.fuga.R;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
abstract public class AbstractDialogFragment extends DialogFragment implements OnShowListener {
public static final String TAG = "AbstractDialogFragment";
protected Dialog mDialog;
private ViewGroup mContainer;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mDialog = super.onCreateDialog(savedInstanceState);
// Get status bar height
Rect rectgle= new Rect();
getActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(rectgle);
int statusBarHeight = rectgle.top;
// Screen shot http://stackoverflow.com/a/9596132/1121509
View v = getActivity().getWindow().getDecorView();
v.setDrawingCacheEnabled(true);
Bitmap ss = v.getDrawingCache();
if (ss != null) {
ss = Bitmap.createBitmap(ss, 0, statusBarHeight, ss.getWidth(), ss.getHeight() - statusBarHeight);
}
v.setDrawingCacheEnabled(false);
// Blur effect
if (ss != null) {
int radius = (int) (ss.getHeight() * 0.25);
radius = radius > 100 ? 100 : radius;
StackBlurManager _stackBlurManager = new StackBlurManager(ss);
_stackBlurManager.processNatively(radius);
Bitmap blurred = _stackBlurManager.returnBlurredImage();
mDialog.getWindow().setBackgroundDrawable(new BitmapDrawable(getResources(), blurred));
}
// without title
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
// set listener
mDialog.setOnShowListener(this);
return mDialog;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// コンテナの設定
mContainer = (ViewGroup) inflater.inflate(R.layout.dialog_base, container, false);
return mContainer;
}
public void addViewToContainer(View contentView) {
((ViewGroup) mContainer.findViewById(R.id.dialog_container)).addView(contentView, 0);
}
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onShow(DialogInterface dialog) {
// サイズ調整、このタイミングでないとうまく動かない
Point size = new Point();
Display display = getActivity().getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(size);
} else {
size.x = display.getWidth();
size.y = display.getHeight();
}
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)mContainer.getLayoutParams();
lp.width = size.x;
lp.height = size.y;
ViewGroup dialogContainer = (ViewGroup) mContainer.findViewById(R.id.dialog_container);
FrameLayout.LayoutParams lp2 = (FrameLayout.LayoutParams) dialogContainer.getLayoutParams();
lp2.topMargin = (size.y - dialogContainer.getMeasuredHeight()) / 2;
}
}
</pre><br />
/res/layout/dialog_base.xml<br />
<pre class="brush:xml"><?xml version="1.0" encoding="utf-8"?>
<framelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44000000">
<linearlayout android:id="@+id/dialog_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:background="#44FFFFFF"
android:paddingTop="16dp"
android:paddingLeft="8dp"
android:paddingRight="8dp">
</LinearLayout>
</FrameLayout>
</pre><br />
・Dialogを使う場合はAbstractDialogFragmentをextend。<br />
・dialogの設定をするときはonCreateDialog()をoverrideしてsuper.onCreateDialog()してから設定。<br />
・ViewはonCreateView()をoverrideして、super.onCreateView()してから子Viewを作り、super.addViewToContainer(childDialogView)する。<br />
<br />
<br />
GPUImage for androidがblur effect対応してくれたら嬉しいな〜。<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-27710019581711218482014-11-17T15:34:00.002+09:002014-11-17T15:34:37.406+09:00ElasticSearchのインストール検索サーバElasticSearchのインストールと設定。AWS(EC2)での利用。2014.11.15現在。<br />
<br />
<h2>1. Javaのバージョンを1.7.xにする</h2>もし問題なければ飛ばす。単純アップデートだと古いのものこってて競合するそうなので、古いのはremoveする<br />
http://stackoverflow.com/questions/25518908/issues-after-elasticsearch-1-3-2-upgrade<br />
<pre class="brush:bash"># java -version
# yum install java-1.7.0-openjdk
# yum remove install openjdk-6-jre
# yum remove java-1.6.0-openjdk
</pre><br />
<br />
<h2>2. ElasticSearch本体及びプラグインのインストール</h2><pre class="brush:bash"># rpm -ivh https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.0.noarch.rpm
# /usr/share/elasticsearch/bin/plugin --install mobz/elasticsearch-head
# /usr/share/elasticsearch/bin/plugin --install royrusso/elasticsearch-HQ
# /usr/share/elasticsearch/bin/plugin --install elasticsearch/elasticsearch-analysis-kuromoji/2.4.1
# /usr/share/elasticsearch/bin/plugin --install elasticsearch/elasticsearch-cloud-aws/2.4.0
</pre>※head, HQはおこのみで。<br />
※kuromoji, cloud-awsはelasticsearchのバージョンに応じて入れるバージョンが変わる。それぞれ公式のsetup情報にバージョン対応表が載ってるので確認。上記は1.4.0の場合。<br />
<br />
<br />
<h2>3. 設定ファイル</h2>1台構成ならcluster.name位設定しとけばほかはいらない。EC2で複数台サーバを連携する場合は自動でネゴシエートするためのbroadcastが使えないので、cloud-awsプラグインを入れて設定を行う。また利用するEC2インスタンスはSecurity Groupで9200-9400のPortを開けておく。<br />
<pre class="brush:plain">cluster.name: hoge
# multi-server for EC2 settings
discovery.zen.ping.multicast.enabled: false
cloud.aws.access_key: XXXX
cloud.aws.secret_key: XXXX
cloud.aws.region: ap-northeast
discovery.ec2.host_type: private_ip
discovery.ec2.ping_timeout: 5s
discovery.type: ec2
discovery.ec2.groups: IDorNAME
</pre>※access_key, secret_keyはAWSのIAM Roleの設定で、EC2のDescribeの権限を付けたものを設定<br />
※host_typeはpublic_ipでも問題ないと思われる(未確認)<br />
※ regionなしだと接続できずv2.4.0<br />
<br />
<br />
<h2>4. 起動</h2><pre class="brush:bash"># chkconfig --add elasticsearch on
# /etc/init.d/elasticsearch start
</pre><br />
<br />
<h2>他</h2><br />
<h3>PHPのクライアントをComposerでインストール</h3><pre class="brush:bash">$ php ../composer.phar require elasticsearch/elasticsearch:">=1.0"
</pre><br />
<h3>HQ, headによる状態確認</h3>ttp://ipaddar:9200/_plugin/head/<br />
ttp://ipaddar:9200/_plugin/HQ/<br />
プラグインをインストールできてれば、上記でアクセス可能。<br />
<br />
<br />
<hr>Multi masterは出来ないので複数台構成にしてもmasterサーバはひとつ。可用性を考えるなら、dataを持たないゲートウェイ的なマスタを作り、そこに子をぶら下げる形か。<br />
<br />
trittonn, mroonga, Lucene, Solrと比べて検索システムの中ではだいぶ導入が容易な印象。運用考えると日本語対応した今はCloudSearch使ったほうが楽かも。ただElasticSearchからCloudSearchへのスイッチはサービス拡大に応じて行えるレベルかな。<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-19969551564918427332014-11-17T14:56:00.001+09:002014-11-17T14:56:45.951+09:00CakePHP3の環境切り分けCakePHP3でのdevelopment/productionなどの環境ごとの設定をどうするか。<br />
公式ドキュメントを読むと、どうもbootstrapで設定を追加読み込みするよう促しているのでそれに倣う。<br />
<br />
以下の設定で、基本は本番環境になり、developmentの環境変数を設定することで、開発環境の設定を上書きする形になる。<br />
<br />
<h3>config/bootstrap.php</h3>app.phpの読み込みをした後に、追加の設定を環境に応じて読み込む。config/app_development.phpに開発環境で上書きする設定を記述する。<br />
<pre class="brush:php">try {
Configure::config('default', new PhpConfig());
Configure::load('app.php', 'default', false);
// Add this 3 lines
if (env("APPLICATION_ENV") == "dev" || env("APPLICATION_ENV") == "development") {
Configure::load('app_development.php', 'default', true);
}
} catch (\Exception $e) {
die('Unable to load config/app.php. Create it by copying config/app.default.php to config/app.php.');
}
</pre><br />
<h3>Server setting</h3>nginxの場合はvirtualhostなどserverの設定でphpに渡す環境変数を設定する。<br />
<pre class="brush:plain">server {
location ~ \.php$ {
fastcgi_param APPLICATION_ENV development;
}
}
</pre><br />
Apacheの場合は<br />
<pre class="brush:plain">SetEnv APPLICATION_ENV development
</pre>かな。最近触ってないから忘れたけど。<br />
<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-87448104487136937242014-10-23T17:52:00.001+09:002014-10-23T17:54:12.331+09:00ChromeでAjax(POST, PUT, DELETE)の実行テスト<br />
1. 下記jsの2行目にHTTPMethod、URL、urlencoded形式のリクエストデータを追加<br />
2. Chromeの開発者ツールのConsoleなどページでjs実行できる画面開いて以下実行。<br />
<br />
<pre class="brush:js">(function(m,u,p){var x=new XMLHttpRequest();x.onreadystatechange=function(){if(x.readyState==4)console.log("res:"+x.responseText);};x.open(m,u);x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader('Content-Type','application/x-www-form-urlencoded');x.send(p)})
("POST","http://example.jp/”, 'url=encoded&parameters=string');
</pre>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-71455252498907892452014-09-23T21:56:00.000+09:002014-09-23T21:56:04.296+09:00CakePHP3.0でDBを使わずBasic認証CakePHPのBasic認証はdb使わなくちゃいけなくて不便。そんなユーザ増やすわけでもないしソースに記述があれば十分。みたいな時に使う。<br />
passワードの記述は適当なsalt混ぜてmd5とかでハッシュ化しとくとより良さそう。<br />
<br />
<h3>代替クラス</h3># src/Auth/BasicwodbAuthenticate.php<br />
<pre class="brush:php"><?php
/**
*/
namespace App\Auth;
use Cake\Core\Configure;
use Cake\Auth\BasicAuthenticate;
class BasicwodbAuthenticate extends BasicAuthenticate
{
/**
* ユーザ取得部上書き
*/
protected function _findUser($username, $password = null)
{
$availableUsers = Configure::read('App.Basicwodb');
if (empty($availableUsers)) {
return false;
}
foreach ($availableUsers as $u => $p) {
if ($username === $u && $password === $p) {
return array('username' => $username);
}
}
return false;
}
}
</pre><br />
<h3>設定</h3># src/config/app.php<br />
<pre class="brush:php">return [
'App' => [
'Basicwodb' => ['some-username' => 'some-pass'],
],
];
</pre>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com1tag:blogger.com,1999:blog-2350332097502936724.post-12365236423482105312014-09-23T21:55:00.001+09:002014-09-23T21:55:40.131+09:00CakePHP3.0でURLを小文字でもControllerにつなぐconfig/routes.phpでオプション設定する。”['routeClass' => 'InflectedRoute']”を追加すると小文字のコントローラ名をinflectしてくれる。<br />
<br />
<pre class="brush:php"><?php
// $routes->connect('/', ['controller' => 'Index', 'action' => 'index']);
// $routes->connect('/:controller/:action/*');
$routes->connect('/', ['controller' => 'Index', 'action' => 'index'], ['routeClass' => 'InflectedRoute']);
$routes->connect('/:controller/:action/*', [], ['routeClass' => 'InflectedRoute']);
</pre>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-51266495905956777022014-06-28T19:13:00.002+09:002014-06-28T19:13:43.452+09:00Androidでpinch in/outのjsイベント(gesturestart, gesturechange, gestureend)gesturestart, gesturechange, gestureendはAndroidに無いので、独自実装。<br />
<br />
<pre class="brush:js">var funcGestureStart = function (e) {};
var funcGestureChange = function (e) {};
var funcGestureEnd = function (e) {};
// iOS向けイベント設定
document.body.addEventListener('gesturestart', funcGestureStart, false);
document.body.addEventListener('gesturechange', funcGestureChange, false);
document.body.addEventListener('gestureend', funcGestureChange, false);
// Android向けイベント設定
var pinchDistance = 0;
document.body.addEventListener('touchstart',function(e){
if(e.touches.length > 1){
pinchDistance = Math.sqrt(Math.pow((e.touches[1].pageX - e.touches[0].pageX),2)+Math.pow((e.touches[1].pageY - e.touches[0].pageY),2));
funcGestureStart(e);
} else {
pinchDistance = 0;
}
},false);
document.body.addEventListener('touchmove', function (e) {
if (pinchDistance <= 0) {
return;
}
var newDistance = Math.sqrt(Math.pow((e.touches[1].pageX - e.touches[0].pageX),2)+Math.pow((e.touches[1].pageY - e.touches[0].pageY),2));
var event = {scale: newDistance / pinchDistance};
funcGestureChange(event);
});
document.body.addEventListener('touchmove', function (e) {
if (pinchDistance <= 0) {
return;
}
funcGestureEnd(e);
});
</pre>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-23627615972393588232014-06-16T20:43:00.000+09:002014-06-16T21:08:59.220+09:00Yii2のインストールパッケージ管理システムのcomposerを使って、yii2を入れる。phpはインストール前提(v5.4以上)<br />
<br />
<h3>Composerのインストール、初期化</h3><pre class="brush:bash">## プロジェクトのディレクトリを作る
$ mkdir -p /path/to/project
$ cd $_
## composerインストール
$ curl -sS https://getcomposer.org/installer | php
## composerの初期化 (201406現在yii2はbetaのため、stabilityにdevを設定)
$ php composer.phar init -name vendername/projectname -author authorName –stablility dev
</pre>これで、カレントディレクトリに「composer.phar」「composer.json」が出来る。<br />
<br />
<h3>Yii2のインストール</h3><pre class="brush:bash">$ php composer.phar require --prefer-dist "yiisoft/yii2 *"
## yiiプロジェクトのセットアップ
$ php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic /path/to/project
</pre>これで、カレントディレクトリに「vendor」ディレクトリと管理されているパッケージ、「composer.lock」が出来る。<br />
<br />
composerでは、composer.jsonが設定、composer.lockが現在の状態データ、composer.pharが実行データになる。<br />
実際にリポジトリで管理するのは上記の3ファイルのみ。他はwebサーバ立ち上げてリポジトリからデプロイした後に、php composer.phar install とか php composer.phar update とかバージョン古くなってるて警告出たら php composer.phar self-update とか便宜実行。<br />
<br />
どうでもいいけど、composerっていつもcomporserとtypoしてしまう。打ちづらい。<br />
<br />
参考:http://www.yiiframework.com/doc-2.0/Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-32442463387507754682014-05-22T13:18:00.000+09:002014-05-22T13:18:03.110+09:00PHPのバックトレースを程よい文字列で取得バックトレースを文字列で欲しい場合。<br />
・debug_print_backtrace()では出力してしまうのでoutput bufferなどでの補足が必要で微妙。<br />
・debug_backtrace(); は配列なので冗長。。もっとコンパクトにまとまってて欲しい。<br />
<br />
と思ってたんだけど、PHPマニュアルのコメント欄でいいものを見つけた。<br />
<pre class="brush:php">$e = new Exception();
print_r(str_replace('/path/to/code/', '', $e->getTraceAsString()));
</pre>from http://www.php.net/manual/ja/function.debug-print-backtrace.php#92542<br />
<br />
これくらいの出力がちょうどいい。Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-45612678070769756832014-05-01T21:06:00.003+09:002014-05-01T21:09:47.480+09:00PHP, ImagickでNeon系装飾で文字を入れるNeonというか覆い焼き<br />
例:<a href="http://4.bp.blogspot.com/-wcWb1jOgqAs/U2I5WZnvznI/AAAAAAAALv8/XY8lnXKt8pM/s1600/tmp.jpeg" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-wcWb1jOgqAs/U2I5WZnvznI/AAAAAAAALv8/XY8lnXKt8pM/s320/tmp.jpeg" /></a><br />
<br />
<pre class="brush:php">$TEXT = "example example!";
$FONT_SIZE = 32;
$FWCOLOR = "#FFFFFF";
$BGCOLOR = "#FF0000";
// 貼り付け先の画像
$im = new Imagick();
$im->readImageBlob(file_get_contents('/path/to/baseimagefile'));
// 文字入れ作業用の画像
$tmp = new Imagick();
$tmp->newImage($im->getImageWidth(), $im->getImageHeight(), "transparent", "png");
$tmp2 = clone $tmp;
// 文字入れ用の設定
$draw = new ImagickDraw();
//$draw->setFont('/path/to/font/file');
$draw->setFontSize($FONT_SIZE);
$draw->setGravity(Imagick::GRAVITY_CENTER);
// 文字:ぼかし下地
$draw->setFillColor($BGCOLOR);
$tmp->annotateImage($draw, 0, 0, 0, $TEXT);
$tmp->blurImage($FONT_SIZE / 8, $FONT_SIZE / 10, Imagick::CHANNEL_ALL);
// 文字:全面に来る文字部分
$draw->setFillColor($FWCOLOR);
$tmp->annotateImage($draw, 0, 0, 0, $TEXT);
// 文字:ぼかし調整
$draw->setFillColor($BGCOLOR);
$tmp2->annotateImage($draw, 0, 0, 0, $TEXT);
$tmp2->blurImage(5, 3, Imagick::CHANNEL_ALL);
$tmp->compositeImage($tmp2, Imagick::COMPOSITE_COLORDODGE, 0, 0);
// 最終画像結合
$im->compositeImage($tmp, Imagick::COMPOSITE_COLORDODGE, 0, 0);
// 出力
//$output = $im->getImagesBlob();
//header('Content-Type: ' . $im->getimagemimetype());
//echo $output;
</pre><br />
<br />
ポイントは<br />
・Imagick::blurImage()で適度にぼかす<br />
・Imagick::compositeImage()でImagick::COMPOSITE_COLORDODGE(覆い焼き)をする<br />
<br />
単に一度だけの合成だとネオン効果が弱い気がするのでぼかし下地で強化。Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-1505149042566049062014-04-30T18:05:00.002+09:002014-04-30T18:18:12.589+09:00UIWebViewへアプリ作成画像(UIImage)を入れ込むAssetLibraryを使わず、画像などをData URI Schemeでhtmlに直接埋め込む。<br />
<br />
<br />
<pre class="brush:objc">- (void)changeImage:(UIImage*)image webview:(UIWebView*)webview imageDomId:(NSString*)domId {
NSData *imageData = UIImageJPEGRepresentation(image, 0.8f);
// iOS7以上、6以下は何かライブラリ使う
NSString *imageBase64 = [imageData base64EncodedStringWithOptions:0];
// encodedに改行が含まれてるとuiwebviewでエラーになるため、取り除く
// 上記encodeメソッドで改行が含まれないのであれば不要
imageBase64 = [imageBase64 stringByReplacingOccurrencesOfString:@"\r" withString:@""];
imageBase64 = [imageBase64 stringByReplacingOccurrencesOfString:@"\n" withString:@""];
[webview stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"$('%@').attr('src', 'data:image/jpeg;base64,%@');", domId, imageBase64];
}
</pre><br />
<br />
jsの変数に入れて使ったりも出来る。その場合は"data:image/[format];base64,[content]"をさらにJSONエンコードしとかないと動かないかも。<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-41880984579796950262014-03-25T13:46:00.002+09:002014-03-25T14:01:23.799+09:002014年、PHPフレームワーク雑感(CakePHP, FuelPHP, Yii, ZendFramework)まとめると、中規模開発以上はYii、ミニサービスやスモールスタートならCakePHPが良いかなと思う。<br />
<br />
CakePHPが良いのはやはり学習コストが低い点。お膳立てが多いので欲しいなと思ったものはだいたいある。まだ安定版出てないけどこれからは3.xでいいと思う。<br />
<br />
<h3>
CakePHP(2.x)</h3>
公式ドキュメントを参照するだけでほとんど迷うこと無く開発を進めることが出来る。導入のしやすさはピカイチ。ただし細かいことしようとするとブラックボックスな配列の取り回しに苦労する。とにかく配列が深い、引数が多い、謎、ストレス。<br />
個人的に気になったところは、<br />
・autoload:ディレクトリパス指定とかで自動で読み込んで欲しい。<br />
・ORM:2.xでは推奨されておらず謎のストレスフルな配列結果セットを使うことになる。3.xでは改善されそう。<br />
・マジックメソッド多用:コード補完が効かなくてつらい。<br />
<br />
<h3>
FuelPHP(1.x)</h3>
CakePHPに比べてお膳立てが少ないので自分であれこれ付け加える必要がある。ディレクトリ構成がモヤッとする。fuel/app/classesとか。導入はCakePHPについで楽だしFuelとかoilとかforgeとかなんかかっこいいけど、CakePHPを超えるメリットはあらかじめ環境切り分け(Production, Develop / DB master, slave)が考慮されているところくらいしか思いつかなかった。ORMのテーブル情報をキャッシュしてくれないところも微妙な点。<br />
<br />
<h3>
Yii(1.1.x)</h3>
日本では人気無いけど英語圏では人気のFWなので情報が豊富。ディレクトリ構成がわかりやすくて、Viewのコンポーネントも充実してる。CakeやFuelよりは導入コストがかかるが、Zendよりは導入しやすい。<br />
<br />
<h3>
Zend(2.x)</h3>
1.xから大きく変わり、色々煩雑になってしまった印象。全体的にお固くて設定の配列が冗長、ディレクトリ構造もわかりづらい。FW自体開発者の利便性よりもオブジェクト指向優先でクラスは細かく細分化されている。学習コストは高いが、その分一度慣れると収まるものが収まるところに収まってるので使いやすく感じる。Zend_Formはとても良い。<br />
<br />
<h3>
まとめ2</h3>
ORMは信用しない方が良い。単純な取得や単体での保存では使うが、複雑な条件での取得・トランザクションはモデル内のメソッドとして自前で実装したほうが良い。特にリレーション設定(hasOne, hasMany等)は使わない。<br />
SELECTもController側でmodel->select()->where()みたいなことせずに、それぞれ該当モデルにてメソッド化する方が後から見た時にわかりやすい。<br />
<div>
<br /></div>
各FWともPSRとか出てきてここ2年くらいで刷新したバージョンを出してる(出そうとしてる)けど、その中だとやはりCakePHP-3.xとYii-2.x系が良さそうだなと思う。<br />
他のフレームワークで注視しとくのはLaravelくらいか。Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-42460911480421690492013-10-16T00:04:00.004+09:002013-10-16T00:04:49.839+09:00iosでのappstoreの国設定切り替えios7対応、2013.10.15現在<br />
<br />
・設定アプリ>一般>言語環境から、言語と書式(国)を切り替える<br />
・設定アプリ>iTunes Store/App Storeからその国に設定しているAppleIDでSign in<br />
※初回はレビューしてクレカ情報とか入力してください言われるけど、alertのレビューをおした後に表示される画面でAppStore国を設定して「次へ」で次画面へ行ったあとに<br />
キャンセルすればOK<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-33164290956623449242013-09-12T14:44:00.001+09:002013-09-12T14:46:58.327+09:00cocos2d-xでCocosDenshion::SimpleAudioEngineのplayEffect()がresume時(background to foreground)に鳴らない問題対応BGMは問題ないのだが、効果音(playEffect)が一度backgroundに移行後、再度foregroundに移行した時に鳴らない場合がある。<br />
target os: iOS6.1<br />
audio format: .caf<br />
cocos2dx ver.: 2.1rc0-x-2.1.4<br />
<br />
SimpleAudioEngine::playEffectを追ってみたら[CocosDenshion playSound:sourceGroupId:pitch:pan:gain:loop:]でも特にエラーが起きておらず、正常にOpenALのalSourcePlay()が呼び出されているようだ。loadも問題ないし原因不明。<br />
<br />
ググったら公式フォーラムでちらほら報告があるだけ。<br />
Sound FX not playing after a while.<br />
http://www.cocos2d-x.org/boards/6/topics/3153<br />
http://www.cocos2d-x.org/issues/2512<br />
<br />
とりあえずの対処としてBackgroundに移行する時にend()して、Foregroundにresumeする時にアプリ起動時にpreloadすることで音を鳴らす事ができる(ただしpause~resumeではないので、途中から鳴らす事はできない。)<br />
<pre class="brush:cpp">bool AppDelegate::applicationDidFinishLaunching()
{
// some code ...
CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("press_button.caf");
}
void AppDelegate::applicationDidEnterBackground()
{
CCDirector::sharedDirector()->pause();
CCDirector::sharedDirector()->stopAnimation();
// end
SimpleAudioEngine::sharedEngine()->end();
}
// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground()
{
CCDirector::sharedDirector()->resume();
CCDirector::sharedDirector()->startAnimation();
// preloadEffect
CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("press_button.caf");
}
</pre><br />
ゲーム系で音が鳴らなくなるって結構致命的な気がするんだけど、v2.1.4stableとか、v3.xでは直ってるのかな。不明。Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-69660111654640480142013-09-02T19:04:00.000+09:002013-09-02T19:04:52.615+09:00Google Analytics iOS SDK v2.0beta から v3.0への移行、変更点<h3>Automatic Screen Measurement - 自動的な画面計測</h3><pre class="brush:cpp">// v2 -------
// SomeViewController.h
#import "GAITrackedViewController.h"
@interface SomeViewController : GAITrackedViewController
@end
// SomeViewController.m
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.trackedViewName = @"Some Screen";
}
// v3 -------
// change "self.trackedViewName" to "self.screenName"
</pre><br />
<br />
<h3>Manual Screen Measurement - 手動での画面計測</h3><pre class="brush:cpp">// v2 -------
[[[GAI sharedInstance] defaultTracker] sendView:view]; // or trackView:view
// v3 -------
#import "GAIFields.h"
#import "GAIDictionaryBuilder.h"
[[[GAI sharedInstance] defaultTracker] set:kGAIScreenName value:view];
[[[GAI sharedInstance] defaultTracker] send:[[GAIDictionaryBuilder createAppView] build]];
</pre><br />
<br />
<h3>Event Tracking - イベントのトラッキング</h3><pre class="brush:cpp">// v2 -------
[[[GAI sharedInstance] defaultTracker] sendEventWithCategory:category withAction:action withLabel:label withValue:value];
// v3 -------
#import "GAIDictionaryBuilder.h"
[[[GAI sharedInstance] defaultTracker] send:[[GAIDictionaryBuilder createEventWithCategory:category action:action label:label value:value] build]];
</pre><br />
初期化時は[GAI sharedInstance].debugがなくなったくらい。<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-73101526599328651112013-07-19T12:52:00.002+09:002013-07-19T12:55:45.166+09:00cocos2dxでModalなAlertView(Dialog)coco2dxでAlertViewのような仕組みが見つからなかった。CCMessageBoxというのがあるがあくまで簡易的なものでボタンを2つは置けないようで。<br />
<a href="http://blog.syuhari.jp/archives/2518">[Cocos2d-x] モーダルレイヤを作成する</a>を参考にして作ってみた。細かいところは未検証。とりあえず動くかなという状態。<br />
<br />
<br />
<h3>FSAlertLayer.cpp</h3><pre class="brush:cpp">#include "FSAlertLayer.h"
USING_NS_CC;
// ceate with 2 buttons
FSAlertLayer* FSAlertLayer::create(const char* message, CCObject *target, SEL_CallFuncN okSelector, SEL_CallFuncN ngSelector)
{
FSAlertLayer* layer = FSAlertLayer::create();
layer->setStyle(message, target, okSelector, ngSelector);
return layer;
}
// create with only 1 button
FSAlertLayer* FSAlertLayer::create(const char *message, cocos2d::CCObject *target, cocos2d::SEL_CallFuncN okSelector)
{
return FSAlertLayer::create(message, target, okSelector, NULL);
}
bool FSAlertLayer::init()
{
// half clear black bgcolor
if (! CCLayerColor::initWithColor(ccc4(0, 0, 0, 100))) {
return false;
}
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority, true);
CCSize vsize = pDirector->getVisibleSize();
// bg
CCSprite* frame = CCSprite::create("bg_alert.png");
frame->setTag(FSAlertLayerTagFrame);
frame->setPosition(ccp(vsize.width / 2, vsize.height / 2));
this->addChild(frame);
return true;
}
void FSAlertLayer::setStyle(const char* message, cocos2d::CCObject *target, cocos2d::SEL_CallFuncN okSelector, cocos2d::SEL_CallFuncN ngSelector)
{
this->target = target;
this->okSelector = okSelector;
this->ngSelector = ngSelector;
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
// message
CCLabelTTF *pMsg = CCLabelTTF::create(message, "", 16);
pMsg->setPosition(ccp(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(pMsg);
// OK Button
CCMenuItemImage *pOKItem = CCMenuItemImage::create("btn_ok.png", "btn_ok.png", this, menu_selector(FSAlertLayer::menuAlertOK));
int btnHeight = visibleSize.height / 2 - this->getChildByTag(FSAlertLayerTagFrame)->getContentSize().height / 2 + pOKItem->getContentSize().height / 2 + 10;
pOKItem->setTag(FSAlertLayerTagOK);
pOKItem->setPosition(ccp(visibleSize.width / 2, btnHeight));
CCMenu* pMenu = CCMenu::create(pOKItem, NULL);
pMenu->setPosition(CCPointZero);
pMenu->setTag(FSAlertLayerTagMenu);
this->addChild(pMenu);
// set as 2 buttons
if (ngSelector) {
pOKItem->setPosition(ccp(visibleSize.width / 2 - pOKItem->getContentSize().width / 2, btnHeight));
// NG btn
CCMenuItemImage* pNGItem = CCMenuItemImage::create("btn_back.png", "btn_back.png", this, menu_selector(FSAlertLayer::menuAlertClose));
pNGItem->setTag(FSAlertLayerTagNG);
pNGItem->setPosition(ccp(visibleSize.width / 2 + pOKItem->getContentSize().width / 2, btnHeight));
pMenu->addChild(pNGItem);
}
}
// touch event disable other layers
bool FSAlertLayer::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
return true;
}
void FSAlertLayer::menuAlertOK(CCObject* pSender)
{
CCLOG("OK");
this->menuAlertClose(pSender);
if (this->target && this->okSelector) {
(this->target->*this->okSelector)(this);
}
}
void FSAlertLayer::menuAlertClose(cocos2d::CCObject *pSender)
{
this->removeFromParentAndCleanup(true);
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->removeDelegate(this);
if (((CCNode*)pSender)->getTag() == FSAlertLayerTagNG && this->target && this->ngSelector) {
(this->target->*this->ngSelector)(this);
}
}
</pre><br />
<h3>FSAlertLayer.h</h3><pre class="brush:cpp">#ifndef __xxx__FSAlertLayer__
#define __xxx__FSAlertLayer__
#include "cocos2d.h"
#define FSAlertLayerTagMenu 101
#define FSAlertLayerTagOK 102
#define FSAlertLayerTagNG 103
#define FSAlertLayerTagFrame 110
class FSAlertLayer : public cocos2d::CCLayerColor
{
public:
static FSAlertLayer* create(const char* message, CCObject* target, cocos2d::SEL_CallFuncN okSelector, cocos2d::SEL_CallFuncN ngSelector);
static FSAlertLayer* create(const char* message, CCObject* target, cocos2d::SEL_CallFuncN okSelector);
virtual bool init();
void setStyle(const char* message, CCObject* target, cocos2d::SEL_CallFuncN okSelector, cocos2d::SEL_CallFuncN ngSelector);
virtual bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
void menuAlertOK(CCObject* pSender);
void menuAlertClose(CCObject* pSender);
CREATE_FUNC(FSAlertLayer);
private:
cocos2d::CCObject* target;
cocos2d::SEL_CallFuncN okSelector;
cocos2d::SEL_CallFuncN ngSelector;
};
#endif /* defined(__xxx__FSAlertLayer__) */
</pre><br />
<br />
<h3>利用側</h3><pre class="brush:cpp">// call from Scene, Layer, etc
FSAlertLayer *alertLayer = FSAlertLayer::create("XXXを使用します。よろしいですか", this, callfuncN_selector(ThisScene::menuOKCallback), callfuncN_selector(ThisScene::menuNGCallback));
// 適当に高い数値を入れて最上部に表示させる
this->addChild(alertLayer, 100001);
</pre>Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-89260922869776097072013-06-21T17:03:00.002+09:002013-07-19T12:56:42.678+09:00xcode更新後で新規に作成したファイルでauto completeやsyntax colorが働かないXcodeを更新したらsyntax coloring(code highlight)やauto-complete(code hint)が動かない、作業用インデックスに追加されていないぽい。<br />
<br />
まず以下を試す。organizerでderiveddataを削除、他ユーザのworkspace情報なども削除。<br />
<a href="http://stackoverflow.com/a/8165886">http://stackoverflow.com/a/8165886</a><br />
<br />
それでもダメで、しょうがなくProject, Targetの情報をひとつずつチェックしてったら、どうやらProject->Targets->Build Phases->Compile Sourcesに新しいファイルが含まれていないのが原因だったようだ。新規ファイル作成時にこれまではチェックされていたはずのTargetsがはずれていた。<br />
<br />
これをチェックしてファイルを新規作成ことで問題は解消された(既存ファイルの場合はCompile Sourcesに直接mファイルを追加)<br />
<br />
<a href="http://2.bp.blogspot.com/-f-EXqGNAg-g/UcQINOtF4YI/AAAAAAAALtQ/o-bi7zP8_Jc/s1600/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2013-06-21+16.48.18.png" imageanchor="1" ><img border="0" src="http://2.bp.blogspot.com/-f-EXqGNAg-g/UcQINOtF4YI/AAAAAAAALtQ/o-bi7zP8_Jc/s320/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88+2013-06-21+16.48.18.png" /></a><br />
<br />
<br />
とても無駄な時間だった…。Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0tag:blogger.com,1999:blog-2350332097502936724.post-88128332126242173562013-06-10T11:07:00.002+09:002013-06-10T11:07:43.581+09:00勉強会ログ: 6月7日(金) (Twitter) API 勉強会/API1.0告別式 @恵比寿 @engineyard_jp #apihack2013.6.7<br />
第9回<br />
<br />
次回以降の予定<br />
・PaaS API<br />
・ヘルスケアデバイス系API Nicke+とか<br />
・地理系API GEO系<br />
・決済系API<br />
<br />
<br />
■twitter API1.1<br />
・Twitterエコシステムの定義<br />
・いわゆるtwitterクライアントは自社で出すので作って欲しくない<br />
・”クライアント”の定量的な判断基準はない<br />
・今後新規のいわゆるクライアントはもう無理(ユーザ10万に限るなど…)<br />
・ポイントはtwitterにとって有益になるかどうか<br />
・ディベロッパ利用規約変更<br />
・表示形式の指定がrequiredに<br />
・タイムラインのレンダリングは、twitterのタイムラインであることがわかるように<br />
・twitterの鳥を配置<br />
・API1.0 -> 1.1<br />
・endpointの変更<br />
・単純なURLプリフィクスの変更<br />
・xml廃止、jsonのみに<br />
・廃止されるエンドポイント(public_timeline, retweet関連など)<br />
・レートリミット方式変更<br />
・1.0:1アカウント350回/1時間、1.1:1エンドポイント15回/15分・多く使われるものは180回/15分 (いずれもOAuth必須)<br />
・OAuth必須に<br />
・1.0:一部は150回/1時間でOAuthなしで呼び出し可能、1.1:全て必須<br />
<br />
期限<br />
・1.0は、3/5>6/11に廃止(at SF time)<br />
<br />
移行<br />
・twitter4j(Java):バージョン3.0.xに切り替え>コンパイルエラーをつぶす<br />
・他言語:エンドポイントのバージョン部分を1から1.1にかえてエラーをつぶす<br />
<br />
<br />
■Twitter Cards<br />
・tweetにメタ情報、付加情報を埋め込む為の仕様<br />
・140文字以外の文章として出してくれる<br />
・例:webページURLをはるとそのページのアイコンが自動で表示<br />
・例:SlideShare、tweet内にスライド<br />
<br />
方法<br />
・webページにmetaタグで埋め込む<br />
・twitter:card, summary photo, player<br />
<br />
Twitter CardsとOpen Graph<br />
・twitter cardsはopen graphがベースになっており、だいたい一緒<br />
・基本のメタ情報(url, title, description, image...)はopen graphを設定しておけばtwitter cardsとして表示される(twitter:cardは必要)<br />
<br />
事前申請が必要<br />
・open graphは普通は不要(Facebookなど)<br />
・twitterの申請ページからフォーム入力して申し込み<br />
・期間は数日から2週間くらい(申請確認メールに返信すればチケット作られるのでやってくれるはず)<br />
・何故必要なのか<br />
・tweetが多いので全URLに反応してクロールするのは高コストなため事前申請(ほぼ登録みたいな感じ?)にしている<br />
<br />
>webを展開するなら、Twitter Cardsは対応しておいた方が良さそう。tweetへの追加情報の表示は魅力的<br />
<br />
<br />
■なんとなくわかってきたtwitter APIとのつきあい方(小宮さん)<br />
・twitter4jを使ってツイートをDBに蓄積するにあたって、実際のなま情報<br />
・仕様と違うとか<br />
・注意するポイント6点<br />
<br />
1)アプリケーションの登録に注意する<br />
・WebSite:twitter.comドメインとかいれといてAPIをはげしくつかうと、アプリケーションのstatusがsuspendedになって、アプリケーションも削除できずどうにもできなくなる<br />
<br />
2)絵文字に負けない<br />
・絵文字(UTF-8外字)を含むテキストをVARCHAR(140)に保存すると文字数オーバ<br />
・絵文字を保存する際は、MySQLならcharsetをutfmb4にする必要があり、絵文字1文字につき4文字分消費するので、560にする必要がある<br />
<br />
3)NULL文字に負けない<br />
・時々tweetにNULL文字が紛れ込むことがある<br />
・NULLは除外する方がよい<br />
<br />
4)NFD/NFKDに負けない<br />
・UNICODE正規化:発音記号等を1バイト文字2文字で表現するような分解<br />
<br />
5)ユーザが常に存在するとは限らない<br />
・search/tweetsのstatus["user"]が存在しないことがある<br />
<br />
6)screen_nameが15文字であるはずがない<br />
・サイトには15文字と書いてあるが、過去に20文字許されてた時期があった。<br />
<br />
<br />
■家族フォト<br />
MVP(mininum valuable product)<br />
・最小構成でサービスをリリースする<br />
・その後仮説と検証を経てよりよいものにつくってく<br />
<br />
ベネッセとデジタルガレージの協業<br />
・2ヶ月でweb, iOS, Android向けアプリを出さなきゃなかった<br />
・APIは自社json(HTTPS)、bgはappEngine<br />
・appEngineではSSLを使う際、金払った実績がないと利用できない制約がある<br />
・appEngine:dbモジュールからndbモジュールに変更:modelで定義してるものは自動でmemcacheでキャッシュを利用してくれる<br />
・スマホアプリは基本APIをたたく。<br />
・PhoneGapを使った(iphone4あたり少しもっさりだが、一般のユーザはそんな気にしない)<br />
・sharp端末で不具合頻発、あとandroidでは画像の保存ディレクトリが端末によって違ったりした<br />
・phonegapはhtml+css+jsで開発しやすかった<br />
<br />
仮説と検証<br />
・DL当日しか使ってないユーザは30〜40%<br />
・週1以上起動ユーザは約半数<br />
<br />
<br />
■Acitivity body (fitbit API)(朝倉さん)<br />
・アクティビティトラッカー<br />
<br />
fitbit feature<br />
・歩数<br />
・移動距離<br />
・消費カロリー<br />
・上位機種は、階段上り下りや睡眠時間なども記録可能<br />
<br />
Fitbit API(json or xml)<br />
・userinfo<br />
・body measurements(体組織:体重、慎重)<br />
・Activities(歩数とか)<br />
・利用<br />
・要ディベロッパー登録<br />
<br />
Third party libs<br />
・ruby, php, .net, java<br />
<br />
<br />
■飯テロのススメ(美馬さん)<br />
・twitter日本語で、一番つぶやかれる時間は0時<br />
・おやすみが一番いわれるのは23:50分くらい<br />
<br />
<br />
■Application-only authentication<br />
・ユーザの認可を必要とせずに、twitter APIにアクセスできるようになる認可方式<br />
・tweet投稿や、フォロー等の操作に依存するAPIは使用できない<br />
・一部APIのレートリミットは大きく緩和されている。search/tweetsは+270回、friends/list・folloowers/listは+15回<br />
<br />
twitter4jでの実験的な利用方法<br />
・OAuthコンシューマーキーを作る<br />
・twitter4j.propertiesを編集する:consumerkey, consumersecretの設定、useSSL=true(3.3.4以前)、enableApplicationOnlyAuthentication=trueにする<br />
・twitter.getOAuth2Token();を呼び出すとA-oAが適用になる<br />
<br />
<br />
■だれとくアプリからSNS活用への道(佐藤さん)<br />
・秋葉の雁川という中華料理屋のアプリ<br />
・そのおすすめアプリサービス(androidアプリ)<br />
・twitter, Facebook, mixi, forsquareへ同時投稿や行ったときのチェックインを一括で行うアプリ<br />
・twitter ->twitter4j, forsquare->forsuqare-api-java<br />
・mixi, facebook ->SDKが多機能だったので独自に利用部分だけ実装<br />
・公開後1年たったら公式アカウントからキャンペーンに使いたいという連絡が来た>杏仁豆腐おごってもらった。<br />
<br />
<br />
<br />
その他メモ<br />
・twitterのAPIが1.1になって、tweetを集めるのはやりやすくなったが、フォロワー関係を取得しづらくなっている<br />
・3時間で128ツイート、1日に1024ツイートで規制。メンションしまくりでsuspended<br />
<br />
<br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com2tag:blogger.com,1999:blog-2350332097502936724.post-84536283226053522582013-02-22T01:27:00.001+09:002013-02-22T01:30:11.685+09:00修正BSD, MIT, Apacheライセンスのライブラリを使ってスマホアプリを作る場合の対応以下のライセンスのライブラリ等を利用しスマホアプリを作成、配布(公開)する場合。正しいかどうかはわかりません。。。<br />
<br />
<h3>エンドユーザ向け表示</h3><br />
<h4>修正BSDライセンス、MITライセンス</h4>・ライブラリのソースファイル内ヘッダコメントやREADME等にあるライセンス表記を、ライブラリ名とともにそのまま表示する。<br />
※無い場合はライブラリ名、著作権表記(無ければライブラリ所在URLとか?)、免責事項を含む一般的なライセンス表記を表示<br />
※アプリ上の設定等にライセンスについてや著作権表示みたいな専用の画面を作ってそこに記述するのがオーソドックス<br />
<br />
<h4>Apacheライセンス</h4>・ライブラリ内にNOTICEファイル等帰属告知やライセンス表記があるものがあればそれをそのまま表示する<br />
※無ければApacheライセンスのテキストとライブラリ名を表示<br />
※上記同様専用の画面を作る<br />
<br />
<br />
<h3>開発ソース</h3><h4>修正BSDライセンス、MITライセンス</h4>・ライブラリ上に記載される著作権表記等はそのままにする<br />
<br />
<h4>Apacheライセンス</h4>・ライブラリ上に記載される著作権表記等はそのままにする<br />
・ライブラリを改変する場合はその旨を上記著作権表記あたりに追加記述する<br />
<br />
<br />
<h3>参考</h3><a href="http://ja.wikipedia.org/wiki/MIT_License">Wikipedia - MITライセンス</a><br />
<a href="http://ja.wikipedia.org/wiki/BSD%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9">Wikipedia - BSDライセンス</a><br />
<a href="http://ja.wikipedia.org/wiki/Apache_License">Wikipedia - Apacheライセンス</a><br />
<a href="http://www.homu.net/2007/06/post_cd47.html">BSDライセンスの特徴:BSDライセンスが適用されたソフトウェアを商用利用する場合の注意点を教えてください。またMITライセンスとの違いも教えてください</a><br />
Anonymoushttp://www.blogger.com/profile/12632269558207596790noreply@blogger.com0