2011年11月23日

そうだ、SkyDrive、やろう

ご無沙汰です。
最近HDDが高いっすなー、2~3倍近くまで跳ね上がってるものもあるようで
年末こそは新しいPC作ろうと思っていたのですが
HDDの値上り以前に年末の賞与もとい寸志が
ほぼ0というレベルのため中止となりましたΣ(T□T)

さらに最近コードを書く仕事が入ってこないので、
非常にコーディング欲が湧いています。
何が悲しくて他社製品のER図とかDFD書かなきゃなんないんだよと(;-_-) =3 フゥ

で、いくつか作ってみたいツールのネタが出たので
欲求不満解消+HDD買えない憂さ晴らしに作ってみた。

その名も

SkyDriveのアカウントを管理して、ついでにワンクリックでログインしちゃうツール


えーっと、機能としてはこれらを満たすように作ったつもりです

1:SkyDriveのアカウントとパスワードを一覧で管理できる
2:ワンクリックでログイン処理が実行できる
3:ログインしたらざっと中の様子を見れる+ちょっとしたファイル操作ができる
4:最後にいつログインしたかが分かるようにする
5:無料

自動でログイン→自動ログアウト機能をつけるべきか迷ったのですが
そういった機能を自分は欲していないので今回はなしとしました<(_ _)>
まあ、あまり自動化しすぎるとSkyDrive側の仕様変更に対応できなくなるし

画面としてはこんな感じです。


SkyDriveは1アカウントで25GB使えるので、
1アカウント20GBの利用量でも5アカウントで100GBいく計算ですな
無限に作れるメールアカウント用意すれば理論上は無制限なファイルスペースが・・・
※あくまでも理論上です。SkyDriveは使用上の注意をよく読み、用法用量を守って正しくお使いください

で、ここから重要です。

どうもこのツール。起動時にインターネット通信を行うためか
ノートンのSONARにマルウェアとして誤検知されますΣ(゚д゚lll)

怪しい処理は何一つしていませんが?ノートン先生?
その証拠としてソースコードも公開しちゃいますよ?

namespace SkyDriveLoginAssistant
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

  private void button1_Click(object sender, EventArgs e)
  {
   //とりあえずテーブルがちゃんと選択されているか確認
   int SelectRowNumber = 0;
   SelectRowNumber = dataGridView1.CurrentCell.RowIndex;
   if (SelectRowNumber < 0)
   {
    return;
   }
   //データを変数にfade-in
   string id = dataGridView1[1, SelectRowNumber].Value.ToString();
   string pass = dataGridView1[2, SelectRowNumber].Value.ToString();

   //入力ボックスにそれぞれ値をセット
   webBrowser1.Document.All.GetElementsByName("login")[0].Focus();
   webBrowser1.Document.All.GetElementsByName("login")[0].InnerText = id;
   webBrowser1.Document.All.GetElementsByName("passwd")[0].InnerText = pass;

   HtmlElementCollection all = webBrowser1.Document.All;
   HtmlElementCollection forms = all.GetElementsByName("SI");
   forms[0].InvokeMember("click");


   //ログインボタンをクリック!
   //webBrowser1.Document.Forms[0].InvokeMember("submit");





  }

  private void button2_Click(object sender, EventArgs e)
  {
   //リストを保存
   //本当はDataGridViewにDataSourceを設定してXML出力したほうが楽
   //でも、ファイルを直でメンテしたかったりするので、あえてCSVをループで出力させる

   string line = string.Empty;
   Encoding enc = Encoding.GetEncoding("Shift_JIS");
   System.IO.StreamWriter sr = new System.IO.StreamWriter(@"ACLIST.csv", false, enc);
   int colCount = dataGridView1.Columns.Count;
            int rowcount = 0;
   
   foreach (DataGridViewRow row in dataGridView1.Rows)
   {
                rowcount++;
                if (rowcount == dataGridView1.Rows.Count)
                {
                    break;
                }
    for (int i = 0; i < colCount; i++)
    {
     //フィールドの取得
     string field;
     if (row.Cells[i].Value == null)
     {
      field = string.Empty;
     }
     else
     {
      field = row.Cells[i].Value.ToString();
     }
     //"で囲む必要があるか調べる
     if (field.IndexOf('"') > -1)
     {
      //"を""とする
      field = field.Replace("\"", "\"\"");
     }
                    if (i == 0 && field == "0")
                    {
                        break;
                    }
     field = "\"" + field + "\"";
     //フィールドを書き込む
     sr.Write(field);
     //カンマを書き込む
     if (colCount-1 > i)
     {
      sr.Write(',');
     }
    }
    //改行する
    sr.Write("\r\n");
   }
   sr.Close();

  }

  private void Form1_Load(object sender, EventArgs e)
  {
   //CSVファイルからDataGridViewに値を格納
   //CSVからDataSourceに使えるテーブルにしたほうがいいかと思う
   //だが直接セットを貫いてみる。仕事で作るソフトじゃないし(*^-゜)vィェィ♪
   if (!System.IO.File.Exists("ACLIST.csv"))
   {
    //ないものはない
    return;
   }

   System.Collections.ArrayList csvRecords = new System.Collections.ArrayList();
   System.Collections.ArrayList csvFields = new System.Collections.ArrayList();
   Encoding enc = Encoding.GetEncoding("Shift_JIS");
            System.IO.StreamReader sr = new System.IO.StreamReader("ACLIST.csv", enc);


   string csvText = sr.ReadToEnd();
   sr.Close();
   sr.Dispose();

   //前後の改行を削除しておく
   csvText = csvText.Trim(new char[] { '\r', '\n' });

   int csvTextLength = csvText.Length;
   int startPos = 0, endPos = 0;
   string field = "";

   while (true)
   {
    //空白を飛ばす

    while (startPos < csvTextLength &&
      (csvText[startPos] == ' ' || csvText[startPos] == '\t'))
    {
     startPos++;
    }

    //データの最後の位置を取得

    if (startPos < csvTextLength && csvText[startPos] == '"')
    {
     //"で囲まれているとき

     //最後の"を探す

     endPos = startPos;
     while (true)
     {
      endPos = csvText.IndexOf('"', endPos + 1);
      if (endPos < 0)
      {
       throw new ApplicationException("\"が不正");
      }
      //"が2つ続かない時は終了

      if (endPos + 1 == csvTextLength || csvText[endPos + 1] != '"')
      {
       break;
      }
      //"が2つ続く
      endPos++;
     }

     //一つのフィールドを取り出す

     field = csvText.Substring(startPos, endPos - startPos + 1);
     //""を"にする
     field = field.Substring(1, field.Length - 2).Replace("\"\"", "\"");

     endPos++;
     //空白を飛ばす

     while (endPos < csvTextLength && csvText[endPos] != ',' && csvText[endPos] != '\n')
     {
      endPos++;
     }
    }
    else
    {
     //"で囲まれていない

     //カンマか改行の位置
     endPos = startPos;
     while (endPos < csvTextLength &&
       csvText[endPos] != ',' && csvText[endPos] != '\n')
     {
      endPos++;
     }

     //一つのフィールドを取り出す

     field = csvText.Substring(startPos, endPos - startPos);
     //後の空白を削除
     field = field.TrimEnd();
    }

    //フィールドの追加
    csvFields.Add(field.Replace("\"", "").TrimEnd(' '));

    //行の終了か調べる

    if (endPos >= csvTextLength || csvText[endPos] == '\n')
    {
     //行の終了

     //レコードの追加
     csvFields.TrimToSize();
     csvRecords.Add(csvFields);
     csvFields = new System.Collections.ArrayList(csvFields.Count);

     if (endPos >= csvTextLength)
     {
      //終了

      break;
     }
    }

    //次のデータの開始位置
    startPos = endPos + 1;
   }

   csvRecords.TrimToSize();

   for (int i = 0; i < csvRecords.Count; i++)
   {
    try
    {
     int Num = int.Parse(((System.Collections.ArrayList)csvRecords[i])[0].ToString());
     string id = ((System.Collections.ArrayList)csvRecords[i])[1].ToString();
     string pass = ((System.Collections.ArrayList)csvRecords[i])[2].ToString();
     string day = ((System.Collections.ArrayList)csvRecords[i])[3].ToString();

     dataGridView1.Rows.Add(new Object[] { Num, id, pass, day });
    }
    catch
    {
    }
   }

  }

  private void button3_Click(object sender, EventArgs e)
  {
   int SelectRowNumber = 0;
   SelectRowNumber = dataGridView1.CurrentCell.RowIndex;
   if (SelectRowNumber < 0)
   {
    return;
   }
   dataGridView1[3, SelectRowNumber].Value= DateTime.Now.ToString("yyyy/MM/dd");
  }

        private void button4_Click(object sender, EventArgs e)
        {
            webBrowser1.Navigate("https://skydrive.live.com/");
        }
 }
}


どうでしょうか?怪しい動きはありましたか?
デジタル署名すればSONARの誤検知を防げるという情報も見ましたが
「無料で公開するツールにそんなお金かけられるかっての!」
※デジタル署名に必要な証明書の入手には大抵お金がかかります

なので無料のVisualStudioで出来る範囲の対応しかできませんことをお詫びします<(_ _)>
もし誤検出されちゃったら復元してもらえるとありがたいです。
ついでにSymantecにクレームしてくれても構いません(;´▽`A``

正直まだまだバグが残っていますが、
必要最低限の機能は確保できているので
あとは運用でカバーしてください。
100点満点のプログラムはコストも時間も掛かり世界じゃ通用しません。
ま、動けばいいんです。バグったらその時直します。

ダウンロードはこちらからどうぞ!

いやー、意味もなく長い仕様書とか標準化とか画面定義書とかない
自由に作れるコーディングはやっぱり楽しいです。ものづくりバンザイ!ヽ(^◇^*)/

2011年9月29日

GoogleCodeJamに挑戦。挫折寸前


お昼休みに激安弁当つつきながらGoogleCodeJamの練習問題というのを解いてみました。

まあ、あれです。昼休みなのに客先サーバの動作が不安定っていう理由で座席に縛り付けられているのです(;-_-) =3
なので気分転換にやってみました。
とりあえずは「数珠繋ぎ」だけですが、
C#で解いたよっ♪
っていう記事が見当たらなかったのでC#で解いてみた結果を載せてみます。

ロジックとしては単純な処理しかしていません。
というか、複雑な処理を組む気はないっす(;´▽`A``

問題としては、

  • 1個以上の電気的スイッチが存在している
  • スイッチの終端には電球がセットされている
  • 終端以外のスイッチの出力には次のスイッチが接続されている
  • スイッチは指を鳴らすという動作によってON/OFFが切り替わる
  • 先頭のスイッチは電力を供給するプラグに接続されている
  • スイッチは電力が供給されている場合のみON/OFFを切り替え、電力が遮断されている場合には変化しない

さて、指をN回鳴らしたとき、K個連結されたスイッチの終端にある電球は光るでしょうか?

脳内で解読した限りこんな感じの要点ではないかと。
興味の出た人はCodeJamのページを読んでみてください。
(練習問題が消えてしまってたらごめんちゃい)

さて、どう解こうかな~、と紙にスイッチの動きを書き出してみたところ
「4個のスイッチ(A-B-C-D)がつながっている場合」
試行回数:スイッチの状態(0:OFF/1:ON)
0:0-0-0-0
1:0-0-0-1
2:0-0-1-0
3:0-0-1-1
4:0-1-0-0
5:0-1-0-1
中略
13:1-1-0-1
14:1-1-1-0@まだ電球は点かない
15:1-1-1-1@ここで電球点灯
16:0-0-0-0@また消える

・・・うん。2進数だ。
2進数でスイッチの数の桁数下位ビットがすべて1の時に点灯するな、これ(^_^;)

てことは。
指を鳴らした数を2進数で変数にセット
その数にスイッチの数だけ下位ビットから1を並べた2進数を論理積する
論理積した結果がスイッチの数とイコールであれば電球は点く
ということではないかと。

紙にちょっと書き出して検算中・・・検算中・・・β(□-□ )
うん。たぶんおっけー

で、こんなソースになりましたとさ

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace GCM_A
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		string Fileadd = string.Empty;
		int counter = 0;
		int[] snapper;
		int[] finguer;
		bool[] light;

		private void button1_Click(object sender, EventArgs e)
		{
			//ファイルを開くボタンを用意して、ファイルを開くと同時に処理スタート

			OpenFileDialog ofd = new OpenFileDialog();

			if (ofd.ShowDialog() == DialogResult.OK)
			{
				Fileadd = ofd.FileName;
			}
			else
			{
				return;
			}

			//FileLoad
			//全データをStringの配列に突っ込む
			string[] lines = System.IO.File.ReadAllLines(Fileadd);

			//先頭に問題数が記載されているのでそれを取り出して各配列の初期値に使う
			counter = int.Parse(lines[0]);
			snapper = new int[counter];
			finguer = new int[counter];
			light = new bool[counter];

			for (int i = 1; i <= counter; i++)
			{
				//スイッチの数と指を鳴らす回数はブランクで繋がっているので数値に変換して取り出す
				snapper[i-1] = int.Parse(lines[i].Split(' ')[0]);
				finguer[i-1] = int.Parse(lines[i].Split(' ')[1]);

			}

			//電球点灯状態を一括チェック
			Calc();

			//結果を出力
			OUTPUT();

			//めでたしめでたし
		}

		private void Calc()
		{

			for (int j = 0; j < counter; j++)
			{
				//指を鳴らした数
				uint a = (uint)finguer[j], x;
				//スイッチの数から論理積に使用するビット列を作る。-1するのを忘れないように
				int n = (int)Math.Pow(2, (snapper[j]));
				uint b = (uint)n-1;
				//指を鳴らした数と1になっているべき値を論理積
				x = a & b;
				//電球が点灯しているかを判断
				if (x==b)
				{
					light[j] = true;
				}
				else
				{
					light[j] = false;
				}

			}

		}


		private void OUTPUT()
		{
			//ファイルに一気に出力する
			StreamWriter sw = new StreamWriter(@"z:\output.txt");
			for (int k = 0; k < counter; k++)
			{
				if (light[k])
				{
					sw.WriteLine("Case #" + (k + 1).ToString() + ": ON");
				}
				else
				{
					sw.WriteLine("Case #" + (k + 1).ToString() + ": OFF");
				}

			}
			sw.Close();
			sw.Dispose();
		}

	}
}


Largeの問題を1秒程度で解いてくれると思っています。
さらに速度を上げるのであれば、、、そうすなぁ~
スイッチの数であらわすことのできる2進数値よりも指を鳴らす回数のほうが小さいときは即座にOFFと判断できるんじゃないかと。

ここまで書いておいてなんですが、
きっと毎回参加される方々はもっと早くプログラム作って解けるんだろうなぁ~と。
C#でビット演算ってあまりやらないよなぁ~と。

こういうの好きな高校とかの先生は次回のテストで
+αのボーナス問題に穴埋めにしてこの問題使いそうだな
と思ったところでお開き。

土曜の予選に参加できるかどうかはサーバが安定するかにかかっている( ̄▽ ̄;)