「Googleドキュメントのフォーム機能からGoogle Apps Scriptを使ってメール送信」を参考に、Google Apps Scriptで簡易メールフォームを作成してみた。
function mailUserName(value) {
return value + " 様\n\n";
}
function sendMailFromForm() {
Logger.log('sendMailFromForm() debug start');
//------------------------------------------------------------
// 設定エリアここから
//------------------------------------------------------------
var subject = "[お問い合わせ]";
var body
= "お問い合わせありがとうございます。\n\n"
+ "------------------------------------------------------------\n";
var footer
= "------------------------------------------------------------\n\n"
+ "後ほど担当者よりご連絡させていただきます。";
var COLUMN_TIMESTAMP = "タイムスタンプ";
var COLUMN_NAME = "氏名";
var COLUMN_MAIL = "メールアドレス";
// メール送信先
var admin = "yohei.yoshikawa@gmail.com"; // 管理者(必須)
var cc = ""; // Cc:
var bcc = admin; // Bcc:
var reply = admin; // Reply-To:
var to = ""; // To: (入力者のアドレスが自動で入ります)
//------------------------------------------------------------
// 設定エリアここまで
//------------------------------------------------------------
try{
// スプレッドシートの操作
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getLastRow();
var cols = sheet.getLastColumn();
var range = sheet.getDataRange();
Logger.log("cols =" + cols);
for (var j = 1; j <= cols; j++) {
var col_name = range.getCell(1, j).getValue();
var col_value = range.getCell(rows, j).getValue();
body += "【"+col_name+"】\n";
body += col_value + "\n\n";
if (col_name === COLUMN_NAME) {
body = mailUserName(col_value) + body;
}
if ( col_name === COLUMN_MAIL ) {
to = col_value;
}
}
/*
var timestamp = range.getCell(rows, 1).getValue();
var last_name = range.getCell(rows, 3).getValue();
var first_name = range.getCell(rows, 5).getValue();
var last_name_kana = range.getCell(rows, 2).getValue();
var first_name_kana = range.getCell(rows, 4).getValue();
var to = range.getCell(rows, 6).getValue();
var content = range.getCell(rows, 7).getValue();
Logger.log("last_name="+last_name);
Logger.log("first_name="+first_name);
Logger.log("last_name="+first_name_kana);
Logger.log("first_name="+first_name_kana);
Logger.log("to="+to);
Logger.log("content="+content);
body += LABEL_TIMESTAMP + "\n";
body += timestamp + "\n";
body += LABEL_NAME + "\n";
body += last_name + " " + first_name + "様\n";
body += LABEL_CONTENT + "\n";
body += content + "\n";
body += footer;
Logger.log("body="+body);
*/
// 送信先オプション
var options = {};
//if ( cc ) options.cc = cc;
//if ( bcc ) options.bcc = bcc;
if ( reply ) options.replyTo = reply;
// メール送信
if ( to ) {
MailApp.sendEmail(to, subject, body, options);
}else{
MailApp.sendEmail(admin, "【失敗】Googleフォームにメールアドレスが指定されていません", body);
}
}catch(e){
MailApp.sendEmail(admin, "【失敗】Googleフォームからメール送信中にエラーが発生", e.message);
}
}
viでWindowsの改行コードで「^M」が表示されることがあるが、viコマンドモードでは「^M」が認識できないので、
[Ctrl]+[V]キーを押して、[Ctrl]+[M]キーを押す
これで以下のように置換できる。
:%s/^M//g
よく忘れるのでメモ。 連想配列をソートする方法のひとつに、NSSortDescriptor の sortedArrayUsingDescriptors がある。 initWithKey でキーを、ascending で昇順、降順を指定(昇順がYES)します。
関数化するまでもないですが、とりあえず。
- (NSArray *)sortScore:(NSSet *)values :(NSString *)sortKey :(BOOL)flag {
return [values sortedArrayUsingDescriptors:
[NSArray arrayWithObject:
[[NSSortDescriptor alloc] initWithKey:sortKey ascending:flag]
]
];
}
NSSet のところは NSArray でもいいですが、その辺は状況に応じてキャストします。
■SPECCTR http://specctr.com/
■Select Manager http://www.pixelimage.jp/blog/2008/05/_fireworksselectmanager.html
■PI_Slice http://www.pixelimage.jp/blog/2011/07/pi_slice.html
■css-professionalzr http://www.mattstow.com/css-professionalzr.html
■ImageSnippet https://github.com/KinkumaDesign/ImageSnippet
■SequenceNumSlice http://www.kuma-de.com/program/2009-06-14/799
■まとめサイト http://oshare.jugem.cc/?eid=759
jQuery downloadで、draggableにチェックをつけてダウンロードする。
/**
* draggable
*/
$(function() {
$(".draggable").draggable({
snap: ".gray",
snapTolerance: 50,
opacity: 0.5
});
});
AudioServicesCreateSystemSoundID を利用して短い音を再生するのは良いのですが、
ネットワーク通信するとボリュームボタンで制御できない
事が判明
たちの悪い事に、adMobを利用するだけでダメです。 と言う事で、短い音を再生するには OpenALが一番手っ取り早いかと。
AVAudioPlayerはBGM鳴らすのはいいのですが、効果音のように連続で音をならすようなモノはちょっと不向きです。
--2012/06/08追記 OpenALは、AdMobとかで処理が割り込まれた場合、オーディオが止まることがあります。 以下の対処でいいらしい。 restarting openAL after application interruption on the iPhone
AudioSessionInitialize で interruptionListener を設定し、割り込みがあった時に OpenAL を Suspendしてやる感じだそうです。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self loadALC];
OSStatus result = AudioSessionInitialize(NULL, NULL, interruptionListener, (__bridge void*) self);
NSLog(@"result %@", result);
return YES;
}
- (void)loadALC {
UInt32 category = kAudioSessionCategory_AmbientSound;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (category), &category);
AudioSessionSetActive(YES);
ALCdevice* device;
ALCcontext* alContext = alcGetCurrentContext();
if (alContext == nil) {
device = alcOpenDevice(NULL);
alContext = alcCreateContext(device, NULL);
alcMakeContextCurrent(alContext);
}
}
void interruptionListener(void *inUserData, UInt32 inInterruption) {
if (inInterruption == kAudioSessionBeginInterruption) {
printf("BeginInterruption\n");
ALCcontext* alContext = alcGetCurrentContext();
alcMakeContextCurrent(NULL);
alcSuspendContext(alContext);
}
if (inInterruption == kAudioSessionEndInterruption) {
printf("EndInterruption\n");
UInt32 category = kAudioSessionCategory_AmbientSound;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
ALCcontext* alContext = alcGetCurrentContext();
alcMakeContextCurrent(alContext);
alcProcessContext(alContext);
}
}
目覚ましのように定期時間ではなく、ホームボタンを押した後に定期時間に通知させる場合、applicationDidEnterBackground にLocalNotification処理を記述する。
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self addNotification];
}
- (void)cancelNotification {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
- (void)addNotification {
[self cancelNotification];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL isNotification = [defaults boolForKey:SETTING_IS_NOTIFICATION];
if (!isNotification) return;
int timeIndex = [defaults integerForKey:SETTING_NOTIFICATION_TIME];
int sec = 60;
NSDate *today = [NSDate date];
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [today dateByAddingTimeInterval:sec];
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.alertBody = [NSString stringWithString:NSLocalizedString(@"MESSAGE_NOTIFICATION", nil)];
notification.alertAction = NSLocalizedString(@"Open", nil);
notification.soundName = UILocalNotificationDefaultSoundName;
//localNotif.applicationIconBadgeNumber = localNotif.applicationIconBadgeNumber + 1;
//NSDictionary *infoDict = [NSDictionary dictionaryWithObject:@"local notify" forKey:@"Key"];
//notification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
よく使うのでメモ
まず型を指定しない場合はObjective-Cのオブジェクト同様、以下のメソッドで利用する。
- (id)objectForKey:(NSString *)defaultName;
- (void)setObject:(id)value forKey:(NSString *)defaultName;
- (id)loadSetting:(NSString *)key {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return [defaults objectForKey:key];
}
- (void)saveSetting:(NSString *)key :(id)value {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:value forKey:key];
[defaults synchronize];
}
明示的に型を指定する場合は、castするか以下のメソッドを利用する。
- (NSString *)stringForKey:(NSString *)defaultName;
- (NSArray *)arrayForKey:(NSString *)defaultName;
- (NSDictionary *)dictionaryForKey:(NSString *)defaultName;
- (NSData *)dataForKey:(NSString *)defaultName;
- (NSArray *)stringArrayForKey:(NSString *)defaultName;
- (NSInteger)integerForKey:(NSString *)defaultName;
- (float)floatForKey:(NSString *)defaultName;
- (double)doubleForKey:(NSString *)defaultName;
- (BOOL)boolForKey:(NSString *)defaultName;
- (NSURL *)URLForKey:(NSString *)defaultName NS_AVAILABLE(10_6, 4_0);
- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName;
- (void)setFloat:(float)value forKey:(NSString *)defaultName;
- (void)setDouble:(double)value forKey:(NSString *)defaultName;
- (void)setBool:(BOOL)value forKey:(NSString *)defaultName;
- (void)setURL:(NSURL *)url forKey:(NSString *)defaultName NS_AVAILABLE(10_6, 4_0);
ちなみに、カスタムクラスをそのまま保存しようとする場合はエラーになってしまうので、NSDictionary に変換する必要がある(うまくcastとかできるかも知れないが・・・)。
- (BOOL)loadSettingBool:(NSString *)key {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return [defaults boolForKey:key];
}
- (void)saveSettingBool:(NSString *)key :(BOOL)value {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:value forKey:key];
[defaults synchronize];
}
ちなみに不要になった設定は、removeObjectForKey で削除する。
- (void)removeObjectForKey:(NSString *)defaultName
http://www.hollance.com/2011/02/soundbankplayer-using-openal-to-play-musical-instruments-in-your-ios-app/
http://www.deluge.co/?q=midi-driven-animation-core-audio-objective-c
Web Audio API + Web Socket + MIDI(Java)でピアノのマルチセッションができるサンプル http://www.multiplayerpiano.com/
これでMIDIデバイスで操作できれば?と調べると「Midibridge」で利用できるみたいだ。
さすがにWebKitベースでは無理なので JavaApplet を経由している。
Midi Devices -> Java Applet -> Javascript Midibridge API
http://jazz-soft.net/demo/HelloMIDI.html