Visual Studio 2015 インストーラ他

なんだかもう仕事がいやになりました。
色んなことが進みません。

サーバと接続できないし、Visual Studioもインストールできないし・・・

なんで、最新バージョンしかださず、古いバージョンも簡単に表示してくれないんだ!
必要なんだよ!!!

と、怒っていたが、すんなり行くときはいくもので。
とりあえず2015バージョンのダウンロードページを見つけたので貼っておく。

https://my.visualstudio.com/Downloads?q=visual%20studio%202015&wt.mc_id=o~msft~vscom~older-downloads

結局ダウンロードするには、Microsoftのアカウントが必要・・・

PowerShell覚書 指定IPアドレス+ポート番号で接続確認

Windowsのコマンドプロンプトでpingをたたけば、そのIPアドレスと通信できるかがわかるが、ポート番号まで見てくれはしない。
IPアドレスとポート番号で通信できるか確認するときは、Powershellを使うらしい。

test-netconnection {IPアドレス} -port {ポート番号};

例)

test-netconnection 1.2.3.4 -port 5432;

で、実行すると以下のようなメッセージが返ってくる。

OKの時

ComputerName : 1.2.3.4
RemoteAddress : 1.2.3.4
RemotePort : 8080
InterfaceAlias : Wi-Fi
SourceAddress : 172.22.128.11
TcpTestSucceeded : True ←つながりました!

NGの時

警告: TCP connect to (1.2.3.4 : 3306) failed
警告: Ping to 1.2.3.4 failed with status: TimedOut

ComputerName : 1.2.3.4
RemoteAddress : 1.2.3.4
RemotePort : 3306
InterfaceAlias : Wi-Fi
SourceAddress : *.*.*.*(こっちのアドレス)
PingSucceeded : False  ←ダメでした
PingReplyDetails (RTT) : 0 ms
TcpTestSucceeded : False  ←ダメでした

サイトタイトル変更

はじめは撮った写真をアップして色々メモを残すためのブログだったが、もう仕事とかの備忘録になったので、記載内容にタイトルを合わせるするため変更した。
「Easy Photo Blog」改め、「My備忘録」。

安直やな・・・

Windows覚書 タスクスケジュール一覧の取得コマンド

基本

schtasks /query

CSV形式でファイル出力(/Vで詳細まで出力させる)

schtasks /query /V /FO CSV > d:\schtasklist1.csv

CSV形式でファイル出力(/Vで詳細まで出力させる,/NHで列タイトル非表示)

schtasks /query /V /NH /FO CSV > d:\schtasklist2.csv

こう見ると、タスクスケジューラにはいっぱいタスクが登録されているのだなぁ・・・と思った。

Docker覚書 VMWareが使えない・・・のときの対処

VMWare Workstationを起動して、仮想環境を立ち上げようとしたらエラーが出た。

あぁー、Dockerを入れた所為だなぁ・・・
というので、Dockerをアンインストールしようかと思ったが、一旦Dockerを使えなくしてしまう方法を探し、以下の手順でVMWareを無事起動できるようにした。

  1. タスクバーの検索アイコンをクリックして「ローカルグループポリシーの編集」と入れて、ローカルグループポリシーにアクセス
  2. コンピューターの構成>管理用テンプレート>システム>Device Guardを選択し、「仮想化ベースのセキュリティを有効にする」の設定を無効にする。
  3. 次はコントロールパネル>プログラム>Windowsの機能の有効化または無効化をクリック。
  4. Hyper-Vのチェックを外す(下層もすべて外す)
  5. 適用ボタンをクリックすると、再起動するかどうか聞かれるが、ここでは再起動しない。
  6. コマンドプロンプトを念のため管理者権限で開いて、以下のコマンドを打つ。
    (Xドライブを作成するので、Xドライブががないことが前提。もしXドライブがすでにある場合は、「X:」の箇所を別のドライブに変更して実行。)

    mountvol X: /s
    copy %WINDIR%\System32\SecConfig.efi X:\EFI\Microsoft\Boot\SecConfig.efi /Y
    bcdedit /create {0cb3b571-2f2e-4343-a879-d86a476d7215} /d “DebugTool” /application osloader
    bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} path “\EFI\Microsoft\Boot\SecConfig.efi”
    bcdedit /set {bootmgr} bootsequence {0cb3b571-2f2e-4343-a879-d86a476d7215}
    bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} loadoptions DISABLE-LSA-ISO,DISABLE-VBS
    bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} device partition=X:
    mountvol X: /d
    

    PCによっては、以下のコマンドを打つ。

    bcdedit /set hypervisorlaunchtype off  
    

    参考URL「あさまのブログ VMWare仮想マシン起動時に「Device/Credential Guard には互換性がありません。」のエラー解決」

  7. そしてようやくPC再起動。
    (再起動後はDockerは使えなくなる。)

で・・・

これでVMWare Workstationが動くか!と思ったら動かなかった・・・

しょうがないので、VMWare Workstationを再インストール。で、うまくVMWareの仮想環境が起動できた。
ん~、PC再起動でうまくいくって書いてあったんだけど、なんか変なことやらかしたかな。
まぁ、でも取りあえずはVMWareがうまく動いたので一安心。
で、最終的にはDockerをアンインストールしようと思うのだが、なにかうまい手はないか、と思っていたら、VMWare上のLinuxにDockerをいれるという手順を紹介している人がいて、「あぁ、なるほどな」などと感心してしまった。
また時間があったら試す予定。
まだDocker環境上へのDeployを試してない。これが肝心なのに。

Docker覚書 Win10にインストールの巻

そろそろDockerぐらい使えないと!と思って、仕事が暇な今こそ!とチャレンジ。
で、WordpressとMySQLの環境を作って繋げてやろうと意気込んで開始して、後述する手順でうまくいった。

ただ、後から分かったが、同じ環境でVMWare Workstationも使っているので、Dockerを動かしている間はVMWare側は動かせない・・・
しまった!!!
と思いつつ、とりあえずはDockerインストールと環境立ち上げの手順だけの備忘録を投稿。

Windows10でDocker上にWordPressを立ち上げる

  1. Docker CE → Desktop Docker for Windows インストール
  2. Desktop Dockerを起動、Setting
    • スタートメニュー等よりDesktop Dockerを起動
    • タスクバーにDockerアイコンが表示されたらアイコンを右クリックしてSettingをクリック
    • DaemonのExperimentalにチェックしApply
    • NetworkのDNS ServerはFixed:を選択して「8.8.8.8」を設定
    • ResetでRestart Docker…をクリック
  3. コマンドプロンプトを起動
  4. Imageの取込コマンド実行(次のrunコマンド実行でimageがなかったら自動的に取り込むのでここは省略できる。)
    • docker pull mysql:5.7.25
    • docker pull wordpress:latest
    • docker images で取り込めたかどうか確認
  5. コンテナー作成・起動
    • docker run --name test-mysql -e MYSQL_ROOT_PASSWORD=password -d -p 3307:3306 mysql:5.7.25
    • docker run --name test-wordpress --link test-mysql:mysql -d -p 8081:80 wordpress
      • それぞれ、ポート番号は他と被らない番号にしておきます。
    • docker container ls -a  で作成できたかどうか確認
  6. localhost:8081に接続して確認
    • WordPressの初期設定画面が表示されたら、うまく動作していることになる。

うまくいかないパターン

  • DB接続できない
    • MySQLのバージョンがWordpressと噛み合ってないのが原因

他のDockerコマンド

  • docker exec -it {コンテナ名} /bin/bash
    • Linux上でコマンド操作可能に
    • cat wp-config.php で定義ファイル内の確認
  • docker stop {コンテナ名}  コンテナ停止
  • docker start {コンテナ名}  コンテナ開始
  • docker rm {コンテナ名}  コンテナ削除
  • docker rmi {イメージ名}  イメージ削除

他のLinuxコマンド

  • apt update
  • apt install -y vim (WordPressサーバ上で、VIMを利用する場合)
  • apt install -y procps (MySQLサーバ上でMySQLが動作しているか確認で利用)
  • ps aux (プロセス状態確認)
  • mysql -u root -p (MySQL接続)
  • exit (Linuxから抜ける)

Node.js覚書 外部ファイルの変数定義を参照する

Map変数の設定するデータの量が多すぎて、別のファイルに移せないかなぁと思って調べた。

呼出元

変数

var exp = require('./mapxxx.js');
var mapX = exp.data;

呼出先

ここでは、mapxxx.jsとして保存。
変数定義後、exports.ホゲホゲ = 定義した変数 としておけば、呼出元で使えるようになる。

var maps = new Map([
    ['D01', 'DDDDDD'],
    ['E02', 'EEEE'],
    ........
]);

exports.data = maps;

最後の「exports.***」を忘れて、「うまくいかないぃ~」と思っていたが、こんなにあっさりできるとは。

AWS覚書 Lambda関数を作る(2)~コード編集

SDKを入れたZipをアップロードすると、index.jsがないぜ!とエラーが出るので、ファイルツリーの表示欄を右クリックして、New Fileを選択。
できたファイルの名前をindex.jsに変更して、この中に処理を書いていく。
同じ要領で、package.jsonファイルも作っておく。
このとき、node_modulesフォルダとindex.js、package.jsonは同じフォルダ内に配置する。(違う場所に作ってもD&Dでファイル移動できる。)

index.jsサンプル

LaunchRequestHandlerは、呼出名のみ言われたときの処理。
*******IntentHandlerは、*******Intentに引っかかったときの処理。(*******は任意で。)
その他、HelpやErrorのIntentHandlerは処理部分をLaunchRequestHandlerと同じように記載していく。
今回は、DBアクセスなどがないので、軽量SDK「ask-sdk-core」を利用する。

const Alexa = require('ask-sdk-core');

// --------------------------------------------------------------------
const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
                       .speak('返答内容')
                       .reprompt('質問内容')
                       .getResponse();
  }
};

// customize intent ***************************
const *******IntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === '*******Intent';
  },
  handle(handlerInput) {
    
    var intent = handlerInput.requestEnvelope.request.intent;
    var dat = intent && intent.slots && intent.slots..*****. && intent.slots.*****.value;
    
    return handlerInput.responseBuilder.speak(speechText)
                                       .withSimpleCard('タイトル', '返答内容')
                                       .getResponse();
  },
};
// customize intent ***************************

const HelpIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
      ・・・・(省略)・・・・
  },
};

const CancelAndStopIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
        || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
      ・・・・(省略)・・・・
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
      ・・・・(省略)・・・・
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
      ・・・・(省略)・・・・
  },
};

// --------------------------------------------------------------------
let skill;
exports.handler = async function (event, context) {
    if (!skill) {
      skill = Alexa.SkillBuilders.custom()
                                          .addRequestHandlers( LaunchRequestHandler,
                                                               *******IntentHandler,
                                                               HelpIntentHandler,
                                                               CancelAndStopIntentHandler,
                                                               SessionEndedRequestHandler
                                          )
                                          .addErrorHandlers(ErrorHandler)
                                          .create();
    }

    const response = await skill.invoke(event, context);
    return response;
};

package.jsonサンプル

nameはLambda関数の名前でOK。versionは関数のバージョン。dependenciesに利用するSDKを設定。

{
  "name": "****",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "ask-sdk-core": "^2.7.0"
  }
}

処理を記述後、Alexaからの呼出で想定通りの返答がなされていればOK。
もし、うまくいかないときは、Alexa Developer コンソールのテスト画面に表示される「スキルI/O」の「JSON入力」に出力されるJSONをコピーして、Lambda関数のテストイベントの設定に貼り付けてテストしてみる。
すると、結果のログにエラー内容が出力されるので、そのエラー内容で処理の記載を変更してやればよい。

AWS覚書 Lambda関数を作る(1)~Alexa SDK for Node.js v2

いつの間にかVersion2が出てた。
alexa-sdkからask-sdkに変わってた。

ということで、せっかくなので対応したLambda関数を作ってみようと思ったのだが、SDKを取得するのに相変わらずLinux環境が要るのだ。
簡単にできますよぉ~などという謳い文句とは裏腹に面倒なのだ。

しかし、普段Linuxを使うことのない私にとっては「いい勉強だ」などと半分自分に嘘をつきながら、SDKを取得してみた。
Linuxの環境はAWS EC2インスタンスで用意。
AWSのEC2(Amazon Linux)が便利なところは、ブラウザ上でコマンドが打てる点だ。気が利いている。
(とはいうものの、ブラウザを放置していると、コマンドが打てなくなるという不具合なのか、セッション切れなのかよくわからない現象が起こるので注意が必要。)

起動したら、npmまで入ってない・・・トホホ。
しょうがないからいろいろ入れることに。
※ここから下のコマンドは、上記の通りEC2インスタンス(Amazon Linux)をブラウザでコマンド実行例。

NodeBrewのインストール

NodeBrewはNode.jsのバージョン切替用ツールらしい。そして、NodeBrewを使ってNode.jsのいろんなバージョンを取得し、バージョン切替が簡単にできるのである。
すごいなぁ・・・などと感心。

curl -L git.io/nodebrew | perl - setup
export PATH=$HOME/.nodebrew/current/bin:$PATH
source ~/.bashrc
nodebrew help

で、NodeBrewのヘルプが見られたら、NodeBrewのインストールは完了。これでnpmも入る。

Node.jsのインストール

ここではversion8で利用予定のversion8.10.*のインストールを行う。

nodebrew install v8.10
nodebrew use v8.10
node -v

インストールして、8.10のバージョンを使うよ!と宣言後、nodeコマンドでインストールしたNode.jsのバージョンを確認。

ask-sdkをnpmを使ってインストール

npm install ask-sdk
npm install ask-sdk-v1adapter
npm install ask-sdk-core
npm uninstall aws-sdk

上は例。要らないものは入れなくていい。取得したモジュールはすべてnode_modulesフォルダ内に入る。
AWS-SDKがあると容量が増えてLambda関数にアップロードできなくなるので、削除しておくこと。

ask-sdkをZip圧縮後、S3へアップロード

cd ./
zip -r alexa_ask_sdk.zip node_modules

上の階層に行って、node_modulesフォルダを丸ごとZIP圧縮。
Zipの中身を確認するときは、以下のようにless文を使う。

less alexa_ask_sdk.zip

(コマンド終了は:q)

次はS3へアップロード。これはAWS CLIを使う。
{****}はバケット名。

aws s3 cp alexa_ask_sdk.zip s3://{****}/alexa.zip

S3にアップロードしたzipをLambda関数の関数コードのところで取り込めば、ようやくコードの編集が始められる。
続きは(2)へ。

PostgreSQL覚書 crosstabでPIVOT

PostgreSQLでもOracleのPIVOTみたいなことをやりたいなぁ・・・と思って調べた。
crosstabらしい。
拡張機能らしい。
早速PgAdminで以下のSQLを実行して取り込む。

CREATE EXTENSION IF NOT EXISTS tablefunc;

いくつか関数が追加された中に、crosstabがあればOK。
で、続けてSQLを組み立てる。

今回は以下のように縦並びである店舗日別データ(qty)を全店SUM(qty)にして横並びにしてみる。
tab_shop_qty カラム構成(y |m |d |no |shop | qty)

CREATE TABLE tab_shop_qty (
  y integer,
  m integer,
  d integer,
  no integer,
  shop character varying(10),
  qty numeric(5,0)
);
INSERT INTO public.tab_shop_qty values(2019,1,1,1, 'abc', 10);
INSERT INTO public.tab_shop_qty values(2019,1,1,2, 'abc', 8);
INSERT INTO public.tab_shop_qty values(2019,1,2,1, 'abc', 25);
INSERT INTO public.tab_shop_qty values(2019,1,2,2, 'abc', 15);
INSERT INTO public.tab_shop_qty values(2019,1,1,1, 'efg', 12);
INSERT INTO public.tab_shop_qty values(2019,1,1,2, 'efg', 7);
INSERT INTO public.tab_shop_qty values(2019,1,1,2, 'efg', -2);
INSERT INTO public.tab_shop_qty values(2019,1,2,1, 'hij', 20);

店舗(shop)別に、日毎のqtyを横に並べる

SELECT c.shop,c."1",c."2",...,c."31"
FROM crosstab(
      'SELECT shop,d,SUM(qty) qty FROM tab_shop_qty WHERE y=2019 AND m=1 GROUP BY shop,d ORDER BY 1'
     ,'SELECT d FROM generate_series(1,31) d'
     )  
AS c(shop varchar,"1" numeric,"2" numeric,...,"31" numeric) 
ORDER BY c.shop

上の例だと、shopというカラム1つだけがキーになっているのでこのようなSQLで済むのだが、キーが複数カラムある場合は、第1引数のSQL文にORDER BY句を追加するという工夫が必要。

店舗,NO(shop,no)別に、日毎のqtyを横に並べる

SELECT c.shop,c.no,c."1",c."2",...,c."31"
FROM crosstab(
      'SELECT shop,no,d,SUM(qty) qty FROM tab_shop_qty WHERE y=2019 AND m=1 GROUP BY shop,no,d ORDER BY 2'
     ,'SELECT d FROM generate_series(1,31) d'
     )  
AS c(shop varchar,"1" numeric,"2" numeric,...,"31" numeric) 
ORDER BY c.shop,c.no

ドキュメントurl: https://www.postgresql.jp/document/9.6/html/tablefunc.html では、
第1引数のORDER BY句は
「実際は、同じrow_name(キー項目のこと)を持つ値をまとめられるように、source_sql(第1引数のSQL文のこと)問い合わせでは常にORDER BY 1を指定すべきです。」
との記載があるが、「ORDER BY 1」なのであれば指定ありとなしでは変わりはなかった。

結局、ORDER BYの指定の仕方がイマイチわからなかったが、ORDER BYの1つめで指定したカラム数まではキー、次が第2引数のデータとの関連付け用、その次がPIVOTとして出力するデータ、かな・・・などと思った。

————————
<2019/08/08 追記>
いろいろ試していた時に発覚したことがあったので追記。
crosstabの第1引数のSQL文だが、グルーピングするカラムのうち、1つでもデータが1種類しかないカラムが存在した場合、うまく動作しないことが分かった。
上の説明文だと自分で後から見直しても、なんのこっちゃ!って思うと推測するので、追記しておくと・・・・
最後の例だとshop,noの2カラムがグループ,dが横並びにするカラム,qtyが横並びにするデータとなるのだが、
テーブルのレコードにshop=’abc’のデータ1種類しかない場合、crosstabがうまく動作しないということがある、ということだ。
ORDER BY 2までならうまくいくかもしれないが、少なくとも私が試してみたORDER BY 3(つまりグルーピングするカラムが3列)の場合、うまくマージされず、本来は何全行と出るはずの結果レコードが1行しか出てこない始末となった。

う~ん、なんとかなんないのだろうか。他にうまくできる方法を探さなければ、「関数作成してカーソル利用」しか思いつく方法がない・・・

2019 クーラーをつけた日

今年はそんなに暑くないのだが、そろそろムシムシするので、と6/29にはクーラーをつけてしまった。
去年まではスプレーをプシューとしてから稼働させたのだが、今年はスプレーがなくてしょうがなく掃除しないままで稼働。
といっても、毎年そんなに汚れてないのは知っているので、今年はいいかなぁ・・・などとつけてみた。

うん、特に必要なさげ。
と、思ってるだけだが、本当はすごいカビ菌が繁殖してるかも。

というのは、窓の周りがカビだらけになっていることに、ハタと気づいてしまったので、クーラーも・・・となっているのである。
窓周辺のカビをふき取って、とりあえず湿気とりを簡易的に配置してみた。

後はカーテンを付け替えないといけない・・・

あー、カビは本当にヤダ。
やっぱり除湿機を買うべきだろうか。あぁ買うべきなんだろうな・・・

この半年

この前の投稿から半年が過ぎた。
暇なときは書くことがないし、書きたいことがあるときは暇でない、というありきたりな理由なのだが、もう梅雨時になってしまった。

私はこのブログにエアコンをつけた日をメモしているのだが、今年はなんだろうか6月の始めにはもうエアコンをつけてやろうか!と思うぐらい暑かった。
まだそんなに暑いわけでもないのだろうに暑く感じたので、熱かな、とか、更年期かな・・・とか思ったり。
女でも男でも更年期はあるらしい。
ちなみに、生理に似た症状も男にあるらしいことは昨日知った。
でも、まだ違った。

そんな話はともかく、とりあえずまだエアコンは付けず、氷をドバっといれた炭酸水を飲んで乗り切っている。

この半年はいろいろあった。
正月明けから、同僚がiPhoneが壊れて修理に出した話をきいたのだが、その次の週には私のiPod Touchが壊れた。
新しいiPod TouchをAppleがさっさと出さないせいだ!と修理に出して直してもらったのたが、5月ようやく待望の新バージョンが発売になった。
そして新しいiPod Touchを買う準備をしていたのだが、持っているPocketWiFiの契約を解除して、別会社に乗り換えたらタダ同然でiPhon6sが手に入ったので、iPodはもう用無しになってしまった。
iPod Touchはホント軽くて薄くてちょうどいいんだよね。ディスプレイはちょっと小さいけど、WiFiがあればネットにもつながるからちょうどよかったんだけど、iPodからiPhoneへののデータ移行が無事済んだので、iPhoneとiPodの2台持ちは無駄でしかない。
ちょっと寂しいが、とりあえず私のiPod遍歴はこれにて一旦終了なのだ。

そしてiPodが壊れたその後すぐにバイクが壊れた。乗ってる最中にチェーンが外れて、バイク屋さんに取りに来てもらった。
直ったあとのギアチャンジの快調さに、なんでもっと早く交換してもらわなかったのかと反省した。
乗れているからいい、ってわけじゃないんだな。
乗ってる最中に壊れたのだがコケることもなかったので、周囲に迷惑をかけずに済んでよかった。
(バイク屋さんには迷惑かけたけど)

同僚がiPhoneを無くしたときいてから数日後、私は財布を落とした。
こんな話ばっか、みたいな感じだが、すぐに無くした場所に戻れたので、財布はすぐに手元に返ってきた。
別の同僚が同じ日に財布を落として、それもすぐに見つかったらしい。
そんな話ばっか、みたいな感じだった。
まぁ、すべて手元に戻ってきたので良かったのだが、気をつけねば。

ということで、今年はろくでもないなぁという年だが、ちょっとずつ頑張っていくさ。

JQuery3覚書 属性・階層と付き合う

HTMLを初めて触ったのは22とか23の頃で、もう20年以上前の話になってしまった。
そのころはタグは大文字で書くのが普通だった。

いつの間にかIDやNAME、CLASSでスタイルを指定できる世の中になってしまった。
タグは小文字で書くのが当然になった。

そして今、属性を自分で勝手に作ってデータ操作する時代。
jsのライブラリもいっぱい世の中に出回っているが、何をやっているのかわからないやら、余計なことをするわで、結局自分でゴリゴリ作った方がカスタマイズしやすいんではないのか?などと後戻りできない旅路の一歩をを踏み出してしまう。

■ 属性

例えばの以下のようなテーブル構成の場合でいうならば、「data-no」というのが勝手に作った属性。
この属性の設定値を取得する方法をメモする。

<table id="tab1">
    <thead>
        <tr>
            <th data-no='1'>COL1</th>
            <th data-no='2'>COL2</th>
            <th data-no='3'>COL3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-cd="101">DATA1-1</td>
            <td data-cd="102">DATA1-2</td>
            <td data-cd="103">DATA1-3</td>
        </tr>
        <tr>
            <td data-cd="201">DATA2-1</td>
            <td data-cd="202">DATA2-2</td>
            <td data-cd="203">DATA2-3</td>
        </tr>
    </tbody>
</table>

JQueryで、thタグをクリックしたときに、そのdata-noが何かをアラート表示させてみる。

    $(document).on('click', '#tab1>thead>tr>th', function (event) {
        alert($(this).attr('data-no'));
    });

これは、以下のように書いても問題はないのだが、もし当該テーブル、あるいはテーブルの要素が動的であった場合は、CLICKイベントが検知できないので、上記のように書いた方が汎用的のよう。

    $('#tab1>thead>tr>th').on('click', function (event) {
        // (記載略)
    });

対象の指定は下のように省略して書いても、tbodyタグにthがないときは問題ない。

    $('#tab1 th').on('click', function (event) {
        // (記載略)
    });

なお、attrは、attr({要素名})とすると、指定した要素の値があればその設定を返し、ないときはundefindedを返す。
そして、指定した要素に値を設定するときは、 attr({要素名}, {設定値}) とする。


■ 階層(親・子)

次に階層(親・子)を考慮しながら値を取る方法をメモしておく。
はじめにイベントの対象要素を「$(‘#tab1>thead>tr>th’)」と、恩着せがましく記述したのだが、これは親子関係をわかりやすくするためでもある。

#tabの子供がthead、その子供はtr、その子供はth

ということで、逆に言うと、thの親はtr、trの親は・・・と、もう書かないけどそんな感じ。

> 階層(親)

親は簡単に取れる。なんせ1つだから。

親である(tr)のHTML記述内容をアラート表示させてみる。

    $(document).on('click', '#tab1>thead>tr>th', function (event) {
        alert($(this).parent().html());
    });

簡単。親の親(thead)はparent().parent()。
親の親の親(#tab1)なら、parent().parent().parent()ということに。もはやfor文でも使った方がよさそうだ。

> 階層(子)

子の取り方はいろいろ。

試しに#tab1 tbody tr の行をクリックしたら、子要素(td)を順番にとって、コンソールに出力してみる。

    $(document).on('click', '#tab1>tbody>tr', function (event) {
        $(this).children().each(function (event) {    // (a)
            console.log($(this).html());              // (b)
        });
    });

(a)の$(this)は「tr」の要素のこと。
(b)の$(this)は子要素「td」のこと。
これだと、trの子要素はすべて取得できるので、tdとthの両方のタグがある場合は両方とも取得できる。

    $(document).on('click', '#tab1>tbody>tr', function (event) {
        $(this).children('td').each(function (event) {
            console.log($(this).html());
        });
    });

これだと、trの子要素のうちtdタグのみを取得できる。

    $(document).on('click', '#tab1>tbody>tr', function (event) {
        $(this).find('td').each(function (event) {
            console.log($(this).html());
        });
    });

findだと、引数で指定した要素であれば、子要素でも、孫要素でも範囲内すべてから取得可能になる。
サンプルだとテーブルの中にテーブルを入れ子していないので、子要素のみ取得できる。

children()を使うか、find()を使うかは子要素だけなのか、関係なく下の階層すべてに適用するのかで決める。

> 階層(子要素のn個目)
    $(document).on('click', '#tab1>tbody>tr', function (event) {
        $(this).children('td:nth-child(2)').each(function (event) {
            console.log($(this).html());
        });
    });

childrenで対象を指定するときに「:nth-child({n})」を使うと、n番目の要素だけ取得できる。

今日はここまで。次はソートについてメモせねば。

JQuery3覚書 初歩的なこと

歩道を歩いていて、前のヤツがタバコ吸うとこっちは受動喫煙になる。
もっとも、周りに気使う喫煙者は、路上や屋外で喫煙はしない。
路上や屋外で喫煙する奴は基本的にアホです。ハイ。ハッキリ断言します。
周りに人がいる、来るかもしれない場所での喫煙はやめましょう。ただの迷惑。

久しぶりの投稿の冒頭がこれかい!って感じですが、いつになったら分かるんでしょうねって思うので書いてみた。

で、JQuery。
今使っているのはバージョンは3.3.1。
色々データをこねくり回さなければいけないということで、ネットを検索しながらHTML/CSS/JSのファイルを作成。
今頃気づいたのだが、JavaScriptとJQueryは別モノ。
当たり前なのだが、JQueryで取得した要素に、JavScriptの標準メソッドを適用させようとするとエラーになる。

$('#table1').innerHTML 

これはダメ。左はJQuery、右はJavaScript標準。

$('#table1').html()

これはJQueryの記述方法で、OK。

document.getElementById('table1').innerHTML 

これはJavaScript標準の記述方法で、OK。

という話なのである。

松竹新喜劇パート2

9月の大阪松竹座の公演は松竹新喜劇の70周年記念公演。

松竹新喜劇70周年
松竹新喜劇70周年

見てきた。

よかった。
めっちゃよかった!

『人生双六』
感動!
自分が子供のころTVでみたのは、藤山寛美・高田次郎だったように記憶している。
当然今はキャストが変わっていて、行ったときは扇治郎・植栗コンビだった。
(役替わりで次の日は扇治郎・天笑だったらしい。天笑さんのも観たかった!)

昔ながらの芝居を今の人がやるっていうのは、なんだか嬉しいな。
ずっとこういう芝居が続いていってほしいな、と改めて感じた。
ただ、若いからか芝居にまだ遠慮が感じられる。もっとぐぐっと思い切って演じてもいいようにも思う。

~ご挨拶~
いやぁ、高田次郎、小島慶四郎米寿コンビが元気で何より。
小島さんはイマイチおぼつかないが、高田さんのあのしっかりした姿はすごいな。
いい歳の取り方をしている人の代表だなぁ、としみじみ。

そして文童さん。
久しぶりに見たけど、この人もいい歳の取り方してるなぁ。
天外・文童2枚看板だったころは、自分はまだ若くてとても芝居を見に行くなんてできなかった時期だった。
たぶん、世の中も結構大変な時期だったと思う。
でも、そういうときにメンバーもそうだけど一生懸命頑張ってくれてたおかげで、今私たちは松竹新喜劇をみられるんだと思うと、本当に皆さんありがとう!と感謝しかない。

『八人の幽霊』
この演目は初めて見た。
寛太郎さんメインのお芝居。
天外さんがワンポイントで出てくるんだが、ちゃんと魅せてくれる。さすが。
楽しいお芝居だった。

2019年の1月もまた、新喜劇やるそうなので、こちらも観にいく!
絶対観にいくぞ!

Excel VBA覚書 クリップボード

クリップボードに文字列を貼り付けるときに、貼り付かないケースがあったので、
別の方法を調べてみた。

String型変数 buf の内容をクリップボードに設定するということで・・・
a) DataObjectを使う方法1

        Dim cb As Object
        Set cb = New DataObject
        cb.SetText buf
        cb.PutInClipboard

b) DataObjectを使う方法2

        With New MSForms.DataObject
            .SetText buf
            .PutInClipboard
        End With

c) TextBoxを使う方法

       With CreateObject("Forms.TextBox.1")
          .MultiLine = True
          .Text = buf
          .SelStart = 0
          .SelLength = .TextLength
          .Copy
        End With
        If cb.CanPaste Then cb.Paste

Access覚書 リンク貼替

結構間が開いてしまった。
1か月に1度ぐらいはせめて投稿しようと思いつつ。

テーブルやらクエリやらがAサーバのDBをみているのだが、Bサーバのテスト環境のDBをみるように変えたい
となったとき、結構大変である。
標準機能で変更できるのかどうか、やり方がわからん。

ということで、VBAでできないか探してみたら、やはり一括でどべっと変更できるやり方があった。

' テーブルとクエリのリンク先を変更
' 引数 :from_srv = 変更前(例:172.0.0.1)
'    :to_srv   = 変更後(例:196.128.1.10)
Sub ChangeLinks(from_srv As String, to_srv As String )

    Dim db As DAO.Database
    Dim tb As DAO.TableDef
    Dim qr As DAO.QueryDef
    
    Set db = CurrentDb
    On Error Resume Next
    For Each tb In db.TableDefs
        If tb.Connect <> "" Then
            tb.Connect = Replace(tb.Connect, from_srv , to_srv)     'サーバ変更
            tb.RefreshLink  ' テーブルはリフレッシュ
        End If
    Next
    For Each qr In db.QueryDefs
        If qr.Connect <> "" Then
            qr.Connect = Replace(qr.Connect, from_srv , to_srv)     'サーバ変更
        End If
    Next
End Sub

パスワードとかだと、
Replace(tb.Connect, “PWD=***”, “PWD=***”)
ってな感じで変換してやる。

松竹新喜劇

大阪人だからか、新喜劇が好きだ。
といっても、吉本の、ではなく松竹の。

子供のころは週1必ず舞台中継(録画)をやっていて、それを毎週欠かさずといっていいほど観ていた。
そのせいか、やはり今でも「松竹新喜劇」をみたいのである。
吉本はお笑い優先でちょびっと人情もんなんだけど、松竹はどっちかというと人情もんプラス笑い。

で、新喜劇が松竹座であるっていうから観にいってみたのだが、なんだかミュージカル?活劇?。
「新喜劇も進化したんだなぁ~」とは思ったのだが、なんだか「松竹新喜劇」じゃなかった。
なんか違った。

こんなんじゃないんだよ、松竹新喜劇は・・・

客層も思ってたのと違うし。なんか、ミュージカル客ばっかり。
ミュージカルの観方はそうなんだろうけどね、新喜劇の観方はちょっとちゃうんやで、と思った。

ミュージカルの客ってのは、なんというか、厚かましいんだな。
セリフもうしゃべってまっせ!ってなときも拍手でセリフが聞こえないわ、拍手で芝居の流れも止めてるわ。
そして、終了のアナウンスがあってもまだアンコールしてる。
終了のアナウンスがあったら、出ていけってことやねん。分らんかな、そういうの。ほんま、遠慮せんな。

ふん、そうさ、私の心の狭さは人一倍だよ。
でも、いままでいろんな舞台を見てきたけど、ミュージカルは出ている演者も客もそういう厚かましい人の寄せ集めなんだなぁ、と思う。

だって、矢鱈目ったら手拍子するよね、ミュージカル客。
演者は演者で、客がのせてくれたら演者もノリよくパフォーマンスができる!みたいなこと平気で言うし。
気持ちはわからなくないけど、客がどうだろうが、自分が盛り上げればいいんだよね。
そういうことちゃんとやる人に仕事がくるんだから。

ということで、新喜劇がみたいんだよ!って調べたら、9月に新喜劇をやるらしい!
よっしゃ、ほんまもんの新喜劇みせてもらいまひょ!
ということで、9月はリベンジするぜ。

やっぱりパンが好き

新しい年度の始まり。
ここ最近は、春というよりなんかいきなり初夏!な感じだったが、まだ肌寒かったりもする中途半端な季節。

最近中津(大阪ね)に行く機会があったのだが、中津ってのはいいね。なんだか。

大きな企業がいっぱいあって、梅田もすぐそばなのに、なんか庶民的。

で、「セ・シュエット」というケーキ屋みたいなパン屋が目に入ったので、さっそく入ってみる。
なんか、ショーケースもケーキ屋!でもパンが並んでる。
いや、ケーキみたいなパンもあるし、お菓子も置いてある。

で、パオガオサンドみたいな名前のバーガーっぽいサンドと、他に何個か購入して試し食い。

うまい!

あぁ、特にパオガオサンドは、あんまし東南アジア風味はしないのだが、バランスがいい。
パンのもちもち感も具にあっている。

あぁ、こんなパン屋近所に欲しい。
中津に引っ越そうかな・・・