読者です 読者をやめる 読者になる 読者になる

i++

プログラム系のメモ書きなど

golang : URL短縮サービス goo.gl を使う

URL Shortener API の使い方はこちら → URL Shortener

ここでは API Key を使った方法を載せています。

type responseParam struct {
    Kind    string `json:"kind"`
    Id      string `json:"id"`
    LongUrl string `json:"longUrl"`
}

func GetShortenedUrlImpl(longUrl string) (string, error) {

    values := url.Values{}
    values.Add("key", GoogleApiKey) // パッケージの変数として定義し、この関数を呼ぶ前にセットしておきます。

    url := "https://www.googleapis.com/urlshortener/v1/url" + "?" + values.Encode()

    param := fmt.Sprintf(`{"longUrl":"%s"}`, longUrl);
    req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(param)))
    if err != nil {
        return "", err
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    respBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
    var respParam responseParam
    err = json.Unmarshal(respBody, &respParam)
    if err != nil {
        return "", err
    }
    return respParam.Id, nil
}

golang : 日本語(マルチバイト)文字を含む string の substring

go では string のスライスは byte として扱われるので、日本語のようにマルチバイト文字を含んだ文字列 str に対して str[start:start+length] のようなことをすると、思わぬ場所が切り取られてしまいます。

この問題を回避するために、一旦 rune にキャストしてから string に戻します。

func substring(str string, start, length int) string {
    if start < 0 || length <= 0 {
        // 明らかに不正な値なので、チェックせずに進んで panic を起こしても良さそうです。
        return str
    }
    r := []rune(str)
    if start + length > len(r) {
        return string(r[start:])
    } else {
        return string(r[start:start + length])
    }
}

TypeScript : typings による Chrome Extension 用型定義のインストール

typings で型定義ファイルの管理を行うので、未インストールの場合はインストールします。

npm install -g typings

拡張機能のプロジェクトのディレクトリに移動し、typings init コマンドで初期化します(typings.json ファイルが作成されます)。 その後、install コマンドで Chrome Extension 用の 型定義ファイル(.d.ts)をインストールします。

typings install chrome --ambient --save
typings install filesystem --ambient --save
typings install filewriter --ambient --save
typings install webrtc/mediastream --ambient --save
typings install es6-shim --ambient --save

chromeChrome Extension 用の型定義の本体ですが、これをインストールするだけ使えず、chrome が依存している他の型定義もインストールする必要があります。 typings でインストールしたときに、Stripped reference というメッセージが表示された場合、それらを手動でインストールする、と覚えておけば良さそうです。

> typings install chrome --ambient --save
typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/webrtc/MediaStream.d.ts" during installation from "chrome"
typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/filesystem/filesystem.d.ts" during installation from "chrome"
chrome
└── (No dependencies)

--ambient って何者?など typings についてより詳しく知りたい場合は TypeScriptの型定義管理ツールTypingsについて - Qiita が参考になります。

Git : コミットメッセージに自動でブランチ名を挿入する

参考:How to add Git's branch name to the commit message?

  1. .git/hooks/ 下にある prepare-commit-msg.sample を prepare-commit-msg に変更する(.sample を外す)
  2. prepare-commit-msg に以下のようなスクリプトを追記する
branchPath=$(git symbolic-ref -q HEAD) # branchPath は refs/heads/feature/XXXX_YYYY のような文字列に
branchName=${branchPath##*/} # 最後の / 以下を取得し、branchName は XXXX_YYYY のような文字列に
issueNumber=$(echo $branchName | cut -d "_" -f 1) # "_" を delimiter として cut し、issueNumber は XXXX に
firstLine=$(head -n1 $1)

if [ -z "$firstLine"  ] ;then # 最初の行が空行かチェックして、amend でないことを確認
    sed -i "1s/^/($issueNumber) \n/" $1 # コミットメッセージの先頭に (XXXX) という文字列でブランチの情報を追加。
fi

参考先に少し修正を加え、branchName を直接使うのではなく、cut を使ってその一部を使うようにしています。 例えば feature/XXXX_YYYY というブランチ名だった場合、コミットメッセージには (XXXX) という形でブランチ名の一部が入るようになります。

これは、自分は XXXX の部分にイシューやタスクの番号を、YYYY の部分に少し説明的な文章を入れる形でブランチ名を作っているためです。

Unreal Engine : Timeline を C++ コードで作成・実行する

手順

準備
  1. Timeline で使用する Curve を「Content Browser を右クリック」→「Miscellaneous」→「Curve」(もしくは「Float Curve」)で作成する
  2. 作成した Curve を右クリックして「Copy Reference」する
  3. C++ のコード上で ConstructorHelpers::FObjectFinder を使い、先ほど作成した Curve を取得する
  4. FTimeline オブジェクトを作成する
  5. FTimeline オブジェクトに追加する FOnTimeline* (FOnTimelineVector や FOnTimelineFloat など Curve の種類による)を作成する
  6. FOnTimeline* に、Timeline が更新される毎に呼び出す関数を設定する
  7. FTimeline に、Curve と FOnTimeline* を追加する

Timeline 完了時のイベントを追加する場合のために SetTimelineFinishedFunc などもあるので、適宜使用する。

実行
  1. FTimeLine の PlayFromStart 関数を呼ぶ
    • 途中から再生する場合は Play、逆再生する場合は Reverse など再生開始方法は任意
  2. Tick で FTimeline の IsPlaying() が真であれば、TickTimeline(DeltaTime) を呼ぶ
    • 更新頻度が低くて良い場合は Tick ではなく TickTimeline を呼ぶだけの関数を設定した Timer を作成したほうが負荷が軽くなって良いかも

サンプルコード

void MyActor::MyActor()
{
    // 他の初期化処理...

    // メンバー変数として FTimeline* MyTimeline を定義している
    MyTimeline = new FTimeline();
    MyTimeline->SetTimelineLength(1.0f);

    // 作成した Timeline の取得。Copy Reference でコピーしたテキストを TEXT の中に貼り付ける。
    // <> の中身は Curve の種類によって変更する。今回は Vector。 
    const ConstructorHelpers::FObjectFinder<UCurveVector> StepCurve(TEXT("CurveVector'/Game/Timeline/TimelineCurve.TimelineCurve'"));

    // Timeline 更新時に呼ばれる関数の設定。このクラスに定義している void TimelineStep(FVector v) を呼ぶ。
    FOnTimelineVector MyTimelineStepFunction;
    MyTimelineStepFunction.BindUFunction(this, "TimelineStep");
    MyTimeline->AddInterpVector(StepCurve.Object, MyTimelineStepFunction);

    // Timeline 終了時に呼ばれる関数の設定。このクラスに定義している void TimelineFinished(FVector v) を呼ぶ。
    FOnTimelineEvent MyTimelineFinishedFunc;
    MyTimelineFinishedFunc.BindUFunction(this, "TimelineFinished");
    MyTimeline->SetTimelineFinishedFunc(MyTimelineFinishedFunc);
}

void MyActor::BeginPlay()
{
    if (MyTimeline != nullptr) {
        MyTimeline->PlayFromStart();
    }
}

void MyActor::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

    // Timeline 再生中であれば DeltaTime 進めて実行
    if (MyTimeline != nullptr && MyTimeline->IsPlaying())
    {
        MyTimeline->TickTimeline(DeltaTime);
    }
}

// TickTimeline 毎に、進んだ Time の合計と対応した Timeline から得られる値でこの関数が呼ばれる
// .h で定義する際に UFUNCTION() を付けておくこと
void MyActor::TimelineStep(FVector value)
{
    UE_LOG(LogTemp, Warning, TEXT("TimelineStep : (%.2f, %.2f, %.2f)"), value.X, value.Y, value.Z);
}

// Timeline 完了時に呼ばれる関数
// .h で定義する際に UFUNCTION() を付けておくこと
void MyActor::TimelineFinished()
{
    UE_LOG(LogTemp, Warning, TEXT("TimelineStep Finished"));
}

参考


Blueprint も良くできていると思いますが、メインは C++ で書いたほうが楽そうです。

Unreal Engine 4で極めるゲーム開発:サンプルデータと動画で学ぶUE4ゲーム制作プロジェクト

Unreal Engine 4で極めるゲーム開発:サンプルデータと動画で学ぶUE4ゲーム制作プロジェクト

WPF/XAML : DataGrid の行にコンテクストメニューを設定する

方針・ポイント

  • EventSetter を使って DataGridRow に右マウスボタンイベント(MouseRightButtonUp)を設定する
  • ContextMenu を DataGrid.Resources 内で作る
  • そのイベント内で、Resources の ContextMenu を取得、設定する

ContextMenu の方もコード上で作る、右クリック時ではなく行を追加した時に ContextMenu を設定するなど、他にも様々な方法で同じことが実現できると思いますが、今回は上記の方法で行います。

右マウスボタンのイベントの方が、右クリックによるコンテクストメニューの表示よりも先に行われるようなので、最初の右クリックでメニューは表示されます。

f:id:tkyjhr:20160127145816p:plain

サンプルコード

XAML
<DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False">
    <DataGrid.Resources>
        <!-- ContextMenu の作成 -->
        <ContextMenu x:Key="DataGridContextMenu">
            <MenuItem Header="Menu 1" Click="MyDataGrid_ContextMenu1_Click"/>
            <MenuItem Header="Menu 2" Click="MyDataGrid_ContextMenu2_Click"/>
        </ContextMenu>
        <!-- DataGridRow に右マウスボタンイベントの設定 -->
        <Style TargetType="{x:Type DataGridRow}">
            <EventSetter Event="MouseRightButtonUp" Handler="MyDataGrid_Row_MouseRightButtonUp"/>
        </Style>
    </DataGrid.Resources>
    <!-- 適当なサンプルデータ表示用の列 -->
    <DataGrid.Columns>
        <DataGridTextColumn Header="苗字" Binding="{Binding FamilyName}" Width="80"/>
        <DataGridTextColumn Header="名前" Binding="{Binding FirstName}" Width="80" />
    </DataGrid.Columns>
</DataGrid>
C#
public partial class MainWindow : Window
{
    // 適当なサンプルデータ用のクラス
    public class Person
    {
        public string FirstName { get; set; }
        public string FamilyName { get; set; }

        public Person(string firstName, string familyName)
        {
            FirstName = firstName;
            FamilyName = familyName;
        }
    }

    private ObservableCollection<Person> MyDataGrid_SourceCollection;

    public MainWindow()
    {
        InitializeComponent();

        // 適当サンプルデータを追加
        MyDataGrid_SourceCollection = new ObservableCollection<Person>();
        MyDataGrid_SourceCollection.Add(new Person("太郎", "山田"));
        MyDataGrid_SourceCollection.Add(new Person("花子", "佐藤"));
        MyDataGrid.ItemsSource = MyDataGrid_SourceCollection;
    }

    // DataGridRow に対する右マウスボタンイベント
    private void MyDataGrid_Row_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
    {
        // Resources から ContextMenu を取得して設定
        (sender as DataGridRow).ContextMenu = MyDataGrid.Resources["DataGridContextMenu"] as ContextMenu;
    }

    // ContextMenu の MenuItem のイベントその1
    private void MyDataGrid_ContextMenu1_Click(object sender, EventArgs e)
    {
        if (MyDataGrid.SelectedItem != null)
        {
            MessageBox.Show("Menu 1 : FirstName = " +(MyDataGrid.SelectedItem as Person).FirstName);
        }
    }

    // ContextMenu の MenuItem のイベントその2
    private void MyDataGrid_ContextMenu2_Click(object sender, EventArgs e)
    {
        if (MyDataGrid.SelectedItem != null)
        {
            MessageBox.Show("Menu 2 : FamilyName = " + (MyDataGrid.SelectedItem as Person).FamilyName);
        }
    }
}

Markdown : タイトル末尾に # 記号を使う

Markdown で # を使った形式でタイトルを書く時、

### C#

と書くと結果は

C

となり、末尾の #(ハッシュ記号?シャープ記号?)が表示されません。
以下のように、後ろに # をつけることできちんと表示されるようになります。

### C# #

C#