2012/07/05

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);
    } 
}

  2012/07/05

viでWindowsの改行コードで「^M」が表示されることがあるが、viコマンドモードでは「^M」が認識できないので、

[Ctrl]+[V]キーを押して、[Ctrl]+[M]キーを押す

これで以下のように置換できる。

:%s/^M//g

  2012/06/28

よく忘れるのでメモ。 連想配列をソートする方法のひとつに、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 でもいいですが、その辺は状況に応じてキャストします。

  2012/06/21

jQuery downloadで、draggableにチェックをつけてダウンロードする。






/**
 * draggable
 */
$(function() {
    $(".draggable").draggable({
        snap: ".gray",
        snapTolerance: 50,
        opacity: 0.5
    });
});

Stack Trace:Draggable

  2012/05/30

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);
    }
}

  2012/05/28

目覚ましのように定期時間ではなく、ホームボタンを押した後に定期時間に通知させる場合、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];
}

  2012/05/28

よく使うのでメモ

まず型を指定しない場合はObjective-Cのオブジェクト同様、以下のメソッドで利用する。

- (id)objectForKey:(NSString *)defaultName;
- (void)setObject:(id)value forKey:(NSString *)defaultName;

NSUserDefaults から値を読み込む場合(型未設定)

- (id)loadSetting:(NSString *)key {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    return [defaults objectForKey:key];
}

NSUserDefaults に値を保存する場合(型未設定)

- (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とかできるかも知れないが・・・)。

NSUserDefaults から BOOL型を読み込む場合

- (BOOL)loadSettingBool:(NSString *)key {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    return [defaults boolForKey:key];
}

NSUserDefaults に BOOL型を保存する場合

- (void)saveSettingBool:(NSString *)key :(BOOL)value {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setBool:value forKey:key];
    [defaults synchronize];
}

ちなみに不要になった設定は、removeObjectForKey で削除する。

- (void)removeObjectForKey:(NSString *)defaultName

  2012/05/25

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

  2012/05/09

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

pngファイルの軽量化
Google DriveのIconを再起的に削除
php-markdownでバニラPHPなコードブロック処理
laravel-ffmpeg を使う
2021年版 Ubuntu + certbot + Let's Encrypt でサーバ証明書設定
GihHub のデフォルトでない master ブランチを checkout する
マルチログインで未認証のリダイレクト
Homebrew で Redis をインストール
CSS だけでスムーズスクロール
EC-CUBE4 で Gmail の smtp を利用する
Amazon Linux 2 の amazon-linux-extras とは
UNIQUE カラムのバリデーションで自分自身を除外して更新
フォーム有効期限切れで Page Expired をリダイレクト
ログを日付でローテーションやクリアや削除
Homebrew で PHP8.0 から PHP7.4 にダウングレード
Big sur で zsh 移行と Homebrew アップグレード
Mac に minikube をインストール
途中から .gitignore に追加する
Larevel 6.x から Laravel 8.x にバージョンアップ
Composer で Allowed memory size (メモリ不足)エラー
Blade でカスタムクラスを利用する
git push git pull にブランチ指定せずに実行する
git pull や git push できなくなったとき
Docker のコンテナからホストOS に接続
Mac で ローカル IP アドレス(ipv4)のみを表示する
ホストOS から Docker の MySQLコンテナに接続
caching_sha2_password のエラー
node-config で環境設定ファイルを利用する
rootパスワードを初期化(再設定)する
Git から clone したときのエラー対処
Mac に MySQL をインストール
Mac に PostgreSQL をインストール
Laravel 環境構築 - Mac ネイティブ編
Firebase 入門 - Firebase とは
Firebase 入門 - CLI インストールとデータベースの設定
AWS 無料枠(t2.micro)で容量とメモリエラー
Cloud9 を起動する -初心者編-
gcloud で GCEインスタンスを起動してみる
AWS CLI と jq でインスタンス一覧を整形して表示
React と Laravel7 のプロジェクトを作成する
Homebrewインストール-2020年版
3直線で囲まれた範囲塗りつぶし
PuLP で線形最適化問題を解く
カスタムのペジネーションを作る
node-sass を使って sass をコンパイルする
Log ファサードでSQLログを分離して書き出す
いちから始める Docker - 複数のコンテナを使う - (2020年)
いちから始める Docker - docker-compose を使う - (2020年)
AWS ECR を使ってみる
Laravel7 でマルチ認証