ごらくらいふ

プログラミングしたりゲームしたり

Bootstrapの学習をはじめた

今までちょっとした管理ツールとかばかり作っていたのでCSS frameworkは滅多に触ってこなかった。 CSSに集中せざるを得なかった案件もあるが、逆に全て調整しなくてはならずframeworkが入る余地もなかった。

と、いうことで。 モダンな(もうモダンじゃなくなってるか?)、いろんなところの基礎になってる感のあるbootstrapの学習に手を付けることにした。

github.com

とりあえずv4のドキュメントを読み進めて、Grid Layoutの基本的な部分までやった。 ここらへんはflexboxらしいので、flexbox学習の足がかりになりそうだなーという気持ち。

Componentsは色彩豊かで楽しそー。

WPFかじり: HTTP GETする

MSDNのHTTPページにリクエストを飛ばして、レスポンスから適当に表示してみる。

工程を分割

URIからリクエストの発行

var uri = "https://docs.microsoft.com/en-us/dotnet/framework/network-programming/http";
var request = WebRequest.Create(uri);
var response = await request.GetResponseAsync();

response.Close();
  • WebRequestはabstruct
  • WebRequest.Create(string uri)はFactoryで、http(s)部分を見つけるとサブクラスであるHttpWebRequestインスタンスを返却してくれるらしい
  • GetResponseAsync()を発行して初めてリクエストが飛ぶ

レスポンスを取り出す

var stream = response.GetResponseStream();
var reader = new StreamReader(stream);
var responseBody = await reader.ReadToEndAsync();

reader.Close();
  • Responseからはstreamが得られる

HTMLをパースして要素を取り出す

HtmlAgilityPackを使用する

var htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(responseBody);

var title = htmlDoc.DocumentNode.SelectSingleNode("//title");

ViewModel全体コード

public class MainWindowViewModel :INotifyPropertyChanged
{
    private string _text;
    public string Text
    {
        get { return _text; }
        set
        {
            if (_text != value)
            {
                _text = value;
                NotifyPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public MainWindowViewModel()
    {
        fetchWebSite("https://docs.microsoft.com/en-us/dotnet/framework/network-programming/http");
    }

    private async void fetchWebSite(string uri)
    {
        var request = WebRequest.Create(uri);
        var response = await request.GetResponseAsync();
        var stream = response.GetResponseStream();
        var reader = new StreamReader(stream);
        var responseBody = await reader.ReadToEndAsync();

        var htmlDoc = new HtmlAgilityPack.HtmlDocument();
        htmlDoc.LoadHtml(responseBody);

        var title = htmlDoc.DocumentNode.SelectSingleNode("//title");
        Text = title.InnerHtml;

        reader.Close();
        response.Close();
    }
}

雑感

  • async methodからVMのpropertyをいじってもちゃんとUIに反映してくれるの優しい

参考リンク

WPFをかじりだした。Hello world.

直近、Web systemとしてC#に触れる機会が発生して、ついでにGUIアプリケーションの作り方にも触れたいと思ったのでかじった。

とりあえず@ITの連載をざっと流し読みして雰囲気を掴む。

public partial class MainWindow :Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel {
            text = "Hello World",
        };
    }
    public class MainWindowViewModel
    {
        public string text { get; set; }
    }
}
<Grid>
    <Label Content="{Binding text}" />
</Grid>

所感

  • MVVM
    • DataContextに突っ込んだオブジェクトのpublic propertyにBindできる
      • クラス生成しなくても即時生成objectでもbind出来なくはないらしい
  • エントリーポイントはApp.xaml
    • Buildすると中にMain()が生成されるらしい
    • Application.StartupUriにMainViewのPathが突っ込んである
      • Uriってことは、Routingあたりが居てView遷移の交通整理でもしてくれんのかな
  • View(Window?)のライフサイクルが知りたい
    • 泥のOnCreateとか、OnDestroy相当のやつ
    • View, ViewModelはいつ生まれても死んでもいいようにModelやら切り離す設計を強要してる?
      • Apprlcationのライフサイクルがあればそっち管理で十分か。あるか知らんけど。

ちょろい。いや、ちょろいと思わせてくれないと辛いんだけども。

参考URL

Insider.NET > 業務アプリInsider > 連載:WPF入門 - @IT

Select文でJoinするときは一番深いところをFromにしたい

前提

  • mysqlでの話。
  • Subjects --(1:n)-+ Subjects_Tags +-(n:1)-- Tags というテーブル構造での話。

本題

趣味の範疇なのだろうけれども、レコード数が増加する方向のJOINは極力控えたい。 Select * from Subjects left join Subjects_Tags ...より、Select * from Subjects_Tags left join Subjectsの方が好み。

「行を増やすこと自体にコスト多少コストがかかる」感覚を持っている。 オプティマイザがよしなにやってくれるはずなんだろうけどね。

具体的には

SELECT S.name, T.name AS tag_name
FROM Subjects AS S
  LEFT JOIN Subjects_Tags AS S_T ON S.id = S_T.subject_id
  LEFT JOIN Tags AS T ON S_T.tag_id = Tags.id
WHERE S_T.subject_id = :id
;

よりも

SELECT S.name, T.name AS tag_name
FROM Subjects_Tags AS S_T
  LEFT JOIN Subjects AS S ON S_T.subject_id = S.id
  LEFT JOIN Tags ON S_T.tag_id = Tags.id
WHERE S_T.subject_id = :id
;

の方が好み。

「リトル・レディ」勝手に復活日誌 #20 (完結宣言) + 過去記事をちょっと整えた

f:id:yajamon:20150715095909p:plain

もう二年前なのね。

リトル・レディ関連の記事を全部廻って記事を整えました。

  • あとで読む を取っ払った
  • 次の記事リンクを貼った

いまいちど、リトルレディをプレイする事ができた。

「リトル・レディ」勝手に復活開発は、これにて完了とする。

これから手を加えるのは、より現代ブラウザ向けの修正になるので、"リファクタリング:リトル・レディ"とかのタイトルでやろうかな。

はじめから

yajamon.hatenablog.com

型に語らせて in kotlin (and java ?)

某本の某コードをkotlin化している。

この本はちょっとしたイラッを無数に積み重ねる反面教師本だと感じている。

何を悪しとして何を良しとしたかの備忘録。

あまり手を加えず、本件とは無関係の要素を削ぎ落としたコード片が以下の通りである。

abstract class Token {
    open fun isIdentifier():Boolean { return false }
    open fun getText():String { return "" }
}
class Lexer {
    inner class IdToken(private val value:String) :Token {
        override fun isIdentifier(): Boolean { return true }
        override fun getText(): String { return value }
    }
    fun read(): Token {
        // 諸々省略
        return IdToken()
    }
}
class Leaf {
    fun parse(lexer: Lexer) {
        val t = lexer.read()
        if (t.isIdentifier()) {
            // なにかしらの処理
        }
    }
}

少しイラッとしただろうか。欠片でも伝われば報われる。

何がクソだと感じたか

  • super classであるToken特定のsub classの存在を予定しているところ

お前なんかこうだ!

abstract class Token {
    open fun getText():String { return "" }
}
inner class IdToken(private val value:String) :Token {
    override fun getText(): String { return value }
}
class Lexer {
    fun read(): Token {
        // 諸々省略
        return IdToken()
    }
}
class Leaf {
    fun parse(lexer: Lexer) {
        val t = lexer.read()
        if (t is IdToken) {
            // なにかしらの処理
        }
    }
}

javaにだってinstanceof演算子がいるからできるでしょ。

型に語らせれば分かることをis**(Type)**化する意味はない。

Production環境のMastodonでnohup.outログがたまり続ける件を解決する

Mastodonを導入した際、npmコマンドだけバックグラウンドで稼働するようになっていなかったため、nohupを使ってバックグラウンドで稼働するようにした。

yajamon.hatenablog.com

それ以降、nohup.outにログがダバダバと放出され続けている。 以下はログの一部。

ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b error: データベース"mastodon_development"は存在しません
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at [object Object].Connection.parseE (/home/mastodon/live/node_modules/pg/lib/connection.js:554:11)
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at [object Object].Connection.parseMessage (/home/mastodon/live/node_modules/pg/lib/connection.js:381:17)
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at Socket.<anonymous> (/home/mastodon/live/node_modules/pg/lib/connection.js:117:22)
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at emitOne (events.js:77:13)
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at Socket.emit (events.js:169:7)
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at readableAddChunk (_stream_readable.js:153:18)
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at Socket.Readable.push (_stream_readable.js:111:10)
ERR! 0b9a54ac-3018-4f52-9bbd-9ff0af90184b     at Pipe.onread (net.js:540:20)

Production環境で動作しているにもかかわらずmastodon_developmentを探そうとしている。

答え。typo

mastodon-streamingにて、環境変数typoしていた。

RNODE_ENVとなっており、正しくproduction環境として動作していなかった。

(2017/05/07 16:50) 当該記事の問題箇所は修正済み。