head

2013年11月13日水曜日

ファイルアップロードでHTML5-ドラッグ_ドロップと、ajax画像送信とPHP受信処理。2013-11-13

11月前半ですけど寒くなってきましたね。鍋の季節!!

さて、ファイルのアップロード機能について
HTML5 のDrag & Drop、Ajax(jQuery)送信、PHP(cakePHP 2.1.x)の受信の
実装などについてメモです。
(客先見積りの関係で調べてましたが、結構ハマリました。)



動作確認は、Chromeのみです。

cakePHPの app/ 以下のみですが、Gitに置いてます。どうぞ。
https://github.com/kuc-arc-f/php_cake11

win版のXAMPPで開発 (unix版はそのまま動くか未定です。)
コンテキスト=cake11

============================================内容の説明など
[1] /cake11/posts/dnd6 で画面起動します。
div要素の [ここへ画像ドロップ] 領域にドロップします。

[2] アップロードされます。
 (1個だけ、複数の場合はループ処理にすればできるはず!)

[3] Controller, ajaxの送信先は upload5()です。

class PostsController extends AppController {
    public $helpers= array('html' ,'Form');

        public function upload5(){
//var_dump( $_FILES['files']['name'] );
                        $uploadfile = "../webroot/img/"  .  $_FILES['file']['name'] ;
                        if (move_uploaded_file( $_FILES['file']['tmp_name'] , $uploadfile) == false ) {
                     $response = array('ret'=> "0");
                         echo json_encode($response );
                         exit();
                         }else{
                     $response = array('ret'=> "1");
                         echo json_encode($response );
                         exit();
                         }
        }

        public function dnd6(){
                $this->set('title_for_layout', 'upload dnd5');
                $this->layout = null;
        }
}

[3] View (/ cake11 / app / View / Posts / dnd6.ctp)
ドロップされたら、
HTML5のFormDataに、form要素をセットし、
ajax送信してます、コールバックで、アップされたIMGを描画してます。

<script type="text/javascript">
function send_imgfile( files ){
 $form = $("#hogeForm");
          fd = new FormData($form[0]);
          fd.append('file', files[0] );
   $.ajax('/cake11/posts/upload5', {
     type: 'post',
     processData: false,
     contentType: false,
     data: fd,
     dataType: 'html',
     success: function(data){
       console.log(data);
alert(  'complete send :'+files[0].name );
disp_items( files[0].name );
     }
   });
   return false;
}
</script>

<div id="dropzone"  ondragover="onDragOver(event)" ondrop="onDrop(event)">
    <p>ここへ画像を<br />ドロップ</p>
</div>
<div id="id_form_div" style="display: none;">
<form id="hogeForm" method="post" action="" enctype="multipart/form-data">
  <div><input type="file" name="file1"></div>
  <div>ファイルの説明:<input type="text" name="hogeText"></div>
  <input id="hogeSubmit" type="submit" value="うpする">
</form>
</div>

<script type="text/javascript">
function onDrop(event){
    var files = event.dataTransfer.files;
    send_imgfile( files );

    event.preventDefault();
}
</script>

============================================

*) cakePHPの app/ 以下のみですが、Gitに置いてます。どうぞ。
https://github.com/kuc-arc-f/php_cake11

それでは、また会いましょう。

2013年9月16日月曜日

Android ProgressBar Custom(カスタム版)の作成 2013-09-16

さて、通常のProgressDialogを
使用してましたが、違う部品を作成してみました。

[1] 背景や、サイズを変更できるので。使い道はあるかも。

[2] AsyncTask内などで、使えればよいな。と思ってます。
 サンプルはハンドラで止めてます。デモの為。

[3] こんな感じです。



ソースはこちら。どうぞ
https://github.com/kuc-arc-f/TestProg2


[4] 説明など

====== Laytout-XML (prog.xml)
<com.example.testprog.CustumProgress
        android:id="@+id/progress1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
</com.example.testprog.CustumProgress>
======

コンストラクタで。
プログレス、プログレス下の文字セットします。

======SRC一部分
    public CustumProgress(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setOrientation(VERTICAL);
        setBackgroundColor(Color.argb(128, 0, 0, 0));
        this.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
        mContext = context;
       
        init_progress(context);
    }
   
    void init_progress(Context context){
    mProgress= new ProgressBar(context);
    int i_w   = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  WIDTH_PROG, this.getResources().getDisplayMetrics());
    int i_h   = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  HEIGHT_PROG, this.getResources().getDisplayMetrics());
    int i_ht  = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  HEIGHT_TXT, this.getResources().getDisplayMetrics());
   
        LinearLayout.LayoutParams llp =  new LinearLayout.LayoutParams(i_w, i_h);
        mProgress.setLayoutParams(llp);
        mProgress.setBackgroundColor(Color.BLACK );
        this.addView(mProgress);
       
        mTextView= new TextView(context);
        LinearLayout.LayoutParams llt =  new LinearLayout.LayoutParams(i_w, i_ht);
        mTextView.setLayoutParams(llt);
        mTextView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
        mTextView.setBackgroundColor(Color.BLACK );
        mTextView.setTextColor(Color.WHITE);
        addView(mTextView);
       
        setVisibility(View.INVISIBLE);
    }
====

呼び出し、アクティビティ側
LayoutInflaterで、XML指定し、
CustumProgressを読み込みます。その後Viewを追加。

====
void progress_init( )
{
View view = this.getLayoutInflater().inflate(R.layout.prog, null);
mCProgress= (CustumProgress)view.findViewById(R.id.progress1);
mCProgress.set_titie("Loadging..");

addContentView(view, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT ));
}
===
*) どうそ
https://github.com/kuc-arc-f/TestProg2

それではまた。



2013年8月27日火曜日

GCM でマルチキャスト メッセージ送信方法(JSON形式)、(PHP) 2013-08-27

夏ですね。お盆過ぎてもまだ暑い、、

さて、PHPで
APサーバからGCM送信時に、マルチキャスト メッセージ(複数配信、JSON形式)
する方法です。最大= 1,000件までみたいですけど。

ぐぐると単発(テキスト形式)はあるけど、マルチは少なかった気がしますので、メモ。

GCMの申請、register(登録IDの確定)などは、他のサイトをご参考ください。
送信処理のみ記載です。

$apiKeyは、取得したキー使ってください、curl使ってますけど。
下記はファイルから、複数ID取得してます。($ROOT/dat)
postするパラメータなどは、下記のサイト様など参照頂ければと思います。
(いろいろ設定できるみたいです。)
===============================
<?php

$url = 'https://android.googleapis.com/gcm/send';

$message = 'Hello, test-GCM!!';

$apiKey = "xxxx";

//heaer
$header = array(
  'Content-Type: application/json',
  "Authorization: key={$apiKey}",
);

    $registerDir =  $_SERVER['DOCUMENT_ROOT'] . "/dat";
$fileList = scandir($registerDir);

//    $ict =count($fileList);
    $i_reg=0;
    $items = array();
    foreach($fileList as $s_fnm){
        if(!is_dir($s_fnm)){
     $regId = file_get_contents($registerDir . "/{$s_fnm}");
 $items[$i_reg] = $regId;
 $i_reg += 1;
        }
    }
// print(json_encode($items) );
       //post-data
$post_list = array(
'collapse_key' => 'update',
'time_to_live' => 108,
'data'         => array('message' => $message),
'registration_ids' => $items,
);

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_FAILONERROR, 1);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($curl, CURLOPT_POST, TRUE);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($post_list) );
    curl_setopt($curl, CURLOPT_TIMEOUT, 5);
 
$ret = curl_exec($curl);
var_dump($ret);
?>
===============================
実行すると、複数push配信できるはず!!(たぶん)

*)参考までに、送信の前の、登録ID保存。(Androidからの送信ID保存)
===============================
<?php
if (!isset($_POST['regId'])){
 print("-1");
 exit;
}

$registerDir =  $_SERVER['DOCUMENT_ROOT'] . "/dat";

$regId = $_POST['regId'];
$filename = md5($regId). ".txt";

file_put_contents($registerDir."/{$filename}", $regId);
?>
===============================


ご参考のサイトさま:
http://www.techdoctranslator.com/android/guide/google/gcm/gcm

http://www.atmarkit.co.jp/ait/articles/1302/12/news029.html

*) それでは、また会いましょう。

2013年8月11日日曜日

Mac OS 10.7.5に、Node.js, WebSocketをインストールしてみる。 2013-08-11


お盆の時期ですね。それにしても暑い、、

さて、
WebSocketを試したかったので。
Node.jsを Mac(10.7.5)にインストールしてみました。
若干はまったので、メモしておきます、


[1] Node.js インストール

1) http://nodejs.org/ で[INSTALL] ボタン押す。
*) 今回は、pk形式。

2) node-v0.10.15.pkg を実行。ダイアログでるので
 ひたすら、次に進む。
 完了。

3)確認。
コンソールから、
node --version
など実行。
$ node --version
 v0.10.15
version出ればOK

[2] 「npm」のインストール
ぐぐると、Ubuntu 系の説明はあるが、Macは少ない気がした。

1) apt-getで、curlのセットアップ
$ sudo apt-get install curl
 > macは、apt-getがない事に気づく(汗、)

2) macの場合、fink で対応するらしいので、
このへん参考。
 http://d.hatena.ne.jp/haronoid/20130503/1367581401
時間かかったけど、終了。しかし、 すでにcurlがインストール済だった事に気づく(汗、)
*) fink は不要かもしれません。

3) npm setup
 参考記事には、下記コマンドの記載が多いが、macだとこれエラーなりました。
 $ curl http://npmjs.org/install.sh | sh
 回避策は、ブラウザで 「http://npmjs.org/install.sh」入力して、ローカル保存。
 (wget でも良いかも。)

 $sh install.sh ,実行してOK

4) npmでのインストール手順、
$ npm install 【パッケージ名】
 npm install -g [pkg]  が良いかもしれません、 -g は、グローバル領域?。

*) この後、コンソールの再起動が必要だったかも、たぶんパスの関係で

[3] WebSocket (socket.io)
 1) socket.io入れてみました。
 npm install -g socket.io
 2) express フレームワークもついでに、追加。
 npm install -g express

*) WebSocketとかで、ぐぐると。サンプルのプロジェクトとか、
 数件でてきましたので、動かしてみました。

[4] 実行編
 このへん参考(おもしろかった、)
 http://www.atmarkit.co.jp/ait/articles/1210/10/news115.html
 expressの chatプロジェクトで、複数ブラウザ立ち上げても、同一メッセージ(chat)
 がリアルタイムにpush配信される。(外部クラウドでも、はやいのか? )


*)参考サイトさま
http://www.atmarkit.co.jp/ait/articles/1102/28/news105.html
http://www.tettori.net/post/293/

*) Node.js はデメリットもありそうですが、いろいろ試してみると
 面白そうですね。
 それでは、また会いましょう


2013年4月21日日曜日

facebook広告, 結果レポート4月、2013/04/21


サツキが咲くころですね。

4月分の宣伝キャンペーン実施しましたので(facebook広告出)、
結果を記載したいと思います。

[推奨入札価格] :おまかせ設定(デフォルト)

[条件]
ターゲット (北米、欧州、アジアの一部ねらい):
米国、
イタリア、
マレーシア、
オランダ、
ノルウェー、
カナダ、
スペイン、
スウェーデン、
スイス、
シンガポール、
イギリス、
フィンランド、
デンマーク、
日本、
韓国、
トルコ、
タイ、
ロシア、
フィリピン、
香港、
台湾、
ブラジル、
メキシコ、
フランスまたはドイツのいずれかに住んでいる

次のカテゴリに該当: 写真、iOS/Apple (All)
掲載期間(東京時間): 2013/4/9 – 2013/4/18 (約10日)
年齢:17歳以上
予算:通算= 10,000 en (JPY)

================== AD-result ===============================
[広告結果]
リーチ: 982,960
クリック数: 1,340
アクション(いいね): 56
CTR: 0.051%
平均費用: 4 en(JPY)
==================

*) 作成した、広告バナーはこれ。 (110 * 80)


*) 期間は長めにしたが、1日の予算が少ないので。効果は低い?みたいな結果でした。
*) tumblrの普及地域を考えて、欧米(先進国)をメインに配信したのも、失敗だったかもしれません。
 (以外と新興国を中心のほうが良かったのかもですね。)
*) 今回、年齢指定(17)してみました。そのせいか「いいね」少なめでした(汗、、)
 次は12歳でチャレンジするか検討です。

*) ちなみに今回出した、iPad Apps はこれです(Kuc.Board Ad for tumblr)。どうぞ。
https://itunes.apple.com/us/app/kuc.board-ad-for-tumblr/id615045225?l=ja&ls=1&mt=8

それでは、また会いましょう。



2013年4月13日土曜日

Apps-Info:「kuc.Board for tumblr」(Android) GWアプリコンテスト応募の掲載記事 2013-04-13

週刊アスキー様向け。GWアプリコンテスト応募の記事です。

概要:tumblr ビューア (タンブラーの写真ビューア)

以下はアプリ説明等です。
=====================================================
(1)アプリについてアピールしたいことを自由にコメント
【質問1】このアプリを着想されたきっかけは?
 1) 開発当時でダッシュボードなどの、グリッドレイアウト表示できるtumblrアプリが少なかった。
 2) タブレットレイアウトのtumblrアプリが少なかった。(スマホと関係ないのですが)

【質問2】このアプリの開発者的なセールスポイントを教えてください
 1) カタログを見るような、スワイプ操作で次ページを表示できます。(6 - 8アイテム)
 2) メイン画面の高速描画 (表示ページの先アイテムを事前にダウンロード)
 3) 詳細画面の高速描画 (スワイプ時には、表示ページの先アイテムを事前にダウンロード)
 4) 詳細画面で,写真(種類=写真の場合)をクリックすると、拡大画面表示できます。

【質問3】開発で苦労された、あるいは楽だったのは、どういう点ですか?
 苦労した点:スマホ(小さい画面)で、レイアウト配置等に苦労しました。

(2)アプリの画像(アイコン、スクリーンショット数点)
アイコン:

スクリーン:


=====================================================

*) おまけ[補足情報]
[Goole Play]

[製品ページ:弊社HP]


*) iOS(iPad)製品もリリースしておりますが、今回スマホ限定みたいですので
   Androidのみ応募とさせて頂きます。




2013年3月8日金曜日

twitter4J 3.0.3 Android実装、 Twitter API 1.1対応 OAuth認証 --2013/03/08

twitter4J 3.0.3 Android実装、 Twitter API 1.1対応 OAuth認証 --2013/03/08

春ですね、梅の咲く時期!!
twitter API 1.1ですが、
2013/03/05で切り替えみたいな記事見ましたので、旧APIでAndroid実装してた部分の、改修やってみました。
今頃修正しても、遅いのですが(汗、、)
現時点で、旧API 1.0でも動くみたいですが、将来的に無くなると予想して作業です。
twitter4J 2.x -> 3.0.3 の移植ですが、結構ハマリました。Androidのサンプルが少い気がしました。

準備などは下記サイトを参考。
推奨されない方法みたいですが、WebView使ってます。
基本はtwitter4J 2.xに似てます。下記ソースです。

1) requestTokenの生成, Intent起動して、onActivityResultでAccesToken生成します、
==============================================
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.auth.AccessToken;
import twitter4j.auth.OAuthAuthorization;
import twitter4j.auth.RequestToken;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationContext;

public static OAuthAuthorization _oauth = null;
private RequestToken requestToken = null;
String mCallbackURL = "myapp://oauth";

public class LoadTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void ... params) {
try
{
exec_connect();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
try
{
start_Intent();
}catch(Exception e){
e.printStackTrace();
}
}
}

    private void start_Intent() throws Exception{
    try
    {
         Intent intent = new Intent(this, TwitterLogin.class);
         intent.putExtra("auth_url", requestToken.getAuthorizationURL());
         this.startActivityForResult(intent, REQUEST_CODE);
    }catch( Exception e){
    throw e;
    }
    }
 

    private void exec_connect() throws Exception{
    try
    {
//Log.d(TAG, "#exec_connect=" );    
            //Twitetr4Jの設定を読み込む
            Configuration conf = ConfigurationContext.getInstance();
            //Oauth認証オブジェクト作成
            _oauth = new OAuthAuthorization(conf);
            _oauth.setOAuthConsumer(m_Const.CONSUMER_KEY, m_Const.CONSUMER_SECRET) ;
            //アプリの認証オブジェクト作成
            try {
                requestToken = _oauth.getOAuthRequestToken(mCallbackURL);
            } catch (TwitterException e) {
                e.printStackTrace();
            }
    }catch( Exception e){
    throw e;
    }
    }



2) WebView, コールバック[oauth_verifier]をGETします。
==============================================
package com.kuc_arc_f.app.hoge;

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.kuc_arc_f.fw.*;


public class TwitterLogin extends Activity {

//
private com.kuc_arc_f.fw.ComUtil m_Util = new ComUtil();

protected void onCreate(Bundle bundle) {

super.onCreate(bundle);
        setContentView(R.layout.twitterlogin );
        try
        {
        init_proc();
        }catch(Exception e){
        e.printStackTrace();
        m_Util.errorDialog(this, e.toString() + e.getMessage());
        }
}
//
private void init_proc() throws Exception{
try
{
WebView webView = (WebView)findViewById(R.id.twitterlogin);
webView.setWebViewClient(new WebViewClient(){

public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);

String CALLBACK_URL = "myapp://oauth";

if(url != null && url.startsWith(CALLBACK_URL)){
String[] urlParameters = url.split("\\?")[1].split("&");

String oauthToken = "";
String oauthVerifier = "";

if(urlParameters[0].startsWith("oauth_token")){
oauthToken = urlParameters[0].split("=")[1];
}else if(urlParameters[1].startsWith("oauth_token")){
oauthToken = urlParameters[1].split("=")[1];
}

if(urlParameters[0].startsWith("oauth_verifier")){
oauthVerifier = urlParameters[0].split("=")[1];
}else if(urlParameters[1].startsWith("oauth_verifier")){
oauthVerifier = urlParameters[1].split("=")[1];
}

Intent intent = getIntent();
intent.putExtra("oauth_token"   , oauthToken);
intent.putExtra("oauth_verifier", oauthVerifier);

setResult(Activity.RESULT_OK, intent);
finish();
}
}
});

// 認証ページを表示。
webView.loadUrl(this.getIntent().getExtras().getString("auth_url"));
}catch(Exception e){
throw e;
}
}

}
3) AccessTokenをGETします。
==============================================
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

if(resultCode == RESULT_OK){
super.onActivityResult(requestCode, resultCode, intent);

TokenTask tsk = new TokenTask();
tsk.execute(intent);
}
}
 
public class TokenTask extends AsyncTask<Intent, Void, Void> {
@Override
protected Void doInBackground(Intent ... params) {
try
{
m_RetAcToken= m_Const.NG_CODE;
AccessToken token = null;
token =  _oauth.getOAuthAccessToken( requestToken, params[0].getExtras().getString("oauth_verifier"));
//Log.d(TAG, "TokenTask.token="+ token.getToken());
//Log.d(TAG, "TokenTask.token.oauth_token_secret="+ token.getTokenSecret());
m_RetAcToken= m_Const.OK_CODE;
            } catch (TwitterException e) {
                e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
try
{
if(m_RetAcToken.equals( m_Const.OK_CODE)){
//ok
}else{
m_Util.errorDialog(BG01Act.this, "system error, fail get AccessToken .");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
==============================================

*)参考サイト様:
http://techbooster.org/android/mashup/5301/
http://techbooster.org/android/5040/
http://qiita.com/items/f6f39900fd5e449045f9

2013年1月15日火曜日

adMob さんに広告出しました(出稿) 結果編 ,2013/01/15

adMob さんに広告出しました(出稿) 結果編です。


冬ですね、鍋の季節!!

AD申請が早めに返事きましたので、申請&結果内容まとめて記載します。

[結果]
インプレッション数: 400,424
クリック数: 936
CTR= 0.23%
平均 CPC= $0.05
コスト= $50 USD

==AD入札条件etc
グループ設定、デフォルト入札額= 0.5(USD)
広告編集、入札= 0.4(USD)
予算= 50 USD (そのまま)
地域:南米、アジア、東ヨーロッパ、西ヨーロッパの一部以外の地域。
*)今回、北米、オセアニア、アフリカとかは対象外しときました。
===

*)ちなみに、Apps はこれ、よろしければどうぞ。
kuc.Board :tumblr ビューワ
https://play.google.com/store/apps/details?id=com.kuc_arc_f.app.board

*) 配信開始後、5-10分程度で予算(広告在庫)使い切ったようです。(即完了メール、汗、)
 次は成功報酬型のADとかも検討しようと思います。でも予算少ないと厳しいですね、、

それでは、また会いましょう。

2013年1月4日金曜日

Android HorizontalScrollView で、指定ページに移動させる方法。 --2013/01/04

Android HorizontalScrollView で、指定ページに移動させる方法。 --2013/01/04



正月ですね。おせちの季節!!
HorizontalScrollViewで移動、イベントなどで指定ページに動かす場合、
苦戦したので、メモです。

ググると、scrollTo() とか出てきます。
メインスレッドから呼ぶと、ページ移動しません。
handler経由だと、動きました。

*) 使ったのは、このアプリ(書籍)、是非どうぞ。
https://play.google.com/store/apps/details?id=com.kuc_arc_f.app.aozora

*) 参考ページ: http://relog.xii.jp/archives/2010/11/horizontalscrol.html
それでは、また会いましょう。

=== SRC一部 ===
 public class ShowH_ScrollView extends HorizontalScrollView implements OnTouchListener, OnGestureListener
 {
static final String TAG="ShowH_ScrollView";
private Handler _handlerAnimation = null;

private final Runnable _runAnimationThread = new Runnable(){
    public void run(){
        updateAutoScroll();
    }
};

public ShowH_ScrollView(Context context) {
 super(context);
 setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
   LayoutParams.FILL_PARENT));
}

public ShowH_ScrollView(Context context, int maxItem,
  int itemWidth, int itemHeight, ArrayList<ItemPT> lst, String s_dir, View info_view)
{
this(context);
try
{
startAutoScroll();


}catch(Exception e )
{
e.printStackTrace();
}
}
/**
 * ハンドラ
 * @return
 */
private Handler getHandlerAnimation(){
    if(_handlerAnimation == null){
        _handlerAnimation = new Handler();
    }
    return _handlerAnimation;
}

public void startAutoScroll(){
    //監視を開始
    getHandlerAnimation().postDelayed(_runAnimationThread, 100 );
}
public void updateAutoScroll(){
scrollTo(itemWidth * activeItem , getScrollY());
}


 }
===

google colaboratory お試し編 、GPUも使える機械学習の環境構築

前回続き、機械学習の関連となります。 開発環境まわりの内容となり。先人様の情報を元に調査しました。 google colab(google colaboratory) を試してみました。機械学習系の いくつかのライブラリがインストール済みで、 クラウド上で、ある程度機械学...

AD-parts

Shop
Bluetooth搭載
ベース基板

Social