昼寝帝国の逆襲

適当に書きます

CentoOS7でRedmineのアカウントを使ってSubeversionとGitの認証をしてみるのすけ

そういえばCentOS7ってどんなもんなんだろうということで個人で使ってるサーバのOSをCentOS7に変えてやりました。

結果:早まった感がある。

Redmine入れるときもgem入れるときにゴネられたりとかSelinuxであれこれありましたけど、その辺はわりと簡単に処理できるので割愛。

RedmineSubversionとGitの認証を共通化したいのは、Apache+Subversionだとパスワードの変更するのにいちいちsshしてファイル書き換えてという面倒があるので、認証をRedmineのアカウントでやってしまえるようにしたいという感じです。

そんで、結構色々な人が書いてるのですが、やり方は2パターンあります。

1.Redmine.pmを使う
2.mod_auth_mysqlを使う

個人的な好みとして、apacheのモジュールでやる方がかっこいいということで、後者の方法でやるんですが、CentOS7でやるとネックなのが

apacheが2.4系
MySQLじゃなくてMariaDB(実際大して変わってないけど)

mod_auth_mysql自体枯れているというか充足しちゃってるので、2005年6月以降更新がないです。

mod_auth_mysql


なので、apache2.4系で素直に動いてくれるわけもないので、パッチ当てたり色々必要になります。

mod_auth_mysql / Patches / #13 Patch for Apache 2.4

2.4系のパッチはここにあります。
その後にRedmineのsaltに対応するパッチを当てないといけないので、余計に面倒さが増すんですが、

SubversionとRedmineのアカウント共通化(プロジェクト毎にグループ化可能) - iWA’s 雑記@はてな出張所

その辺はこちらを参考に。

ソースからコンパイルしちゃえば楽なんですが、rpmあるんだし使いたいということで、rpmをビルドしちゃいたい。

というわけで、

  1. ソース拾ってくる
  2. パッチ当てる
  3. rpmbuild
  4. インストール

という手順でやります。
コマンドの記録するの忘れてたので順番だけですいません。

ソース拾ってくる

本家サイトからだろSPEC書いたり面倒なので、ここはCentOS6.6のsrpmは拝借。

http://vault.centos.org/6.6/os/Source/SPackages/mod_auth_mysql-3.0.0-11.el6_0.1.src.rpm

wget ftp://ftp.pbone.net/mirror/vault.centos.org/6.2/os/Source/SPackages/mod_auth_mysql-3.0.0-11.el6_0.1.src.rpm
rpm -ivh mod_auth_mysql-3.0.0-11.el6_0.1.src.rpm 
パッチ当てる

パッチは先ほど上げた2種なんですが、CentOS6のソースで2.2系に対応するパッチが含まれていて、2.4系対応パッチと内容が一部重複します。
それらのパッチ適用後の内容に合わせてパッチの中身を編集するとこんな感じになります。

内容を編集するとこんな感じ。

--- mod_auth_mysql-3.0.0/mod_auth_mysql.c       2005-06-22 12:17:45.000000000 -0400
+++ mod_auth_mysql-3.0.0_patch_apache_2.4/mod_auth_mysql.c      2013-12-30 18:07:27.646704470 -0500
@@ -237,7 +237,7 @@
   #define SNPRINTF ap_snprintf
   #define PSTRDUP ap_pstrdup
   #define PSTRNDUP ap_pstrndup
-  #define STRCAT ap_pstrcat
+  #define STRCAT apr_pstrcat
   #define POOL pool
   #include <stdlib.h>
   #include "ap_sha1.h"
@@ -907,7 +907,7 @@
 }

 static char * format_remote_ip(request_rec * r, char ** parm) {
-  return r->connection->remote_ip;
+  return r->connection->client_ip;
 }
 
 static char * format_filename(request_rec * r, char ** parm) {
@@ -1272,7 +1272,7 @@
   int method = r->method_number;
 
 #ifdef APACHE2
-  const apr_array_header_t *reqs_arr = ap_requires(r);
+  const apr_array_header_t *reqs_arr = NULL;
 #else
   const array_header *reqs_arr = ap_requires(r);
 #endif

diffの結果はこんな感じ

2a3,11
> @@ -206,7 +206,7 @@
>    #define SNPRINTF apr_snprintf
>    #define PSTRDUP apr_pstrdup
>    #define PSTRNDUP apr_pstrndup
> -  #define STRCAT ap_pstrcat
> +  #define STRCAT apr_pstrcat
>    #define POOL apr_pool_t
>    #include "http_request.h"   /* for ap_hook_(check_user_id | auth_checker)*/
>    #include "ap_compat.h"
12c21,130
< @@ -907,7 +907,7 @@
---
> @@ -589,87 +589,87 @@
>  static
>  command_rec mysql_auth_cmds[] = {
>       AP_INIT_TAKE1("AuthMySQLHost", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlhost),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlhost),
>       OR_AUTHCFG, "mysql server host name"),
>  
>       AP_INIT_TAKE1("AuthMySQLPort", ap_set_int_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlport),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlport),
>       OR_AUTHCFG, "mysql server port number"),
>  
>       AP_INIT_TAKE1("AuthMySQLSocket", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlsocket),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlsocket),
>       OR_AUTHCFG, "mysql server socket path"),
>  
>       AP_INIT_TAKE1("AuthMySQLUser", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqluser),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqluser),
>       OR_AUTHCFG, "mysql server user name"),
>  
>       AP_INIT_TAKE1("AuthMySQLPassword", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlpasswd),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlpasswd),
>       OR_AUTHCFG, "mysql server user password"),
>  
>       AP_INIT_TAKE1("AuthMySQLDB", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlDB),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlDB),
>       OR_AUTHCFG, "mysql database name"),
>  
>       AP_INIT_TAKE1("AuthMySQLUserTable", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlpwtable),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlpwtable),
>       OR_AUTHCFG, "mysql user table name"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupTable", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlgrptable),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlgrptable),
>       OR_AUTHCFG, "mysql group table name"),
>  
>       AP_INIT_TAKE1("AuthMySQLNameField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlNameField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlNameField),
>       OR_AUTHCFG, "mysql User ID field name within User table"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupField),
>       OR_AUTHCFG, "mysql Group field name within table"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupUserNameField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupUserNameField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupUserNameField),
>       OR_AUTHCFG, "mysql User ID field name within Group table"),
>  
>       AP_INIT_TAKE1("AuthMySQLPasswordField", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlPasswordField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlPasswordField),
>       OR_AUTHCFG, "mysql Password field name within table"),
>  
>       AP_INIT_TAKE1("AuthMySQLPwEncryption", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlEncryptionField),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlEncryptionField),
>       OR_AUTHCFG, "mysql password encryption method"),
>  
>       AP_INIT_TAKE1("AuthMySQLSaltField", ap_set_string_slot,
> -     (void*) APR_XtOffsetOf(mysql_auth_config_rec, mysqlSaltField),
> +     (void*) APR_OFFSETOF(mysql_auth_config_rec, mysqlSaltField),
>       OR_AUTHCFG, "mysql salfe field name within table"),
>  
>  /*   AP_INIT_FLAG("AuthMySQLKeepAlive", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlKeepAlive),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlKeepAlive),
>       OR_AUTHCFG, "mysql connection kept open across requests if On"),
>  */
>       AP_INIT_FLAG("AuthMySQLAuthoritative", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlAuthoritative),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlAuthoritative),
>       OR_AUTHCFG, "mysql lookup is authoritative if On"),
>  
>       AP_INIT_FLAG("AuthMySQLNoPasswd", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlNoPasswd),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlNoPasswd),
>       OR_AUTHCFG, "If On, only check if user exists; ignore password"),
>  
>       AP_INIT_FLAG("AuthMySQLEnable", ap_set_flag_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlEnable),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlEnable),
>       OR_AUTHCFG, "enable mysql authorization"),
>  
>       AP_INIT_TAKE1("AuthMySQLUserCondition", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlUserCondition),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlUserCondition),
>       OR_AUTHCFG, "condition to add to user where-clause"),
>  
>       AP_INIT_TAKE1("AuthMySQLGroupCondition", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupCondition),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupCondition),
>       OR_AUTHCFG, "condition to add to group where-clause"),
>  
>       AP_INIT_TAKE1("AuthMySQLCharacterSet", ap_set_string_slot,
> -     (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlCharacterSet),
> +     (void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlCharacterSet),
>       OR_AUTHCFG, "mysql character set to be used"),
>  
>    { NULL }
> @@ -905,7 +905,7 @@
14c132
< 
---
>  
21c139
< @@ -1272,7 +1272,7 @@
---
> @@ -1270,7 +1270,7 @@

で、Redmine対応パッチも行数だけ直しておきます。

--- mod_auth_mysql-3.0.0/mod_auth_mysql.c.redmine
+++ mod_auth_mysql-3.0.0/mod_auth_mysql.c
@@ -288,6 +288,7 @@
 static short pw_aes(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
 #endif
 static short pw_sha1(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
+static short pw_sha1_rm(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
 static short pw_plain(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
 
 static char * format_remote_host(request_rec * r, char ** parm);
@@ -318,7 +319,8 @@
 #if _AES
                                           {"aes", SALT_REQUIRED, pw_aes},
 #endif
-                                          {"sha1", NO_SALT, pw_sha1}};
+                                          {"sha1", NO_SALT, pw_sha1},
+                                          {"sha1-rm", SALT_OPTIONAL, pw_sha1_rm}};
 typedef struct {               /* User formatting patterns */
   char pattern;                        /* Pattern to match */
   char * (*func)(request_rec * r, char ** parm);
@@ -858,6 +858,42 @@
   return  strcasecmp(bin2hex(pool, scrambled_sent_pw, enc_len), real_pw) == 0;
 }
 
+/* checks SHA1 passwords - adjusted for use with redmine */
+static short pw_sha1_rm(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
+  char salt_and_pw[500];
+  char scrambled_pw[500];
+  char *scrambled_sent_pw, *buffer=PCALLOC(pool, 128);
+  char *scrambled_salt_pw, *buffer01=PCALLOC(pool, 128);
+  short enc_len = 0;
+  short enc_len01 = 0;
+#ifdef APACHE2
+  apr_sha1_base64(sent_pw, strlen(sent_pw), buffer);
+  buffer += 5;   /* go past {SHA1} eyecatcher */
+  scrambled_sent_pw = PCALLOC(pool, apr_base64_decode_len(buffer) + 1);
+  enc_len = apr_base64_decode(scrambled_sent_pw, buffer);
+  //scramble (salt+scrambled_pw) for redmine:
+  strcpy(salt_and_pw,salt);
+  strcpy(scrambled_pw,bin2hex(pool, scrambled_sent_pw, enc_len));
+  //conver scrambled_pw to lower:
+  int i;
+  for (i = 0; scrambled_pw[i]; i++)
+  scrambled_pw[i] =tolower(scrambled_pw[ i ]);
+  //cat salt + scrambled_pw:
+  strcat(salt_and_pw,scrambled_pw);
+  apr_sha1_base64(salt_and_pw, strlen(salt_and_pw), buffer01);
+  buffer01 += 5;   /* go past {SHA1} eyecatcher */
+  scrambled_salt_pw = PCALLOC(pool, apr_base64_decode_len(buffer01) + 1);
+  enc_len01 = apr_base64_decode(scrambled_salt_pw, buffer01);
+#else
+  ap_sha1_base64(sent_pw, strlen(sent_pw), buffer);
+  buffer += 5;   /* go past {SHA1} eyecatcher */
+  scrambled_sent_pw = PCALLOC(pool, ap_base64decode_len(buffer) + 1);
+  enc_len = ap_base64decode(scrambled_sent_pw, buffer);
+#endif
+  scrambled_sent_pw[enc_len] = '\0';
+  return  strcasecmp(bin2hex(pool, scrambled_salt_pw, enc_len01), real_pw) == 0;
+}
+
 /* checks plain text passwords */
 static short pw_plain(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
   return strcmp(real_pw, sent_pw) == 0;
rpmbuild

適当にSPECを編集して2.4系対応パッチの後にRedmine対応パッチの順でパッチが当たるようにしてください。

インストール

ビルドしたらインストール。
あとはconfをちゃんと書いてあげればいいです。

    AuthBasicAuthoritative off
    AuthMySQLAuthoritative On
    AuthUserFile /dev/null

も書いておかないとエラー出ます。

以上。備忘のため。

矛盾された契約書は役員が紛失して再度発行されたものです

はい、契約書とか請求書とかがしょっちゅう紛失する弊社です、おはうぃーす。

自分の所属する会社が直接関わってるわけじゃないんですけど、業務委託ってことで契約書をチェックさせられてるフルスタック雑務です。

中身チェックしてみたら結構サービス利用者側に不利なことが多かったのでいくつか修正してもらえないか交渉してみたんすね、結果色々舐めた感じの修正された契約書が届いたんすよ。

んで、色々あったんですが、大まかに下記の3点をつっこみました。

  1. 営業如何に関わらず連絡事項が「到達した」と見做されたら困るので営業日換算で「到達した」と見做すように項目を修正してほしい
  2. 著作権は制作者に帰属する旨があるが、費用を払って制作を依頼した著作物の著作権は弊社に譲渡されるのが、社会通念上妥当である
  3. サーバまたはソフトウェアの障害・不具合・誤動作など、明らかにサービス提供者の責によるものであるものが、免責事項になっているので、免責の対象から除外してほしい

んで、なされた修正

  1. 「乙の「営業日換算」で到達したものとみなす。」という文言を追加
  2. 「ただし乙が費用を支払い制作された著作物の著作権は乙に帰属することを認める」を追加
  3. 「ただし、明らかに甲の責に因るものである場合は、この限りではない。」を追加

2はいいわ、2は。
1って連絡した内容が時間経過によって到達したと見做すよって内容だったから、「営業日換算にしてくれ」って言ったわけ、

修正前)甲より送信後24時間経過で乙へ到達したと見做す
修正後)甲より送信後乙の営業日において1営業日経過後で乙へ到達したと見做す

って感じにしてくれればよかったわけですよ。何でこんな頭の悪い付け足しになっててしかも見做すまでの経過時間についての記述が消滅してんのよね、担当者バカじゃないかしら?

問題は3のとこなんすよね、Webサービスを提供しているのに、「サーバまたはソフトウェアの障害・不具合・誤動作」に関して責任を負わないって何考えてるんですか?って話ですよ。それで「明らかにサービスの提供者の責である部分が免責事項として記載されているのはおかしいので、その責は負って下さい」って旨を伝えたら、該当箇所への修正がなく「ただし、明らかに甲の責によるものである場合は、この限りではない。」っていう文言が追加されたわけですよ。人のこと舐めてますかね?
というか、免責事項に記載されているものが明らかに甲の責によるものだった場合はどっちが優先するの?って話になるからそういう矛盾点は残しておくとまずいと思うんだけど...まぁ、こういうアホは相手にしたくないのでもう放っておくことにします。

それは社長様の意向なのでしょうか?


いつもはWebプロモーション()の名ばかりWebディレクターさんとかが相手なんですが、今回は税理士事務所か何かの声は若いおねえちゃん相手でした。

営「社長様、いらっしゃいますでしょうか?」
俺「社長は滅多にここに来ませんのですが、どのようなご用件でしょうか?」
営「それは何度も伺ってます、税理士事務所の者ですが」
俺「何度も伺ってますね、今契約してる税理士さんから変える気はないと思いますが」
営「それは社長様の意向なのでしょうか?」
俺「滅多に来ない人の意向なんか知るわけないでしょう」
営「社長様の意向を直接伺いたいのですが」
俺「何度もご連絡いただいているからお分かりだと思うのですが、滅多にこちらの事務所にはこないものですから」
営「ですので何度もこうして電話しているのですが」
俺「はぁ、それでしたら興味があるようならそちらに連絡するように来たときに伝えておきます」
営「毎回そう言われますが、本当に伝えていただいているんですか?」
俺「前回あなたからお電話を頂いてから一度もこちらに来ておりませんので伝えておりませんが」
営「ちゃんと伝えてくださいね」
俺「かしこまりました」

というやりとりを非通知でかかってきた営業電話相手にやってました。
社長と直で話したいのは結構ですが、電話の対応をしている従業員の気分を害するような態度で何をしたいのか全く理解できませんね。

昔、父が不在のときにかかってきたマンションの勧誘の電話で同じようなこと言ってる馬鹿がいましたが、そいつは

「これから自分が言う内容を一字一句間違えずにお前の父親に伝えられるか?」

という意味の分からないことを言ってました。一字一句間違えないことに何の意味があるのかと聞いても「間違えずに伝えられるか?」の一点張りで頭悪かったので、「伝えられるから言ってみろ」と言って話し始めたところでガチャ切りしてやりました。

本人に対してだけ媚びるなり営業トークすればいいという態度をとる頭の悪い電話営業の人がいますけど、電話の取次ぎする人間からその態度が本人の耳に入らないとでも思ってるんでしょうか?
本人と直接話したいと主張するのは結構ですけど、その程度のことにも頭の回らないバカは本人と話しても意味がないと思います。

まぁ、どうでもいいんですけど。非通知でかかってきちゃってるから折り返しも何もないですし。

JavaScriptの配列についてざっくり説明してみる【とりあえず配列編】

仕事してて後輩が書き残してったJavaScript見て絶句したのでこんな記事を書いてやることにした。

配列とは?

知らん。入門書でも読んでくれ。

連想配列とは?

知らん。入門書でも読んでくれ。

配列と連想配列の違い?

知らん。(以下略)

はい、概念とかよく分かりません。

というわけでざっくり説明します。
走査とかそういう扱い方の部分は、基本的には触れません。
あくまで初心者がざっくり理解しようって部分にどうでもいい説明をして混乱させてやろうってコンセプトです。
というか俺そもそもそんなに技術力ないから俺の言うことは真に受けちゃダーメ。
文才もないから内容に期待してもダ・メ☆

とりあえず配列。
//宣言して値をそのまま代入しちゃう
//その1
var array = ['Kongo', 'Hiei', 'Haruna', 'Kirishima'];

//その2
var array = new Array('Kongo', 'Hiei', 'Haruna', 'Kirishima');


//先に配列の宣言だけして値を代入していく
//その3
var array = [];
array[0] = 'Kongo';
array[1] = 'Hiei';
array[2] = 'Haruna';
array[3] = 'Kirishima';

//その4
var array = new Array();
array[0] = 'Kongo';
array[1] = 'Hiei';
array[2] = 'Haruna';
array[3] = 'Kirishima';

書き方としては大体上記の4パターンくらいじゃないすかね?全部同じ結果になるはずですけど。

その1その2とその3その4だと手順が違ってますが、前者ができちゃった婚、後者が結婚してから子作りに励んだくらいの認識でいいと思います。
データの入ってるイメージとしてはタンスとかそんな感じですね。各引き出しに1個データが入ってます。
1段目開けたら「英国で産まれた帰国子女の金剛デース!ヨロシクオネガイシマース!」って感じです。
って言ってみたけど、タンスって表現このあとちょっと面倒なんですよね。ふわっとイメージしといてください。

そんで多次元配列。

んでまあ、「○×ゲーム組んでみたいぞ」って思うと、タンスっていうよりも駅のコインロッカーみたいなの欲しくなりません?

A B C
D E F
G H I

って感じの表作って○×ゲームしたくありません?今時子供でもしませんよね。

そんなことはどうでもいいので、この表を配列で管理するとしたらどうしますかね?
絶対にお勧めしませんけど、こういうことができます

var array =[];
array[11] = 'A';
array[12] = 'B';
array[13] = 'C';
array[21] = 'D';
array[22] = 'E';
array[23] = 'F';
array[31] = 'G';
array[32] = 'H';
array[33] = 'I';

こんな感じで無理矢理やっちゃうことはできます。絶対にお勧めしませんけど。

ちなみにこうも書けます

var array =[null, null, null, null, null, null, null, null, null, null, null, 'A', 'B', 'C', null, null, null, null, null, null, null, 'D', 'E', 'F', null, null, null, null, null, null, null, 'G', 'H', 'I'];

気持ち悪いでしょ?
このやり方だと9×9までは何とかなるけど、10×10からはちょっと苦しくなります。
え、なりません?なってください。

そこで多次元配列ってのを使います。

//その1 配列を作ってから配列の配列にする
//まず配列を作る
var line1 = ['A', 'B', 'C'];//1行目
var line2 = ['D', 'E', 'F'];//2行目
var line3 = ['G', 'H', 'I'];//3行目

//配列の配列にしてあげる
var table = [line1, line2, line3];

//その2 いきなり配列の配列を作る
var table = [['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']];

//↑だと分かりにくいのでには改行して記述してあげます。
var table = [
    ['A', 'B', 'C'],
    ['D', 'E', 'F'],
    ['G', 'H', 'I']
];

こんな感じで配列の配列を作ります。配列の配列なんで2次元配列になります。
その2の改行ありの方が表をイメージしやすいと思います。
値を参照するときは

//Aを取り出したいとき
alert(table[0][0]);

//Fを取り出したいとき
alert(table[1][2]);

って感じで添え字を2個つけて指定すりゃなかみは取れます。
すっかり忘れてましたけど、配列の添え字は0から始まりますからね。
無理矢理やるより分かりやすいでしょ?
ちなみに「変数=箱」ってイメージだと、配列の配列の配列つまり3次元配列くらいがイメージの限界になります。
そりゃ生活してるの3次元までだから無理だっつう話ですよね。
普通にやってたら4次元に行く前に何かしらの事情で4次元になる前に何とかなって欲しいです。どうにもなりませんけど。



気が向いたら次は連想配列について書いてみるか。

あー、提督祈りますよ

playを間違えてprayなのか、意図的にやってるのか知りませんが、とりあえずこのツイートを見て祈った提督は私です。
諸君って誰に向けてるんだ?と言う疑問もありましたが、辞書的な意味では「主として男性が、同輩ないし、それ以下の人々に対し、軽い敬意あるいは親愛の念をもって用いる。」とのことなので敵対勢力によるものではないと判断しておきました。まぁ、人様を小馬鹿にして呼んでる雰囲気が滲み出てますけど、ぶっちゃけツイートの方はどうでもいいんで。

とりあえず件のツイートに載ってる記事を見て感じたことは、

「好きだからこそ気になる」と言って粗探しをする理由が全く分からない

と言うこと。粗探しって好きなものに対してすることではないですけど、本人が好きだと申告していても率直に粗探しだと感じましたのであえて言葉を選んでいます。
まあ、別に記事に書かれてる内容に異論を唱える気もないですし、ご高説の内容はごもっともな部分もあるので別に反論をここに書く気もないわけですが。
ユーザーが増えれば話題性も上がり、批判する人間は増えると思うんで、その辺は「お前が頭いいのは分かったからこれ以上頭の悪さをアピールしなくていい」の一言に尽きるんですが、「好きだからこそ」ってのがよく分からんのです。

原作厨と呼ばれる層のラノベやマンガがアニメ化されたときにイメージと違うと叩くのは、好きの優先順位が「原作>アニメ」あるいは「原作が好きなのであってこの作品のアニメは好きじゃない」と言う話なので理解できます。
しかしながら、件の記事では、「好きだからこそ気になる」との記述があるんですよね。「好きだから気になる」でも「好きだけど気になる」でもいいんですけど、「気になる」って部分は別に当たり前のことだと思うんです、そう宣言してるわりに改善の提案とかそういったもんが一切ないってのがよく分かりません。

うちの嫁は比叡ですが、彼女、しょっちゅうカレー作って持ってくるんです。嬉しいんですが、ちょっと苦手なのでカレーから逃げ回ってたら、たぶん榛名が「榛名は大丈夫です」ってハイライトの消えた目でカレーを食べてくれてると思うんですけど、退役して比叡と二人で暮らしましょって話になったら比叡のカレーは自分で食べなきゃならないわけですよ。
そんなカレーの問題点をただ指摘したところで意味ないじゃないですか?
大好きな比叡においしいカレーを作ってもらいたいじゃないですか?
そのためにはそのカレーをどうすればいいのか考えて比叡に伝えないといけないと思うんですよね、関係を長く続けていくために。

長く続けていくためには「気になるところは批判するのではなく改善策まで提案する」か「これはいいものだと妄信する」しかないと思うんですよね。好きだから云々言ってる割に批判してるってのは、そもそも嫌ならやめればいいじゃん、別に失恋しても死なないのと一緒で別なもん見つけて楽しくやってけるでしょ?と言うかそもそもそこまで執着ないと思うんですけど。

グダグダ言ってもしょうがないですけど、要は「好きだと言いながら批判する」ってのは明確なアンチよりも嫌いなスタンスだってことです。

人材紹介業の過酷な電話営業の闇を見た?




とりあえず、採用担当者お願いしますってことだったんで、一応窓口になってる俺が変わったんですが、何ということでしょう。
「御社」が指しているものが逆です。弊社って言われてないけど。

それはともかく毎度毎度の話として、「とにかく会って欲しい」という意向しか伝わってこない営業の電話がかかってくると同情はしますよ、会いませんけど。

今回のは新卒の子だと思うんですけど、

・自分の会社を「御社」って言っちゃってる
・もはや敬語とかいうレベルじゃない
・言ってることが支離滅裂

って感じだったので、慣れてないのとかなり緊張してたんだと思いますが、結局何がしたいの?って聞いたら「とにかく会って欲しい」って言っちゃってる時点で、「アポとって会ってくる」ってのが一つの評価指標となっている可能性が濃厚です。
そんな変なノルマ課して使い潰して何が楽しんですかね、曲がりなりにも人材紹介の会社ですけど。

辞めるなら次の職場紹介してやるから会社の売り上げに貢献して辞めていけなんていう無法なことはないと思いますが、Webプロモーション()の会社であったり人材紹介会社であったり、最近の電話営業には明らかに異様な空気が漂ってると思います。
正直なところ、彼らが営業という仕事をしているのかと問われたら私は「NO」と答えます。ただ電話かけてるだけです。

そこまで言うなら会ってやれって言われるかもしれませんが、そんなもん知ったこっちゃないんですよ。とりあえず今のバカバカしい体制の組織を作ってアホみたいな営業かけてっていう無能共が何とかしてくださいよ。
電話かけてこられるのも迷惑ですし、こんなくだらないことに同情するのも不愉快極まりないです。

ちょっと待て、営業事務ってそういう意味じゃない

諸事情あってうちの会社で新しく人を募集することになりまして、役員が「営業事務を募集する」と息巻いてるんですよ。

一般的に営業事務の仕事って↓みたいな感じだと思うんですよね

http://toranet.jp/contents/job/zukan/office/623/

でもね、うちの役員のイメージする営業事務ってね、「営業兼事務」だったんですよ。


社会通念って言ってもしょうがないけど、普通営業事務って言ったら営業のサポートをする事務スタッフのことなんだと思うんだけどな...