ncursesのバージョンが見たい

os x を使っているんですけど、ncursesはbrewでインストールできるんですよね。

だけどほんとにそのバージョンのを使ってるのかわからないときとかバージョンが知りたくなる。なので、直感的に信じてやって見たらバージョン出力ができたという感じです。ソースコードのどこに書いてあるんだろうね。以下、コード

#include <ncurses.h>
#include <stdio.h>

int main(){
    printf("%s\n", NCURSES_VERSION);
}

バージョン出力だけなので、色々入れてないけど。一応これで出た。ncursesの6.1を入れたはずなんだけど実際には5.7のデフォルトのっぽかったんだよね... どうやったら使えるようになるのかは調査中です。 5.7だと、SIGWINCHのシグナルハンドラーを設定してリサイズしようとするとどうしてもおかしくなるんだよね... どうしようかなぁ

ROMっぽいもの

前回の記事から22日ほど経ってしまっているんですよね。 最近は勉強する習慣をつけてます。 django、vue、golang、cpu製作、web製作などなど 競プロなんかもちょっとずつやってます、はい。 目的は勉強なんですけど、最近ブログ更新してないなぁとか思っちゃったりしてるので、書きたいと思います!!

ROM書いてみた

言わずもがなROMです。定数か変数か変えれば、RAMになると思ってます。numeric_stdを使っているので、そのままFPGAっていうわけにはいかないかも(実験してない)だけど、シミュレーションでは良さげだったので。

ソースコード

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity ROM is
    -- change length of std_logic_vector
    port(address: in std_logic_vector(9 downto 0);
    output: out std_logic_vector(7 downto 0));
end entity;


architecture RTL of ROM is
    -- change size of array to match address
    type Memory1KB is array(0 to 1023) of std_logic_vector(7 downto 0);
    constant data: Memory1KB := (
"00000000",
"00000001",
"00000010",
"00000011",
...
"00000000",
"00000000",
"00000000",
"00000000",
"00000000",
"00000000",
"00000000");
begin
    output <= data(to_integer(unsigned(address)));
end architecture;

typeでaliasを付けつつ、ROMのサイズを指定(210 B = 1 KB)。 address幅もそれに合わせて 10 bit になってる。実際のデータは 0 番地には 0 を 1 番地には 1 を 2 番地には 2 を入れてある。 ROMのは210バイトだけど、1 バイトは1 ^ 8 -1 までしか表せないので、足りないところは 0 埋めでテストした。

f:id:b1u3:20181130005053p:plain
ROMのシミュレーション

シミュレーションでは、addressに 0 から順番にアドレスを入れていった。 FPGAとかに載せる時は、ベンダーが提供してるものを使うか、下から自作するのか、それともこのままいけるのかまだわかんないです。

djangoのcontenttypes

contenttypesはdjangoでいうアプリの様なもので、modelsとかfieldsとかがある。そのうちのmodelsの中にContentTypeというモデルがある。これがメイン。

ContentTypeとは

簡単に言えば、プロジェクトにインストールされたモデルを管理するモデル インストールされたオブジェクトは自動で生成される。

プロパティ

  • app_label これは、モデルがどのアプリケーションに含まれているかを示す。例えば、プロジェクトmysite内のpollアプリだったらpollになる。ついでに、常にこれはpythonのimport文のドットで区切った最後の単語になる。

  • model これは、モデルの名前。models.Modelを継承したクラスの名前。

  • name barbose nameだと思われる。

メソッド

  • ContentType.get_object_for_this_type(**kwargs) モデルのオブジェクトを持ってくる

  • ContentType.model_class() モデルクラスを持ってくる

contenttypesはアプリケーションなので、同じ様にモデルとかも扱うことができる。 objectsでマネージャーを取って来たりすることができる。

Generic relations

オブジェクトとモデルクラスを結びつける機能。ForeignKeyの強化版。

例えば、ForeignKeyを使うとき、AからBに関係を張りたいとき、AとBっていう名前が必要になる。だけど、ContentTypeを挟んでおくと、これは動的に変えられる様になる。

Reverse Generic Relations

GenericForeignKeyを設定しておくと逆参照ができる。MenyToMenyのGeneric版。 GenericFordignKeyをもつモデルに対して、GenericRelationを張ると参照できる様になる。

djangoのi18nやってみた

色々djangoi18nチュートリアル見たけど何が必要なのか一貫してなかったからやってみた。

環境

設定とか

l10ni18n
├── l10ni18n
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── testapp
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   ├── __init__.py
    ├── models.py
    ├── templates
    │   └── testapp
    │       └── base.html
    ├── tests.py
    ├── urls.py
    └── views.py

こんな感じのディレクトリ構成になっている。manage.pyがあることからl10ni18nがプロジェクトディレクトリであることがわかる。

base.htmlとviews.py

<html>
        <head>
                <title>I10N I18N</title>
        </head>
        <body>
                {% get_current_language as lang %}
                <p>{{ lang }}</p>
                <p>{% trans msg %}</p>
        </body>
</html>
from django.shortcuts import render
from django.utils.translation import gettext as _


def my_view(req):
    msg = _('Test')
    return render(req, 'testapp/base.html',{'msg':msg})

views.pyではgettextで翻訳文字をマークしてる。

で、このあと、testapp内に空のディレクトリを作る。

% mkdir testapp/locale
% ./manage.py makemessages -l en
% ./manage.py makemessages -l ja

これで、.poがlocaleフォルダ内にできる。 .poファイルを編集して、翻訳後の文字を設定する。 その後、コンパイルする

% ./manage.py compilemessages 

すると.moが.poと同じディレクトリ内にできる。

settings.pyには、LocaleMiddlewareを追加。

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
...
from django.utils.translation import gettext_lazy as _

LANGUAGES = (
        ('en', _('English')),
        ('ja', _('Japanese')),
        )

それとLANGUAGESも追加する。これ以外だったら、LANGUAGE_CODEのものが返されるらしい。これで試して見た。 まず、i18nが効いてないとき、

f:id:b1u3:20181103200132p:plain

f:id:b1u3:20181103200358p:plain

翻訳前の文字列がそのまま出る。 効いてる時、

f:id:b1u3:20181103200448p:plain

f:id:b1u3:20181103200543p:plain

こんな感じになる

vueの最初の方をやった

vueの最初の数ページを読んだ後に、小さいシングルページアプリケーションを書いてみた。ミラクルキラッツなので。

f:id:b1u3:20181028165459p:plain

f:id:b1u3:20181028165515p:plain

なるほど〜って言いながら、書いてた。appにだけコンポーネントを追加しようと思ってたんだけど、それは無理だった。残念。 JSの辞書のキーが文字列限定なのがpythonと違って気をつけなきゃいけない点かなぁと。

フロントはまだまだ覚えることが多くて大変だなぁと思った。

やる気はまだまだあるからできるところまでやろう!!!と思っている。

昨日と違った自分に。1 歩ずつでも前に進もう。

<html>
        <head>
               <meta charset="UTF-8">
               <title>todo</title>
               <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
       </head>
        <body>
                <div id="app">
                        <h1>{{ title }}</h1>
                        <ol>
                                <todo-item v-for="item in todoList" v-bind:todo="item"></todo-item>
                        </ol>
                        <input v-model="newTodo">
                        <button v-on:click="addNewTodo">Add</button>
                </div>
        <script>
               Vue.component('todo-item',{
                       props:['todo'],
                       template:'<li>{{ todo.text }}</li>'
               })
               var app = new Vue({
                       el:"#app",
                       data:{
                               newTodo:'',
                               title:'Todo App',
                               todoList:[
                                       {'text':"todo1"},
                                       {'text':"todo2"},
                                       {'text':"todo3"},
                                       ]
                       },
                       methods:{
                               'addNewTodo':function(){
                                       this.todoList.push({text:this.newTodo})
                                       this.newTodo = ''
                               }
                       }
               })
       </script>
        </body>
</html>

ARC101 C candles

やっぱ難しいなぁ、競プロ。

左右に行ききするタイプ+k個連続のスリットのようなものを動かすみたいなイメージ。

drken1215.hatenablog.com

この方のwiteupを見た。 スリットを動かすみたいのはわかったけど、コードに落とせなかった。

以下、pythonで書いたもの。全く同じ(正確には違う)で載せるのも憚られるのですが、すみません。

def main():
    n,k = [int(i) for i in input().split()]
    candles = [int(i) for i in input().split()]
    i = 0
    res=1<<60;
    while i+k-1<n:
        left = candles[i]
        right = candles[i+k-1]
        res = min(res,min(abs(left),abs(right))+right-left)
        i+=1
    print(res)

if __name__ == '__main__':
    main()
min(abs(left),abs(right))+(right-left)

この部分は(right-left)でこの区間を走査する時間でabsではじめに右に行くか左に行くか決めてるっぽい。 イメージはある区間の一番端に一度行って、逆の端に走って行くという感じ。

学んだこと

  • 個数が決まったスリットの動かし方
  • 考え方

最初、0からスタートするし、0 に一番近いところから取ってって...と考えていたので、その時点で方向性が違ったように感じる。久々に、C解けなかったなぁ。自信なくすなぁ。

pwnable.kr(7)(2) ~input~

前回の続きです。

ステージ 2 からやっていきます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char* argv[], char* envp[]){
    printf("Welcome to pwnable.kr\n");
    printf("Let's see if you know how to give input to program\n");
    printf("Just give me correct inputs then you will get the flag :)\n");

    // argv
    if(argc != 100) return 0;
    if(strcmp(argv['A'],"\x00")) return 0;
    if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;
    printf("Stage 1 clear!\n");

    // stdio
    char buf[4];
    read(0, buf, 4);
    if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;
    read(2, buf, 4);
        if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;
    printf("Stage 2 clear!\n");

    // env
    if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
    printf("Stage 3 clear!\n");

    // file
    FILE* fp = fopen("\x0a", "r");
    if(!fp) return 0;
    if( fread(buf, 4, 1, fp)!=1 ) return 0;
    if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;
    fclose(fp);
    printf("Stage 4 clear!\n");

    // network
    int sd, cd;
    struct sockaddr_in saddr, caddr;
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if(sd == -1){
        printf("socket error, tell admin\n");
        return 0;
    }
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = INADDR_ANY;
    saddr.sin_port = htons( atoi(argv['C']) );
    if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){
        printf("bind error, use another port\n");
            return 1;
    }
    listen(sd, 1);
    int c = sizeof(struct sockaddr_in);
    cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);
    if(cd < 0){
        printf("accept error, tell admin\n");
        return 0;
    }
    if( recv(cd, buf, 4, 0) != 4 ) return 0;
    if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;
    printf("Stage 5 clear!\n");

    // here's your flag
    system("/bin/cat flag");
    return 0;
}

とりあえずコード貼っておく。 ステージ2は標準入出力周り。 単純にsys.stdin.writeとsys.stderr.writeが使えなかった。結局パイプを使う方法がいいみたいだ。forkでexecだと、stdinとstderrをパイプに接続できないので、subprocessのプロセスオープンで対応。

    stdinr, stdinw = os.pipe()
    stderrr, stderrw = os.pipe()
    os.write(stdinw, "\x00\x0a\x00\xff")
    os.write(stderrw, "\x00\x0a\x02\xff")

パイプを作って書き込む。シェルからかくとヌル文字で区切られてしまうので書き込むことができないようだ。低水準は奥が深いなぁ。

ステージ3は唯一書き込み可能な /tmpディレクトリで行わなければならない。chdirをすることを最初考えて進めていたが、あとでダメだということがわかった(これめちゃめちゃ重要だった)なので、/tmpで自分のディレクトリを作って、その中で実行というのが正解みたいだ。ステージ3、4、5は初見で突破できた。以下ステージ3、4、5の

    f = open("\x0a","w")
    f.write("\x00\x00\x00\x00")
    f.close()
    args[ord("C")-1] = '1234'
    subprocess.Popen(["/home/input2/input"]+args,stdin=stdinr,stderr=stderrr)
    time.sleep(1)
    sock = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
    sock.connect(('127.0.0.1',1234))
    sock.sendall(b'\xde\xad\xbe\xef')
    sock.close()

これで、ステージ 5までは突破できた。最後のsystemが実行しても何も吐き出さないので困った。ここで、chdirで/tmpに移行したことがダメだということがわかった。inputプログラムを実行後はcwdを動かせないので、どうやってもflagファイルがあるディレクトリに戻れず、最後のsystemが実行されても何も起こらない。

調べたらここはシンボリックリンクを使うみたいだった。ファイルが保存できるのは、/tmp以下なので、ここで、”実行する場所は/tmp以下でやら”なければならないことがわかった。シンボリックリンクを作成することで実行したディレクトリで、flagを開くというギミックだった。

以下、/tmp内に作った作業用ディレクトリで実行するスクリプト(解答)

import os
import subprocess
import socket
import time


def main():
    os.system("ln -s /home/input2/flag flag")
    os.putenv("\xde\xad\xbe\xef", "\xca\xfe\xba\xbe")
    args = ["0"] * 99
    args[ord("A")-1] = ""
    args[ord("B")-1] = "\x20\x0a\x0d"
    stdinr, stdinw = os.pipe()
    stderrr, stderrw = os.pipe()
    os.write(stdinw, "\x00\x0a\x00\xff")
    os.write(stderrw, "\x00\x0a\x02\xff")
    f = open("\x0a","w")
    f.write("\x00\x00\x00\x00")
    f.close()
    args[ord("C")-1] = '1234'
    subprocess.Popen(["/home/input2/input"]+args,stdin=stdinr,stderr=stderrr)
    time.sleep(1)
    sock = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
    sock.connect(('127.0.0.1',1234))
    sock.sendall(b'\xde\xad\xbe\xef')
    sock.close()


if __name__ == '__main__':
    main()

サーバーのポートは適当に指定。最初65432でやったら別のでやってねって言われた。何回か適当な数入れてこれが大丈夫だった。