サイトコレクションのURLに関して

SharePoint 2013のサイトコレクションのURLには、

"/"

のほかに、

"/sites/(sc)/"

という形式のものがあります。

"/"

のサイトコレクションのコンテンツエディターWebパーツで、サイトコレクションのスタイルライブラリに配置したJSファイルとCSSファイルを

<script type="text/javascript" src="/Style%20Library/test1.js" />
<link type="text/css" rel="stylesheet" href="/Style%20Library/test2.css" />

という風に記述して読み込んで、後続コードで、これらファイルに定義されている関数を呼び出したりしていました。このコンテンツエディターWebパーツをエクスポートして、後者の形式の環境にアップロードして確認したところ、動きませんでした。。理由は、URLのパスが無効だったからです。以下のように先頭に「/sites/(sc)」を付けて書き換えればOKです。もちろん絶対URLでもOKです。

<script type="text/javascript" src="/sites/(sc)/Style%20Library/test1.js" />
<link type="text/css" rel="stylesheet" href="/sites/(sc)/Style%20Library/test2.css" />

これで解決しましたが、なんかコードの携帯性が悪い気がしたので、どっちの形式でもOKな方法はないか考えてみました。
まず、SharePointのページで、URLがどっちの形式なのかを判別できる

_spPageContextInfo.webServerRelativeUrl

ものがあることがわかりました。(まあ、location.hrefでもsitesがあるかどうかでわかりますが。。)
この部分のパスが取れるようなので、これを使って、JSやCSSを動的にロードしようと思いました。
ただし、ここに入っているのは、

サイトコレクションURLwebServerRelativeUrl
//
/sites/(sc)//sites/(sc)
なので、単純に「_spPageContextInfo.webServerRelativeUrl+"/Style%20Library/xxx"」または「_spPageContextInfo.webServerRelativeUrl+"Style%20Library/xxx"」としてしまうと、どちらかの形式のURLのサイトで動きません。
というわけでとりあえず以下のようなコードを考えてみました。これをコンテンツエディターWebパーツのソースの最初のの中に書きます。

(function(){
function LoadJS(src) {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.src = src;
    document.head.appendChild(s);
}

function LoadCSS(href) {
    var l = document.createElement("link");
    l.setAttribute("type", "text/css");
    l.setAttribute("rel", "stylesheet");
    l.setAttribute("href", href);
    document.head.appendChild(l);
}

function LoadJSWithSiteUrl(src) {
    var basePath=_spPageContextInfo.webServerRelativeUrl;
    LoadJS(((basePath!="/") ? basePath :"")+src);
}

function LoadCSSWithSiteUrl(href) {
    var basePath=_spPageContextInfo.webServerRelativeUrl;
    LoadCSS(((basePath!="/") ? basePath :"")+href);
}

LoadJSWithSiteUrl("/Style%20Library/test1.js");
LoadCSSWithSiteUrl("/Style%20Library/test2.css");
})();

scriptタグやlinkタグの代わりとしては、長すぎる(やることに対してコードが大袈裟過ぎる)ので実際の業務ではとりあえず使用しないつもりです。(実際の配置環境に応じて書き換えるのが現実的)
もっといい方法がありましたらぜひ教えてください。

テキストファイルの出力

JavaScriptだけでもテキストファイル(UTF-8)の出力ってできるんですね。
ただし以下は、Blobオブジェクトを使っています。なのでHTML5 File APIを使用してます。たとえば、IE9以下は未対応なので、仕事のコードでは使用し(でき)ませんでした。。

function OutputText(text, fileName) {
    var b = new Blob(["\uFEFF", text]);
    if (navigator.msSaveBlob) {
        navigator.msSaveOrOpenBlob(b, fileName);
    } else {
        var a = document.createElement('a');
        a.href = URL.createObjectURL(b);
        a.setAttribute('download', fileName);
        a.dispatchEvent(new CustomEvent('click'));
    }
}

たとえばHTMLフォームのボタンから以下のように呼びだします。

<input type="button" value="exec" onclick="OutputText('こんにちは!', 'output.txt');" />

とくに、意味はないですが一行のJavaScriptブックマークレットも作ってみました。お気に入りのURLに入れて保存して、クリックすると「こんにちは!」という文字列のファイルがDLできるだけです。

javascript:b=new%20Blob(["\uFEFF","\u3053\u3093\u306B\u3061\u306F\uFF01"]);f="test.txt";if(navigator.msSaveBlob){navigator.msSaveOrOpenBlob(b,f);}else{a=document.createElement('a');a.href=URL.createObjectURL(b);a.setAttribute('download',f);a.dispatchEvent(new%20CustomEvent('click'));}

配列で順序を保ったまま集合算をする

JSの配列で集合算を考えてみた - IIJIMASの日記」の続きです。
配列が2つ与えられたとき、重複を省きつつ、和集合、共通部分、差集合などを表す配列を計算するアルゴリズムで、ループ回数をなるべく少なくしたものを考えます。
以前のエントリのやり方だと、順序が保存されないので、今回は順序が保存されるのを考えてみました。とりあえず考えたアルゴリズムでは対称差(XOR)だけ余計にループが必要となってしまいました。それ以外は、ループは2回で済みます。冒頭部分の演算によって引数の順番を交換しているところは、再帰で書いた方がすっきりするかもしれませんがわかりにくくなると思います。

//演算の種類を表す定数。値に意味はなし、互いに異なればOK
MathSet.Operator.Union = 1;
MathSet.Operator.Intersection = 2;
MathSet.Operator.DiffLR = 3;
MathSet.Operator.DiffRL = 4;
MathSet.Operator.SymmDiff = 5;

MathSet.OperationWithOrdering = function (arrayA, arrayB, operator) {
    var set = {};
    switch (operator) {
        case MathSet.Operator.DiffLR:
        case MathSet.Operator.Intersection:
        case MathSet.Operator.SymmDiff:
            a1 = arrayB;
            a2 = arrayA;
            break;
        case MathSet.Operator.Union:
        case MathSet.Operator.DiffRL: 
        default:
            a1 = arrayA;
            a2 = arrayB;
    }
    var val;
    var newArray = [];
    for (var i = 0; i < a1.length; i++) {
        val = a1[i];
        if (set[val] == null) {
            set[val] = 1;
            if (operator == MathSet.Operator.Union) {
                newArray.push(val);
            }
        }
    }
    for (var j = 0; j < a2.length; j++) {
        val = a2[j];
        if (set[val] == 1) {
            set[val] = 3;
            if (operator == MathSet.Operator.Intersection) {
                newArray.push(val);
            }
        } else if (set[val] == null) {
            set[val] = 2;
            if (operator != MathSet.Operator.Intersection) {
                newArray.push(val);
            }
        }
    }
    if (operator == MathSet.Operator.SymmDiff) {
        for (var i = 0; i < a1.length; i++) {
            val = a1[i];
            if (set[val] ==1) {
                set[val] = 4;
                newArray.push(val);
            }
        }
    }
    return newArray;
};

以下のように使用します。(exec()をボタンのonclickなどで指定して、クリックで実行します。)

function exec() {
    result = "";
    result += "arrayA:\t"; result += A; result += "\r\n";
    result += "arrayB:\t"; result += B; result += "\r\n";
    result += "\r\n";
    result += "A∪B:\t"; result += MathSet.OperationWithOrdering(A, B, MathSet.Operator.Union); result += "\r\n";
    result += "A∩B:\t"; result += MathSet.OperationWithOrdering(A, B, MathSet.Operator.Intersection); result += "\r\n";
    result += "A-B:\t"; result += MathSet.OperationWithOrdering(A, B, MathSet.Operator.DiffLR); result += "\r\n";
    result += "B-A:\t"; result += MathSet.OperationWithOrdering(A, B, MathSet.Operator.DiffRL); result += "\r\n";
    result += "XOR:\t"; result += MathSet.OperationWithOrdering(A, B, MathSet.Operator.SymmDiff); result += "\r\n";
    alert(result);
}

結果:

arrayA:	100,3,1,2,3,2,1
arrayB:	8,12,6,2,3,5,6,3,2

A∪B:	100,3,1,2,8,12,6,5
A∩B:	3,2
A-B:	100,1
B-A:	8,12,6,5
XOR:	100,1,8,12,6,5

結果(順序が保存される)

同じ入力で以前のエントリアルゴリズム(順序が保存されない)

もっと効率が良くて、短いもの、解かりやすいものを考えたならばぜひ教えてください。

JSの配列で集合算を考えてみた

どんなプログラミングでも基本的な配列の操作において、集合算を実装したいということはあるかと思います。言語仕様やライブラリに実装されていればそれを使えばよいですが、そうでない場合に自分で実装せざるをえないなくなったり、興味や頭の体操で実装してみたくなることもあるかと思います。
新しいJavaScriptではSetオブジェクトが定義されているようですが、(→[Link]「ECMAScript Language Specification ECMA-262 6th Edition – DRAFT」)こちらにもとりあえず集合算は見当たりません。
前からある配列(Arrayオブジェクト)で集合算をするロジックを考えてみました。具体的には2つの配列から新しい結果の配列を返す関数を考えてみました。Arrayは重複を許しますので、重複を排除しつつ計算します。和集合は全ての要素だから簡単ですが、共通部分は割と複雑です。ひとまとめにして、とりあえず以下のような関数を実装してみました。
配列Aと配列Bを集合A,Bとみなして(重複は排除)、全体の和集合A∪BをA-BとA∩BとB-Aに分けて、演算の種類に応じて各集合から要素を新しい配列に詰めるかどうかを指定します。

var MathSet;
MathSet = {};
MathSet.Operator = {};
MathSet.Operator.Union = [1,1,1];
MathSet.Operator.Intersection = [0,0,1];
MathSet.Operator.DiffLR = [1,0,0];
MathSet.Operator.DiffRL = [0,1,0];
MathSet.Operator.SymmDiff = [1,1,0];
MathSet.Operation = function(arrayA, arrayB, operator) {
    var ptnA = [operator[0]];
    var ptnB = [operator[1]];
    var ptnAB = [operator[2]];
    var set = {};
    for (var i = 0; i < arrayA.length; i++) {
        set[arrayA[i]] = ptnA;
    }
    for (var j = 0; j < arrayB.length; j++) {
        set[arrayB[j]] = (set[arrayB[j]] && set[arrayB[j]] != ptnB) ? ptnAB : ptnB;
    }
    var newArr = [];
    for (var v in set) {
        if (set[v][0] == 1) {
            newArr.push(v);
        }
    }
    return newArr;
};

以下のように使用します。(exec()をボタンのonclickなどで指定して、クリックで実行します。)

function exec(){
var A = [1,2,3,3,1,2];
var B = [2,3,5,6,3,6,8];

result="";
result+="arrayA:\t";result+=A;result+="\r\n";
result+="arrayB:\t";result+=B;result+="\r\n";
result+="\r\n";
result+="A∪B:\t";result+=MathSet.Operation(A, B, MathSet.Operator.Union);result+="\r\n";
result+="A∩B:\t";result+=MathSet.Operation(A, B, MathSet.Operator.Intersection);result+="\r\n";
result+="A-B:\t";result+=MathSet.Operation(A, B, MathSet.Operator.DiffLR);result+="\r\n";
result+="B-A:\t";result+=MathSet.Operation(A, B, MathSet.Operator.DiffRL);result+="\r\n";
result+="XOR:\t";result+=MathSet.Operation(A, B, MathSet.Operator.SymmDiff);result+="\r\n";
alert(result);
}

結果:

arrayA:	1,2,3,3,1,2
arrayB:	2,3,5,6,3,6,8

A∪B:	1,2,3,5,6,8
A∩B:	2,3
A-B:	1
B-A:	5,6,8
XOR:	1,5,6,8


実行例では、数字要素のサンプルとしましたが、文字列要素などでももちろん実行可能です。
もっと効率が良くて、短いもの、解かりやすいものを考えたならばぜひ教えてください。

関数を動的に書き換えてみた

Webアプリのサーバー側コードが生成するクライアント側コードのJavaScriptで、ある関数の一部だけ、書き換えたいことがあるとします。
その関数は、非nativeで定義を閲覧可能で全体を書き換える程でもない(書き換えたくはない)とします。その関数の呼び出しの前後へのコード追加では用が足りなくて、その関数の中の一部だけを書き換えたいとします。
関数の定義コードの文字列を置き換える関数を考えてみました。
以下のreplaceFuncは、第1引数が書き換えたい関数で、第2引数は元のコードを新しいコードに置き換えた関数を返す関数です。

function replaceFunc(func, replaceMethod){
	var funcScript = func.toString();
	var funcMatches = funcScript.match(/function *([^\(]*)\((.*)\)( *)/);
	var funcSignature = funcMatches[2];
	var funcBody = RegExp.rightContext;
	var newScript ="var f = function("+funcSignature+")"+replaceMethod(funcBody)+";";
	eval(newScript);
	return f;
}

使用例(onloadやonclickでexec()を呼び出します):

//書き換えたい関数(使用例は短いコードだが、意味のある複数行でもよい)
myfunc=function   (  x  ,   y   )     {
	return x   + y;
};
//書き換えたい関数の定義は、以下の形式でもよい
function myfunc0(  x  ,   y   ){return x +y;}
//使用例
function exec(){
	var result="";
	result+=myfunc.toString(); result+="\r\n";
	result+="myfunc(3,5)="+myfunc(3,5); result+="\r\n";
	
	myfunc = replaceFunc(myfunc,
		function(src){return src.replace(/x\s*\+\s*y/,"x*y");});
		
	result+=myfunc.toString(); result+="\r\n";
	result+="myfunc(3,5)="+myfunc(3,5); result+="\r\n";
	alert(result);
}

結果:

function   (  x  ,   y   )     {
	return x   + y;
}
myfunc(3,5)=8
function(  x  ,   y   ){
	return x*y;
}
myfunc(3,5)=15

IEでの実行結果 Google Chromeでの実行結果

退職しました

2014年4月30日をもちまして、6年間勤務した会社(某大手SI企業の子会社、職歴2社目)を退職しました。6年間のうちに職場でかかわった方で。知ってる方が見ているかわかりませんが、お世話になりました。
無名な会社の無名エンジニアの退職の話なんて誰も興味ないでしょうが、ここは「日記」なので正直なところを書かせていただきます。

思い出

2008年5月1日に中途で入社したので、ちょうど6年になります。6年前、内定をもらった会社が吸収合併される同じタイミングで入社でした。5年間いた職歴1社目とはまた、違った経験をいろいろとさせていただきました。最初のプロジェクトでは、休日出勤や、深夜作業後タクシー帰宅を体験させていただいたり、親会社の中では異色な部署で開発環境を向上するツールを普及する仕事でいろいろ学ばさせていただいたり、親会社拠点での常駐をメインとする業態の会社なので、基本的に出張などはないのですが、運よくあるプロジェクトではインド人の方々と仕事をするための意識合わせとして16日間インドのプネに出張させていただいたりしせていただいたりました。とても良い思い出です。インドは機会があればまた行ってみたいです。別のプロジェクトでは、短期間ですが、インフラ系の作業もさせていただいたりしました。IOSのコマンドなんていじったのそのプロジェクトのときだけです。
最後にいたプロジェクトでは、プロジェクト内部の共通チームで、それまでとは少し趣の異なる仕事(周知・催促・督促・集計・グラフ作成)もさせていただきました。良い経験となりました。また、そのプロジェクトではいろいろ社内外の方々とお仕事をさせていただき、所属したチームの方々ともとても良い関係を築くことができました。様々なプロジェクト内部のツールの作成・改修も言語はVBAJavaでしたが、作成作業自体は割と自由にさせていただいたことはありがたかったです。チーム内でツールを作成と言ったら私という風に頼りにされるのは悪くなかったです。Excelもそんなに嫌いじゃないです。
勤務地も、初台→豊洲高田馬場豊洲→入谷(吉原)→両国→赤坂見附と変わっていきましたが、それぞれなかなか特徴があって面白かったです、各地のつけ麺おいしかったです。お昼は、高田馬場コスパ良かった気がします。最後の現場での、オフィスまで売りに来てくれるい和多の450円弁当もコスパはいいです。最初のプロジェクトの仕事で行った東陽町駅の居酒屋大漁の700円ランチは大量でおいしかったです。豊洲の中華料理永利もボリューム満点でした。また最後のプロジェクトでの知り合いに教えてもらった、丼丸というお持ち帰り海鮮丼のチェーンはとて大好きになりました。ワンコイン+税でそこそこ食べれます。両国時代は毎日何人かで買いに行っていました。オフィスが赤坂見附に引っ越ししてからも、お昼休みに丼丸がある隣駅の四ツ谷まで電車乗って買いに行ったりしていました。職場の人もたまに一緒に行ってくれました。

なぜ辞めるのか

なぜ辞めるのかといえば、転職先が決まったからです。
で、転職活動をしていた(転職サイトに登録していた)理由は複数ありますが、まず、C#.NET Framework言語を用いた開発の仕事(プログラミング)がしたかったのですが、会社にはそのような仕事がなかった(少なかった)のです。グループ内の開発の会社と標榜していたと思いましたが、プロジェクトや現場にもよると思いますが、そもそもプログラミングの仕事は、あまり多くないのかもしれません。協力会社や親会社の別の協力会社の方がよっぽどプログラミングをしていると感じました。また、開発がある場合にも言語は、親会社はJava文化なので多くがJavaでした。最後のプロジェクトは、商用開発側チームは基本C言語で、時々Javaという感じだったようですが、私は、共通チームのPJ内部ツールでしたので、VBA時々Javaでした(それでもプログラミングを時々できるだけ幸せでした)。。
また、品質管理などの共通系の仕事もそれなりにやりがいはあるし、携わっている人々が少なからずいますが、会社の人事部の評価基準になっているキャリアパスのなかには、適合する職種はありませんでした。業務SEやPM、インフラエンジニア、営業、スタッフなどはあります。結局あるもののどれか(私の場合業務SE)を目指すことにして、各キャリアパスの到達度を報告する様式の「何々ができる」みたいな設問項目に答えて会社に提出するのですが、普段やっている業務・使命とは程遠いもので、多くがNoとなってしまいます。そのキャリアに実作業も近い人が有利となります。これに関しては、私以外の方でも、実際のしなければならない業務と評価基準の乖離がモチベーションを低下させている原因になると思います。
あと、子会社の宿命なのかもしれませんが、毎年四月に、たくさんの親会社定年退職者が部長として入社されるのも(で、従業員数に対して、新卒が少ない)正直良い文化には感じませんでした。もちろん優秀な方も少なからずおられますし、仕事も連れてくることになっているのでしょうが。部によっては、課長と同数かそれ以上の部長さんがいる事態になったりしていました。「長」って一人だけじゃないのか…といつも思ったりしていました。
ほかにも理由はたくさんありますが、ご想像にお任せします。不満や不安はあるものです。解消できるとは限りませんが、解消のため努力はできます。他人の不満を解消するのがビジネスで解決法がまさにSI業界でよく言われるソリューションとも言えますので、自分が不満に思うことは実はビジネスの種かもしれません。これも経験と思って、今後の業務に活かしていきたいと思います。
最後の現場のチームの方々、現場の親会社の管理者の方とは特に親しくさせていただいたので、そこを離れてしまうのは少々名残惜しいですが、新しい出会いや関係も楽しみで期待も大きいので、このような決断となりました。

今後

今後も、以前の某同僚がやってる内部勉強会には可能ならば参加するつもりです。たとえ会場が辞めた会社の本社だったり辞めた会社の偉い人が参加しても。。そのほか、親しかった同僚に誘われれば、飲み会でもなんでも参加します!
2014年5月1日より、あるソフトウェア開発会社に入社します。

Excelの数式を使って整数の素因数分解を求める

Excelの数式のみを使用して、100以下の数の素因数分解を求めるにはどうすればいいでしょうか。VBAを使用しない方法を考えたいです。(よって、ユーザー定義の関数も使用しません。)Excelのセル参照とビルトイン関数のみを利用して、基本的に、初期値となるいくつかの数値とセル参照の数式を入力して、[Ctrl]+[D](Fill Down)と[Ctrl]+[R](Fill Right)で延長して、素数と整数の素因数分解の表を作成できないものでしょうか。
とりあえず、思いついた手順を以下に書きます。
以下の手順では、まず、A列に整数、1行目に素数の列、セルには、同じ行のA列の整数の素因数分解における、同じ列の1行目の素数の指数が表示される表を作成します。

Sheet1で

セルA2に

=ROW()-1

と入力

A2:A101を選択

[Ctrl]+[D]でA2の数式を、A101まで数式を延長する。A列は対象の整数を表す。

セルB1に最小の素数である

2

を入力。B列以降、1行目には素数が入ることになる。

セルB2に

=IF(MOD($A2,B$1)>0,0,1+INDEX(B:B,MATCH($A2/B$1,$A:$A,0),1))

と入力。この式は、後の手順で下にも右にも延長する。同じ列の1行目の素数で割り切れない場合は0、割り切れる場合は、その商の整数における同じ列の値に1を足したものである。各列には、同じ行のA列の整数が、同じ列の1行目の素数の最大何乗で割り切れるかが入る。

B2:C101を選択

[Ctrl]+[R]と[Ctrl]+[D]でB2の数式をC101まで延長する。

Sheet2で

Sheet2がなければ増やす。
B1とB2に

1

を入力。


B3にSheet1の同じ位置のセルの参照

=Sheet1!B3

を入力。

B列にB3の数式を延長するためにB3からセルを選択する。

B3:B101まで選択して、[Ctrl]+[D]でB3の数式をB101まで延長する。

Sheet2のC列以降は、Sheet1の指数の和を計算して、それまでの素数で割り切れるかどうかを判定するのに使う。それまでの、どの素数でも割り切れなければ0が入る。
C1には

=B1+Sheet1!C1

を入力。

C1:C101まで選択

[Ctrl]+[D]でC1の数式をC101まで延長する。

列ヘッダのCからドラッグでZまで選択。

[Ctrl]+[R]でZ列まで、C列の数式を延長する。

再びSheet1で

C1に

=MATCH(0,Sheet2!B:B,0)-1

を入力。
これは、それまでのどの素数でも、割り切れない最小の数を求めている。すなわちそれが、次に見つかる素数となる。

列ヘッダのCからドラッグでZまで選択。

[Ctrl]+[R]でZ列まで、C列の数式を延長する。

結果、1行目には素数が出現する。他の行には、A列の整数が1行目の素数で何回割ることができるかが入る。再帰的にZ101までの数式で、値が定まる。

ここまでで、整数の素因数分解の各素数の指数が求まる。
本質的にはもうここまでで、素因数分解の表ができたといえる。
以下は素因数分解の見た目でわかりやすい表示にする。たとえば、100を「2^2 5^2」のようにな表し方で一覧を作成する。

Sheet3で

新しいシートSheet3を追加する
B3に

=IF(Sheet1!B3>0,Sheet1!B$1&IF(Sheet1!B3>1,"^"&Sheet1!B3,""),"")

を入力。単にSheet1の指数を素数のべき乗の形で表しただけ。0乗は1だけど、積では何も書かないから、""で表す。また、1乗は指数を書かない。

[Ctrl]+[R]と[Ctrl]+[D]でB3の数式をZ101まで延長する。

Sheet4で

新しいシートSheet4を追加する
B3に

=A3&IF(AND(A3<>"",Sheet3!B3<>"")," ","")&Sheet3!B3

と入力する。Sheet3のB列から、同じ位置のセルまで、値をつなげる。(積で表す。)

B3からドラッグ

B3:Z101を選択。
[Ctrl]+[R]と[Ctrl]+[D]でB3の数式をZ101まで延長する。

Sheet4のZ列に、Sheet1のA列の整数の素因数分解表示ができている。

おわりに

→作成済みのファイルと手順をVBA化したファイルのダウンロード

  • PrimeNums.xlsx ・・・作成済みのファイル
  • PrimeNumsMacro.xlsm ・・・手順をVBA化したファイル

手順をVBA化したファイルはあくまでも上記手順をマクロで実行するだけで、VBAでの計算は行っていません。
ここでは、100までの素数を表示しましたが、各シートで、右と下に数式を延ばせばもう少し素数素因数分解を表示できます。
本質的な部分である、Sheet3の追加前までの部分について、シートを2枚も使用していますが、これを1枚で作成する方法はないでしょうか。より簡単にExcel数式だけで素数素因数分解の表が作れる方法があったら教えてください。もちろんVBAでロジックも書けば少ない労力やデータ量で簡単に同じことをできますが、「Excel数式だけ」しばりでわざわざ何かを作るって少し面白いと思いませんか。