/// BANGBOO BLOG ///
■23/5/29 7:30PM
GCP hands-off 2
■プロジェクト削除時のサービスアカウントプロジェクトは30日保留される。その間サービスアカウント権限は生きており他プロジェクトでは動作する。しかし保留期間はプロジェクトを使用できずサービスアカウントを削除できず、個別に一つ一つ権限をはく奪するしかない。
サービスアカウントはプロジェクト削除前に、必要であれば事前に削除や無効化しておくことも検討する。

■連携
GoogleWorkspace -> GAS -> GCP Oauth + API -> GCP(Bigquery etc.)Python -> Gcloud sdk -> gcloud auth -> GCP(Bigquery etc.) <-> federation query/Connected sheet
Python(Oauth key) -> GCP認証情報(Oauth Key) + API -> GoogleWorkspace
 GCPのクレデンシャルページでOauth2.0 client IDと鍵が発行でき、鍵でイケる
  Pythonコードで鍵を指定すると実行時にログインを求められ、client IDとユーザIDを紐づけして実行することになる  Authentication — gspread 5.7.2 documentation
  Python でシンプルに OAuth 2 する (urllib + oauthlib) - Qiita
 GCPのクレデンシャルページでAPIキーも発行でき、これは可能性はあるPython -> local csv/tsvが基本
●Python(SA key) -> GCP認証情報(SA Key) + API -> GoogleWorkspace
 サービスアカウントでGWSにアクセスできないのでダメ
  信頼しているドメインとのみ外部共有を許可する - Google Workspace 管理者 ヘルプ
  サービス アカウント(ドメイン名の末尾が「gserviceaccount.com」)を信頼しているドメインにすることはできません
   OUで許可するとイケるはずだが、、
●Python でGoogle docをイジるGoogle Docs APIを使って文章を作成してみる - より良いエンジニアを目指して (hatenablog.com)Google Docs APIを使って、索引を作成する #Python - Qiitaスコープ情報 Google API の OAuth 2.0 スコープ  |  Authorization  |  Google for Developers下記のURLの内容を検証すればよいPython のクイックスタート  |  Google Docs  |  Google for DevelopersGoogle CloudコンソールでOauth同意画面を設定Google Docs APIを有効化OAuth クライアントIDを作成シークレットJson ファイルができるのでDL(リネーム)コードにクレデンシャルJSONファイルとDocのURLに含まれるdocumentIDを記述→Python実行するとDocのデータが取れる(ローカルの場合は楽)

/// runのデプロイ時に設定を入れる方法について1)環境変数を(コンソール/cmd/コンテナymiのどれかで)設定:env=os environ.get("ENV") で使う。ログに出やすく非推奨2)シークレットマネージャ保存分を設定環境変数+コードでやるのと同じ?3)ボリュームを使う:クレデンを入れ、トークンの一時保存ができる?Cloud RunでSecret Managerを使いたい #Python - Qiita
※サービスアカウントでGWSを扱うにはGWSのOUで受け入れる設定が必要な場合がある

■secret managerに保存してコードで呼び出して使う Secret Managerのシークレットアクセサー権限 シークレット バージョンにアクセス  |  Secret Manager Documentation  |  Google Cloud (checksumをかけている)
from google.cloud import secretmanagerimport google.cloud.loggingimport loggingdef get_url(secret_key, project_num) logging.warning('####### secret_key' + str(secret_key) + '######') client = secretmanager.SecretManagerServiceClient() resource_name = "projects/()/secrets/()/versions/latest.format(project_num, secret_key) res = client.access_secret_version(resource_name) slack_url = res.payload.data.decode("utf-8") return slack_url
■API等でデータを取った時中身が分からない場合pramsが何かわからん時print(params)print(type(params))#<class 'proto.marshal.collections.maps.MapComposite'>#よくわからんクラスでもdirで保持するAttributeが分かるattributes = dir(params)print(attributes)#そこに含まれるメソッドも確認できるのでhelpするhelp(params.get) #prams.get('query')すると含まれるSQLが分かりこれで進める等

■Protocol buffersAPIの返りはGoogleは自社で開発したProtocol buffersを使っていようだたとえば下記が返るname: "projects/98765"parent: "folders/12345"project_id: "aaaaaa-bbbb-market"state: "ACTIVE"display_name: "aaaaaa-bbbb-market"create_time{ seconds: 1601250933 nanos: 820000000}update_time{ seconds: 1632826231 nanos: 634000000}etag: "W/a06910d9093db111"labels{ key: "budget_group" value: "cccc"}
これはprint (type(response))すると下記であり<class "google.cloud. resourcemanager v3.types.projects.Project"> print (response.project_id) で簡単にデコードし値取得できることが分かる
APIからの値を取るときのコードfrom google.cloud import resourcemanager_v3client = resourcemanager_v3.ProjectsClient()request resourcemanager v3.ListProjectsRequest{ #組織の場合、現状は権限がGOP側で用意がなく無理だった #parent organizations/12345678. parent="folders/1122233344"}page_result = client.list_projects(request=request)for response in page result: print(type(response)) print (response.project_id)
エンコードする場合 https://blog.imind.jp/entry/2019/12/28/124728pip install googleapis-common-protos でインスコ?sudo apt install protobuf-compiler でインスコ
sudo apt-get install protobuf-compiler でインスコ ※google提供のフォルダごと使用しようとして失敗した方法  ※googleapis/google/cloud/resourcemanager/v3/projects.proto at master · googleapis/googleapis · GitHub ※にprotoファイルがあるが丸々必要なので下記でDL ※git clone https://github.com/googleapis/googleapis.git ※バスを合わせてprojects.protoを使うが失敗 ※たとえば protoc python_out=. --proto_path=googleapis ./googleapis/google/cloud/resourcemanager/v3/projects.protoprojects.proto を下記の内容で一から作成することが必要だったsyntax proto3;
message Resource{ string name = 1; string parent = 2;  string project_id = 3; string state = 4; string display_name = 5;  map<string, string> create_time = 6; map<string, string> update_time = 7; string etag = 8; map<string, string> labels = 9;}そして下記を実行しコンパイルprotoc --python_out=. ./projects.protoprojects_pb2.pyが生成されるため、パッケージとして読みこみprotocol buffersを実行できるようになるimport projects_pb2.py※なおエラーで pip install U protobuf=3.20.0でダウングレードした
注意点としては、pythonとprotocol bufferとBigqueryの型合わせが必要 DateやTimestampはUNIXエポックからの日数や秒数に変換する必要がある Noneをstr 'None'や、int -1や、bool FalseにPythonで調整をするBigQuery Storage Write API を使用してデータを一括読み込み、ストリーミングする  |  Google Cloud

//UNIXエポックからの日数current_date = datetime.now()epoch = datetime(1970, 1, 1)record_date = (current_date - epoch).days
//UNIXエポックからの秒数data_string = str(date_v)dt_obj = datetime.fromisoformat(date_string.replace("Z","+00:00"))epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)seconds_since_epoch = (dt_obj - epoch).tatal_seconds()microseconds_since_epoch = int(seconds_since_epoch * 1e6)date_v = microseconds_since_epoch
■BQ APIクォータ割り当て超過(1000件insertしようとした)割り当てと上限  |  BigQuery  |  Google Cloudテーブル変更1日1500件までテーブルメタデータ変更は10sあたり5回までテーブル当たりDMLの実行待ちキューは20件までテーブル当たり10sあたり25のDMLまで→各insertでスリープを5秒入れた import time time.sleep(5)

上限がテーブル単位のためテーブル名を分けると回避できるらしいGCP BigQuery 応用編 ~制限について~ - 自称フルスタックエンジニアのぶろぐ。 (hatenablog.com)
↓■BQ streaming insert->BQ storage read/write APIの上限はDMLと別で、閾値が大きい
streaming insert -> Bigquery storage write API を使うINFORMATION_SCHEMAを用いたBigQueryのストレージ無駄遣い調査 - ZOZO TECH BLOGBigQuery Storage Write API を使用してデータを一括読み込み、ストリーミングする  |  Google Cloud
Storage Write API を使用したデータ読み込みのバッチ処理  |  BigQuery  |  Google Cloud

CreateWriteStream > AppendRows(ループ) > FinalizeWriteStream > BatchCommitWriteStreams
 をstart/append/send/close(write commit)の関数化し返り値でつなげた形にしたが sendをした後 proto_rows = types.ProtoRows() を掛け初期化する必要があった(offsetが倍々で増えたから)offsetで送信毎の開始行の設定も必要(一連の処理で件数を記憶しており0固定で処理を書けないようだった)
■Python/Client libraryの値をBQに入れるにあたり仕様書で型を調べる。STRUCTやクラスは紐解いて通常のカラムでBQに挿入timestampやboolやint64はそのままの形でBQに挿入BQ SQL:日付は値なしならNULLを入れる、数値やBool値はクォートで囲まないPythonでSQLインサート文を作るとき改行コードが含まれるものをセットするとSyntax errror:Unclosed string literalq = q.replace('//', '////') バックスラッシュをエスケープ、あるとイリーガルエスケープシーケンスとなる、raw文字列にしたい?
q = q.replace('/n', '//n') 改行をエスケープq = q.replace("'", "\\'") SQLが途切れないようシングルクォートをエスケープq = q.replace('/n', '    ') 改行を空白で置き換える
■変更の判断
変更で問題がでないか→PCにマウスと付けて問題が起こらないかという問題と相似、最終的に経験で判断するしか

■監査ログからSetIamのメソッドを取りBQ権限付与を検知するクエリ
WITH source AS(SELECT*FROM `project-logging.organization_audit_log_v2.cloudaudit_googleapis_com_activity_20*`WHERE_TABLE_SUFFIX = format_date('%y%m%d', current_date("Asia/Tokyo"))),project source AS(SELECTROW_NUMBER() OVER (ORDER BY timestamp) as id,*FROM sourceWHEREprotopayload_auditlog.methodName = 'SetlamPolicy'project_authorizationinfo AS(SELECTDISTINCTid,__ori.resource.type as type,__ori.resource.labels.project_id as project_id,__ori.resource.labels.dataset_id as dataset_id,protopayload_auditlog.methodName as method_nameprotopayload_auditlog.resourceName as resource_name,protopayload_auditlog.authenticationInfo.principal Email as email_manipulator,authorizationInfo.resource as request_resource,authorizationInfo.permission as request_permission,authorizationInfo.granted as request_granted,protopayload_auditlog.requestMetadata.callerlp as callerlp,protopayload_auditlog.requestMetadata.callerSuppliedUserAgent as callerSuppliedUserAgent,FROM project_source AS __ori). UNNEST (protopayload_auditlog.authorizationInfo) AS authorizationInfoproject_bindingdeltas AS(SELECTid,--array_binding Deltas_project as binding Deltas_project,array_binding Deltas_project.action as action_project,array_binding Deltas_project.member as member_project,array_binding Deltas_project.role as role_project,timestampFROM project_source AS_ori,UNNEST (protopayload_auditlog.servicedata_v1_iam.policyDelta.bindingDeltas) AS array_binding Deltas_project),project_setiam AS(SELECT--*, except(id)type,project_id,dataset_id,method_name,resource_name,email_manipulator,request_resource,request_permission,request_granted,callerip,callerSuppliedUserAgent.action_project,member_project,role project.CAST(NULL AS STRING) AS metadataJson,CAST(NULL AS STRING) AS bindingDeltas_dataset,CASTINULLAS STRING AS action_dataset,CAST(NULL AS STRING) AS member_dataset,CAST(NULL AS STRING) AS role_dataset,CAST(NULL AS STRING) AS bindingDeltas_table,CAST(NULL AS STRING) AS action_table,CAST(NULL AS STRING) AS member_table,CAST(NULL AS STRING) AS role_table,timestampFROM project_authorizationinfoLEFT JOIN project_bindingdeltas ON project_authorizationinfo.id = project_bindingdeltas.idWHERE role_project LIKE 'roles/bigquery%),resource_source AS (SELECT__ori.resource.type as type,__ori.resource.labels.project_id as project id,__ori.resource.labels.dataset_id as dataset_id,protopayload_auditlog.methodName as method_name,protopayload_auditlog.resourceName as resource_name,protopayload_auditlog.authenticationInfo.principalEmail as email_manipulator,authorizationInfo.resource as request_resource,authorizationInfo.permission as request_permission,authorizationInfo.granted as request_granted,protopayload_auditlog.requestMetadata.callerlp as callerlp,protopayload_auditlog.requestMetadata.callerSuppliedUserAgent as callerSuppliedUserAgent,protopayload_auditiog.metadataJson,timestampFROM source AS __ori,UNNEST(protopayload_auditlog.authorizationInfo) AS authorizationInfo WHEREprotopayload_auditlog.methodName = 'google.iam.v1.IAMPolicy.SetlamPolicy' --AND timestamp= "2024-03-11 04:11:30.885258 UTC"),resource_id AS (SELECTROW_NUMBER() OVER (ORDER BY timestamp) as id,*FROM resource_source),resource_bq_dataset AS (SELECTid as id_dataset,json_extract(metadataJson, '$.datasetChange bindingDeltas') as bindingDeltas_dataset,json_extract(array_bindingDeltas_dataset, '$action') as action_dataset,json_extract(array_bindingDeltas_dataset, $.member') as member_dataset,json_extract(array_bindingDeltas_dataset, '$.role') as role_dataset,FROM resource_id,UNNEST(json query_array(metadataJson, '$.datasetChange.bindingDeltas')) AS array_bindingDeltas_dataset),resource_bq_table AS (SELECTid as id table,json_extract(metadataJson, '$.tableChange.bindingDeltas') as bindingDeltas_table,json extract(array_bindingDeltas_table, '$.action') as action table,json_extract(array_bindingDeltas_table. '$.member') as member table,json_extract(array_bindingDeltas_table, '$.role') as role_table,FROM resource_id,UNNEST(json query_array(metadataJson, '$.tableChange.bindingDeltas')) AS array_bindingDeltas_table),resource_setiam AS ( SELECT--*except(id, id_dataset, id_table)type,project_id,dataset_id,method_name,resource_name,email_manipulator,request_resource,request_permission,request_granted,callerlp,callerSuppliedUserAgent,CAST(NULL AS STRING) AS action_project,CAST(NULL AS STRING) AS member_project,CAST(NULL AS STRING) AS role_project,metadataJson,bindingDeltas_dataset,action_dataset,member_dataset,role_dataset,bindingDeltas_table,action_table,member_table,role_table,timestampFROM resource_idLEFT JOIN resource_bq_dataset ON resource_id.id = resource_bq_dataset.id_datasetLEFT JOIN resource_bq_table ON resource_id.id = resource_bq_table.id_table)SELECT * FROM project_setiamUNION ALLSELECT * FROM resource_setiam

■BQからCloudSQLにデータを入れる (GCSを経由する、コマンドやPythonがあるbq query --use_legacy_sql=false 'CREATE OR REPLACE TABLE `prj.ds._table` AS SELECT FROM `prj.ds.view`';bq extract -destination_format CSV 'prj.ds._table' gs://bucket/tbl.csvgcloud sql import csv インスタンス名 gs://bucket/tbl.csv --database=データベース名 --table=テーブル名

■ログの重複をなくす
import google.cloud.loggingimport logging
# クライアントの作成client = google.cloud.logging.Client()
# Cloud Logging ハンドラを追加client.get_default_handler()client.setup_logging()
# 既存のハンドラをすべて削除for handler in logging.root.handlers[:]:    logging.root.removeHandler(handler)
# 新しいハンドラを追加logging.basicConfig(level=logging.INFO)
# logging.basicConfig(level=logging.DEBUG)  # DEBUG レベルからすべてのレベルを記録
# propagate を無効にして重複を防ぐlogger = logging.getLogger()logger.propagate = False
# 各ログレベルでテストlogging.debug('This is a DEBUG log')logging.info('This is an INFO log')logging.warning('This is a WARNING log')logging.error('This is an ERROR log')logging.critical('This is a CRITICAL log')
■何度かAPIコールを繰り返す
def safe_replace_text(document_id, old_text, new_text, max_attempts=3):    for attempt in range(max_attempts):        try:            replace_text(document_id, old_text, new_text)            break  # 成功した場合はループを抜ける        except Exception as e:            print(f"Attempt {attempt + 1} failed: {e}")            if attempt == max_attempts - 1:                print("Reached maximum attempts.")
■Exponential Backoffで時間を指数級数的にゆらぎながら増やすリトライimport timeimport randomdef exponential_backoff(max_retries=5, base_wait_time=1, max_wait_time=32):    retries = 0    while retries < max_retries:        try:            # APIリクエストの送信            response = send_request()            if response.status_code == 200:                return response  # 成功時に結果を返す        except Exception as e:            wait_time = min(base_wait_time * (2 ** retries), max_wait_time)            wait_time += random.uniform(0, 1)  # ランダムなズレを追加(Jitter)            print(f"Retrying in {wait_time} seconds...")            time.sleep(wait_time)            retries += 1    raise Exception("Max retries reached, request failed")
クォータの増加の依頼もできるが、基本的に下記の上限がある
1. Google Docs API の利用上限

これらの制限を超えると、リクエストが拒否されるか、APIを利用できなくなることがあります。

2. Google Drive API の利用上限
Comment (0)

■23/4/23 9:12PM
Bay Bay Bay
ebayはSellerからオファーがあり値引きしてくる。破壊力あるな。ただ購入が面倒だった。

ebayでの問題1)日本には送ってくれない場合がある2)日本に送ってくれるが住所が日本語だと売主でキャンセルされる決済での問題3)クレカ会社で支払いを止められている場合がある4)Paypalで各種証明書が必要で止められている場合がある(クレカ認証も要るはず5)google payでの決済ができない(クレカ側で止められているのでは?↓
対処
↓1)米国転送住所 shipito.com が使える オレゴン倉庫は消費税が掛からないが有料で月10ドル calの10%弱の消費税が掛からず送料も安くなるので一時契約する ebayに米国住所を登録するには米国電話番号が必要  skypeで毎月300円で発行ができるので一時契約する(MSのoutlookメールID) shipito.comに送付されたら日本に転送依頼をする2)ebayの送付先住所(米国)は英語にする(日本に送付可ならコレなくてもいい) 念のため日本の個人情報住所も英語にする(日本に送付可でもココは英語がいいかも) 念のためebayの言語設定を英語、場所を米国にする(上か下ナビにあるはず)  その後に購入・決済手続きする方がいい3)クレカサイトのFAQで支払いできない時等で検索して対処4)Paypalは各種証明書を登録する。クレカ認証は確か少額課金で検証されるはず5)知らん
shipitoで送料見積もると安かったが、実際に荷物が届くと梱包が大きくかなり高い
米国内転送でshipitoでまとめて荷物一つで送ろうと思ったが、直接日本に送ってくれる相手なら直接の方が安いかもしれず良く考えよ解約すること shipito $10 / skype us phone num 300yen

解約していたはずが、SKYPE.COM/GO/BILL利用国LUで300円請求されていた ログインIDを確認しログインし Manage features| Skype My Account で解約した
SkypeとかGoogleとか詐欺ってるよな

=========

流せるトイレブラシの使い方に「天才かよ」 真似したくなるトイレの掃除術 – grape [グレイプ] (grapee.jp)

昭和100年は、2025年/平成37年/令和7年だ。(昭和64年=平成元年/1989、平成31年=令和元年/2019)
西暦の下2桁から018(レイワ)を引くと令和、23-18=5なので令和5年
Comment (0)

■23/3/15 9:27PM
GMT(Greenwich Mean Time)
[Click for image]
■セイコーPROSPEX SPEEDTIMER Solar Chronograph SBDL097(ペプシ)セイコー プロスペックス SPEEDTIMER SBDL097 | セイコーウオッチ (seikowatches.com)腕時計のベルト調整方法(Cリング式) - YouTube
Cリングが内側下側に入っており無くし易いので気を付ける
6時方向を短くした方がバランスが良い
バックル微調整はバネ棒なので縮めてズラす(バックルから外さない方が面倒がない)
 クロノグラフはストップウィッチで秒針が12時のままが正しい
 スプリットセコンド付
  上ボタンでスタート、下ボタンでラップ、下ボタンで続き
  上ボタンでストップ、下ボタンでリセット
 FとEでソーラー充電上体を表示
 竜頭1段出しで日付、2段目で時刻調整
ソーラ充電電池の寿命は10年とメーカで謳われている、交換は三~四千円で、機械かクォーツの方がいい?

■セイコー5 SPORTS SKX Sports Style GMT SSK001K1SBSC001の海外モデルでブレスレットの中3連がミラー艶出し
各部の名称と主なはたらき (seikowatches.com)
ベルト調整はCリング無しの割ピン仕様
 午後8時から午前4時は日付の調整を行わないこと(朝昼夕方に合わせる、反時計回りは駄目)
 竜頭1段目にして反時計回りで前日の日付にセットし、 竜頭2段目にして時計回りで時刻合わせ  竜頭0段目:ぜんまい巻き上げ(時計回り、回しすぎない方がいいらしい)  竜頭1段目:日付合わせ(反時計回り)・GMT24時針合わせ(時計回り)  竜頭2段目:時刻合わせ
 日本時間の24時間針として使う場合
  ベゼルを時差分ずらすと2か国の時刻が分かる
   GMT針は24時間針で日本時間で、ベゼルを9時始まりにしてUTCの設定が良い    +0900 JST9:00のときUTC0:00、UTCだけどcoordinated universal time
 デュアルタイム針として使う場合
  ベゼルを時差分ずらすと3か国の時刻が分かる(日本時間の長短針/盤面の24時間/ベゼルの24時間)
機械式は面倒、嵌めていないと止まる、時間がズレる、でもソコがカワイイかも
クォーツ+ソーラは100倍便利だが、機械の相棒一本がいいかもな
伝統のUI/ユーザビリティとか、機能美とか様式美に行きつく
[Click for image]
■セイコーNH35A サブマリーナスピードタイマー、GMTとくれば、次はサブマリーナでしょ。ベゼルが酸素ボンベの量を表す、潜水開始時に分針をベゼルの0を合わせると何分経ったか分かる、ベゼルは逆回転しないので誤って廻っても分数が加算されるだけ
 時間合わせは5Sportsと同じ、ねじ込み式リューズで先に緩める
 ブレスレットのネジは精密ドライバ1.4mmが良かった、小さいとナメるよ
 グライドロック:ブレスレットの微調整は動く方をパキっと持上げて好きな位置迄スライドさせて押し込む
フルスペック!!
 Superior grade 904 stainless steel construction Sapphire crystal with clear anti reflective undercoat Ceramic bezel insert Solid link bracelet with screw pins and solid end links Case size is 40mm, lug width 20mm
■セイコー5 SPORTS Skz209 7S36-01E0(Blue atlas Landshark)トリッキーなガジェットでヤバいな。回転式コンパスチャプターリング(方位計)、200m water resistant、7S36自動巻き、デイデイト表示、回転式ダイバーズベゼル、ねじ込み式リューズ
方位計の使い方1)時計を水平にして時針を太陽の方向に合せる。この時、時針の指す方向と、12時の中間の方向が南2)回転ベゼル(方位計)を回しSを南の方角に合せると、おおよその全方位がでる
※緯度や季節によってはズレが生じることがある
日付は「午前0時」ごろ、曜日は「午前4時」ごろ送るようになっている
 午後8時から午前4時は日付の調整を行わないこと(朝昼夕方に合わせる、反時計回りは駄目)
 竜頭1段目にして反時計回りで前日の日付、時計回りで前日の曜日にセットし、 竜頭2段目にして時計回りで時刻合わせ  竜頭0段目:ぜんまい巻き上げがない
ベゼルが回らないとき(そもそも反時計回りにしか回らない) アルカリ電解水を入れ何度かやって汚れを取る(不要な部分に浸み込まないように)
 シリコンスプレーを吹く(ベゼルに吹くと若干色が戻り艶がでる)
 SEIKO SKX ブラックボーイのベゼル外して掃除&ブレス交換します! - YouTube
  セロテープをコジリの器具の方に
  時計本体にマスキングテープ
  こじる場所がある場合もある
[Click for image]残るはエクスプローラー/デイトかくらいか、知らんけど、圧倒的にレディーがいいなロレックスデイトジャスト、28mmで濃縮されてる感じで、39/36と28でお揃いとかええけどな。バンド種類の名前:Oyster/Presidential/Jubilee
[Click for image]

■カシオDATA BANK DBC-611
QW-3228 (casio.jp)説明書
左側上Aボタンでモード切替:データバンク>計算>アラーム>ストップウォッチ>DT=デュアルタイム
右側下Cボタン:操作音ONOFF
右側上Lボタン:ライト点灯
戻る:÷、進む:+
アラーム5つと時報がセットできる、Aボタンでセット、鳴るセットでAL-1~5が表示
時報セットでSIGが表示、Cボタンでアラーム時報ONOFF

■カシオ ワールドタイム AE-1200WH-1AV
QW-3198_3299 (casio.jp)説明書

■MOD
SEIKO 5 .club
DLW MODS - Seiko Watch Modification Parts (dlwwatches.com)
SeikoMods: Seiko Mod Parts & Watch Mod Parts UK
Seiko Mod Parts | Watch-Modz
Comment (0)

Navi: <  4 | 5 | 6 | 7  >
-Home
-Column [128]
-Europe [9]
-Gadget [77]
-Web [133]
-Bike [4]

@/// BANGBOO BLOG ///