東京メトロ オープンデータ活用コンテスト
「エンドユーザーのアプリから直接APIを呼んではいけない」
まじか。開発者登録した後に読める規約に書いてあるらしい。
これってつまり、ドメイン取って自前WEBサーバー立ててデータストア設計してWEBアプリ作って、
そこまで揃えてやっとスマホアプリ作りに入れるってことか。
スマホアプリ作るの初めてなんですぅ〜
という軟弱者の私が軽々しく参加できるコンテストではなさそう・・・
東京メトロAPIで取得できるデータを応答するWEBアプリ、で応募するかw
※2014/9/27追記
利用規約が改定され、上の条項は削除されました。
これで、どんなアプリでも自由に作ってくれたまえ、ということになったみたいです。
一緒に「トークンの扱いは自己責任で」的な規約が追加されましたが、
トークンなんて、最初からいらなかったんじゃ・・・
まぁ何か作ってみましょうかね。
ShiftJISの固定長ファイルを読み込む
VBScriptでShiftJISの固定長ファイルを読み込むテンプレ。
例によって cmd.vbs と wow64.vbs を同じフォルダへ入れておく。
サンプルでは text.txt を fixedlength.vbs にドロップすると、1レコードずつmsgboxします。
test.txt
123ほげ1 ふが1 456ほげ2 ふが2 789ほげ3 ふが3
fixedlength.vbs
option explicit dim wsh,fso const ForReading = 1 const ForWriting = 2 const ForAppending = 8 set wsh = CreateObject("WScript.Shell") set fso = CreateObject("Scripting.FileSystemObject") include "cmd.vbs" include "wow64.vbs" call init call main call fini set wsh = nothing set fso = nothing WScript.Quit '----------------------------------------------------------------- sub init() end sub sub main() dim i for i = 0 to WScript.Arguments.Count - 1 call func(WScript.Arguments(i)) next end sub sub func(arg) dim ifile, defs, record defs = array(3,10,10,2) 'レコード定義 set ifile = fso.OpenTextFile(arg, ForReading, False) do until ifile.AtEndOfStream record = readRecord(ifile, defs) if UBound(record) > 0 then msgbox join(record, vbCrLf) end if loop ifile.Close set ifile = nothing end sub sub fini() end sub sub include(filename) filename = fso.BuildPath(fso.GetParentFolderName(WScript.ScriptFullName), filename) ExecuteGlobal fso.OpenTextFile(filename, ForReading, False).ReadAll() end sub ' 固定長ファイルから1レコード分読み込み、配列に分割して返す ' ifile 固定長ファイル ' defs カラム長配列 ' @return 1レコード分の配列 function readRecord(ifile, defs) dim arr,i,s,l,c redim arr(UBound(defs)) for i = 0 to UBound(defs) s = "" l = 0 do while l < defs(i) if ifile.AtEndOfStream then exit function end if c = ifile.Read(1) l = l + lenj(c) s = s & c loop arr(i) = s next readRecord = arr end function ' ShiftJIS相当関数群 --- ' 文字列の切り出し function midj(s, position, length) dim i,c,pos pos = 1 for i = 1 to len(s) c = mid(s, i, 1) if pos >= position then midj = midj + c end if pos = pos + lenj(c) if pos >= position + length then exit function end if next end function ' 1文字の長さ function lenj(c) if(asc(c) >= 1 and asc(c) <= 255) then lenj = 1 else lenj = 2 end if end function ' 右桁埋め(文字列の空白埋めなど) function rpadj(s, length, padding) rpadj = midj(s & string(length, padding), 1, length) end function ' 左桁埋め(数値のゼロ埋めなど) function lpadj(s, length, padding) lpadj = strreverse(rpadj(strreverse(s), length, padding)) end function
bashでメニュー
bashでこんな感じのメニューを簡単に作る方法です。
■■■メインメニュー■■■ 0: submenu001.sh メニュー1 1: submenu002.sh メニュー2 q: 終了 コマンドを選択してEnterキーで決定します>
■作り方
- メインメニューとサブメニューは同じフォルダに作成します
- メインメニューはサブメニューを呼び出します
- サブメニューに記述したコマンドを適宜実行する構成です
- メインメニューにはサブメニュー内の「#@menu:サブメニュー」が表示されます
- メインメニューはとりあえずコピペで動きます
- サブメニューは適宜作成してください
- 小さいシステムならサブメニューだけで、サブメニューを直接起動でも良いかもしれません
■メインメニュー
mainmenu.sh
#!/bin/bash setMenu() { IFS=$'\n' menu=(`grep "^#@menu:" *.sh`) } getMenu() { IFS=$':' arr=($1) if [[ ${#arr[@]} -ge $2 ]]; then echo ${arr[$2]} else echo fi } printMenu() { for (( i = 0; i < ${#menu[@]}; i++ )) do shell=`getMenu "${menu[$i]}" 0` title=`getMenu "${menu[$i]}" 2` printf "%2d: %s %s \n" $i ${shell} ${title} done } executeMenu() { IFS=$':' item=(${menu[$1]}) ./${item[0]} } showMenu() { while true; do clear echo ■■■メインメニュー■■■ printMenu echo " q: 終了" read -p "コマンドを選択してEnterキーで決定します> " input if [[ ${input} =~ "[eEqQ]" ]]; then exit fi if [ ${input} -ge 0 ] && [ ${input} -lt ${#menu[@]} ]; then executeMenu ${input} fi done } setMenu showMenu exit 0
■サブメニュー
submenu001.sh
#!/bin/bash #@menu:メニュー1 while true; do clear cat <<EOF ================================================== メニュー1 ================================================== 1: サブメニュー1 2: サブメニュー2 3: サブメニュー3 q: 終了 ================================================== EOF case "$input" in 1) sudo ssh -t -t {remotehost} {command1} ;; 2) sudo ssh -t -t {remotehost} {command2} ;; 3) sudo ssh -t -t {remotehost} {command3} ;; q|Q|e|E) exit 0 ;; *) ;; esac read -p "メニューを選択してください(1-3:q)>" input done exit 0
重いSQLを抽出する
SQLDeveloperの(たしか)CPU上位SQLを少し改造したもの。
実行1回あたり5秒以上かかっているSQLを洗い出します。
SELECT s.INST_ID, (s.cpu_time/1000000) "CPU_Seconds", s.disk_reads "Disk_Reads", s.buffer_gets "Buffer_Gets", s.executions "Executions", CASE WHEN s.rows_processed = 0 THEN NULL ELSE ROUND((s.buffer_gets/NVL(REPLACE(s.rows_processed,0,1),1))) END "Buffer_gets/rows_proc", ROUND((s.buffer_gets /NVL(REPLACE(s.executions,0,1),1))) "Buffer_gets/executions", (s.elapsed_time /1000000) "Elapsed_Seconds", ROUND((s.elapsed_time/1000000)/NVL(REPLACE(s.executions,0,1),1)) "Elapsed/Execution", ga.sql_fulltext "SQL", s.module "Module", s.SQL_ID FROM gv$sql s LEFT JOIN gv$sqlarea ga ON s.inst_id = ga.inst_id and s.sql_id = ga.sql_id WHERE s.sql_id IN ( SELECT DISTINCT sql_id FROM ( WITH sql_class AS (SELECT sql_id, state, COUNT(*) occur FROM (SELECT sql_id , CASE WHEN session_state = 'ON CPU' THEN 'CPU' WHEN session_state = 'WAITING' AND wait_class IN ('User I/O') THEN 'IO' ELSE 'WAIT' END state FROM gv$active_session_history WHERE session_type IN ( 'FOREGROUND') AND sample_time BETWEEN TRUNC(sysdate,'MI') - :minutes/24/60 AND TRUNC(sysdate,'MI') ) GROUP BY sql_id, state ), ranked_sqls AS (SELECT sql_id, SUM(occur) sql_occur , rank () over (order by SUM(occur)DESC) xrank FROM sql_class GROUP BY sql_id ) SELECT sc.sql_id, state, occur FROM sql_class sc, ranked_sqls rs WHERE rs.sql_id = sc.sql_id --and rs.xrank <= :top_n ORDER BY xrank, sql_id, state ) ) AND ROUND((s.elapsed_time/1000000)/NVL(REPLACE(s.executions,0,1),1)) > 5 -- SQL1回あたり5秒を超えるもの ORDER BY "Elapsed/Execution" DESC NULLS LAST
SQL整形マクロ
SQL整形マクロ V1.04
http://hide.maruo.co.jp/lib/macro/sqlclean104.html
希望通りの動作のものを見つけられなかったので、
自分でも改造できそうだった↑に、ちょっとだけ好みを追加してみました。
■「シングルクォートで括られた」を文字列定数とする機能
スキップ用の変数をループの前に追加して、
##Skip = -1;
シングルクォートが出てくる度にフラグを反転させます。
// 文字列定数の時の処理キャンセル if(code == 39) { ##Skip = ##Skip * -1; right; continue; } if(##Skip == 1) { right; continue; }
■改行を追加する条件のjoinをleftとinnerに変更。
この配列を変更
$EntElm[14] ="join"
やや実行速度が遅い気もしますが、今のところまずまず使わせて頂いています。
delete_flagに0/1
データベースでマスタを削除するとき、割り当て済みのプライマリキーを残すために削除フラグを立てて論理削除する設計があります。このときフラグだから0/1で、というシステムを山ほど見ましたが、100%暗黙の型変換なしの正しいSQLを書けているところはありませんでした。つまりdelete_flag=0とdelete_flag='0'は混在するのです。これはフラグという名前と0/1という値から、項目のデータ型を推測できないことが原因だと思うわけです。そこで、
delete_flagは文字列型で
値は文字列でfalse/trueとか、alive/deadとか、何ならO/Xとか、とにかく数字でなければ何でも良いです。これなら必ずdelete_flag='false'と記述されます。まぁ大文字小文字の間違いとか、頭文字だけにしたらどっちが有効だよ、とかいうのはありますが少なくとも暗黙の型変換が紛れ込む余地をなくせます。ぜひ誰かやってみてくださいw
小数点以下の桁数を指定して丸め
C#で小数点以下の桁数(digit)を指定して丸める関数です。標準関数は整数丸めなので、digitで10進数で桁シフトして、丸めて、元に戻す、としています。なお、マイナス値について、Floorはゼロに近い方への丸め、Ceilingはゼロから遠い方への丸め、に変更しています。
public static decimal Floor(decimal value, int digit) { int shift = (int)Math.Pow(10, digit); return Math.Floor(Math.Abs(value) * shift) * Math.Sign(value) / shift; } public static decimal Round(decimal value, int digit) { int shift = (int)Math.Pow(10, digit); return Math.Round(value * shift, MidpointRounding.AwayFromZero) / shift; } public static decimal Ceiling(decimal value, int digit) { int shift = (int)Math.Pow(10, digit); return Math.Ceiling(Math.Abs(value) * shift) * Math.Sign(value) / shift; }