【Rust】四則演算【Algorithm】

fn main() {

   println!("二つの数字を入力してください。");
   let mut x = String::new();
   let mut y = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   let x: i32 = x.parse::<i32>().unwrap();
   std::io::stdin().read_line(&mut y).expect("Failed to read line");
   y = y.trim_end().to_owned();
   let y: i32 = y.parse::<i32>().unwrap();

   println!("{} + {} = {}", x, y, x+y);
   println!("{} - {} = {}", x, y, x-y);
   println!("{} * {} = {}", x, y, x*y);
   println!("{} / {} = {}", x, y, x/y);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/basic`
二つの数字を入力してください。
24
6
24 + 6 = 30
24 – 6 = 18
24 * 6 = 144
24 / 6 = 4

【Rust】mem::swap【Algorithm】

mem::swap(&mut x, &mut y);でswapできる。
https://doc.rust-lang.org/std/mem/fn.swap.html

use std::mem;

fn main() {

   println!("二つの数字を入力してください。");
   let mut x = String::new();
   let mut y = String::new();
   std::io::stdin().read_line(&mut x).expect("Failed to read line");
   x = x.trim_end().to_owned();
   std::io::stdin().read_line(&mut y).expect("Failed to read line");
   y = y.trim_end().to_owned();

   mem::swap(&mut x, &mut y);
   println!("入力した値をswapすると「{}」と「{}」です", x, y);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/basic`
二つの数字を入力してください。
20
15
入力した値をswapすると「15」と「20」です

既に用意されているのね…

【BNB】BEP-20 Token on BSCを作る

1. bitbankなどでbnbを取得して、metamaskに送信します。
※bitbankの表記では、bnbはビルドアンドビルドとなっており、binance cointと異なるかと思いってしまいますが、ビルドアンドビルドでOKです。
metamaskでbscネットワークに接続し、bnbが受け取れたことを確認してアドレスを取得

2. remixを表示し、bep-20.solファイルを作成する
https://remix.ethereum.org/

pragma solidity >=0.6.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";

contract HpsToken is ERC20 {
    constructor(uint256 initialSupply) public ERC20("HpscriptToken", "HPS") {
        _mint(msg.sender, initialSupply);
    }
}

3. コンパイル

4.DEPLOY & RUN TRANSACTIONS
– Environmentをmetamaskにする
– ACCOUNTがMetamaskのアドレスになっていることを確認
– CONTRACTが先ほどコンパイルしたTokenになっている
– トークン供給量は100,000,000に設定する
-> Deploy

5. txハッシュからトランザクション確認
https://bscscan.com/

6. トークンの受け取り
コントラクトのアドレスを入力

【Rust/React.js】axumでReactのコンポーネントを利用する

### React
まず、reactで実装したコードをbuildする
$ npm run build

すると、build/static/js にjsファイル一群ができるので、その中からmain.*.jsをコピーする
axumのルートディレクトリにstaticフォルダを作成して、./static/js/script.js にbuildされたjsのスクリプトを貼り付ける。

### axum側
dependencyに tower-httpを追加
tower-http = { version = “0.6.2”, features = [“fs”] }

templatesのhtmlからjsファイルを読み込めるように、ルーティングで読み込めるようにする

use tower_http::services::{ServeDir, ServeFile};

#[tokio::main]
async fn main() {
    let serve_dir = ServeDir::new("static").not_found_service(ServeFile::new("static"));

    let app = Router::new()
        .route("/", get(handler_index))
        .nest_service("/static", serve_dir.clone())
        .fallback_service(serve_dir.clone());

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

templates/index.html

<body>
<h1>Hello world</h1>
<div id="root">wait...</div>
<script src="./js/script.js"></script>
</body>
</html>

なるほど、いけますね。あとは作り込みのみ!

【Rust/React.js】jsonで保存したデータをsetTimeoutで表示する

React(Json)で、入れ子のデータを扱うには、data.map((value) => と書くと、for(let d in data) のような処理ができる。

main.rs

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Name {
    first : String,
    last: String,
}

#[tokio::main]
async fn main()  {
    let mut names : Vec<Name> = Vec::new();
    let n1 = Name { first:"taro".to_string(), last:"yamata".to_string()};
    let n2 = Name { first:"hajime".to_string(), last:"tanaka".to_string()};
    let n3 = Name { first:"hanako".to_string(), last:"yoshida".to_string()};
    names.push(n1);
    names.push(n2);
    names.push(n3);
    println!("{:?}", names);
    let serialized: Vec<u8> = serde_json::to_vec(&names).unwrap();
    println!("{:?}", serialized);
    let file_path = format!("./data/data.txt");
    let mut file = File::create(file_path.clone()).unwrap();
    file.write_all(&serialized).expect("write failed");

}

data.txt

[{"first":"taro","last":"yamata"},{"first":"hajime","last":"tanaka"},{"first":"hanako","last":"yoshida"}]

App.js

import React, {Component} from 'react';
import './App.css';
 
class App extends Component {
 
  render() {
    return <div className="App">
    <h1>React</h1>
    <Blocks />
  </div>;
  }
}
 
class Blocks extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
    };
  }

  componentDidMount() {
      this.timer = setInterval(
          () => 
              fetch('./data/data.text').then(response => {
                  return response.json();
                  }).then(json => {
                      this.setState({ data: json});
                  }),
          2000,
      );
  }

  componentWillUnmount() {
      clearInterval(this.timer);
  }

  render() {
    if (this.state.data) {
      return <div>
        {this.state.data.map((value) => (
          <p>名前:{value.first} {value.last}</p>
        ))}
      </div>
    }
    else {
      return <div>Loading...</div>
    }
  }
}
export default App;

これを少し応用したい。

【Ethereum】ECR20を発行しよう

$ pip3 install eth-brownie
$ npm install -g ganache-cli
$ brownie init
$ tree
.
├── build
│ ├── contracts
│ ├── deployments
│ └── interfaces
├── contracts
├── interfaces
├── reports
├── scripts
└── tests

contract/TokenERC20.sol
https://github.com/PatrickAlphaC/erc20-brownie/tree/main/contracts

pragma solidity ^0.6.0;

interface tokenRecipient { 
    function receiveApproval(address _from, uint256 _value, address _token, bytes calldata _extraData) external; 
}

contract TokenERC20 {
    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public decimals = 18;
    // 18 decimals is the strongly suggested default, avoid changing it
    uint256 public totalSupply;

    // This creates an array with all balances
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    // This generates a public event on the blockchain that will notify clients
    event Transfer(address indexed from, address indexed to, uint256 value);
    
    // This generates a public event on the blockchain that will notify clients
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    // This notifies clients about the amount burnt
    event Burn(address indexed from, uint256 value);

    /**
     * Constructor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     */
    constructor(
        uint256 initialSupply,
        string memory tokenName,
        string memory tokenSymbol
    ) public {
        totalSupply = initialSupply * 10 ** uint256(decimals);  // Update total supply with the decimal amount
        balanceOf[msg.sender] = totalSupply;                // Give the creator all initial tokens
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
        emit Transfer(address(0), msg.sender, totalSupply);

    }

    /**
     * Internal transfer, only can be called by this contract
     */
    function _transfer(address _from, address _to, uint _value) internal {
        // Prevent transfer to 0x0 address. Use burn() instead
        require(_to != address(0x0));
        // Check if the sender has enough
        require(balanceOf[_from] >= _value);
        // Check for overflows
        require(balanceOf[_to] + _value >= balanceOf[_to]);
        // Save this for an assertion in the future
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        // Subtract from the sender
        balanceOf[_from] -= _value;
        // Add the same to the recipient
        balanceOf[_to] += _value;
        emit Transfer(_from, _to, _value);
        // Asserts are used to use static analysis to find bugs in your code. They should never fail
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    /**
     * Transfer tokens
     *
     * Send `_value` tokens to `_to` from your account
     *
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transfer(address _to, uint256 _value) public returns (bool success) {
        _transfer(msg.sender, _to, _value);
        return true;
    }

    /**
     * Transfer tokens from other address
     *
     * Send `_value` tokens to `_to` on behalf of `_from`
     *
     * @param _from The address of the sender
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    /**
     * Set allowance for other address
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     */
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
     * Set allowance for other address and notify
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     * @param _extraData some extra information to send to the approved contract
     */
    function approveAndCall(address _spender, uint256 _value, bytes memory _extraData)
        public
        returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, address(this), _extraData);
            return true;
        }
    }

    /**
     * Destroy tokens
     *
     * Remove `_value` tokens from the system irreversibly
     *
     * @param _value the amount of money to burn
     */
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
        balanceOf[msg.sender] -= _value;            // Subtract from the sender
        totalSupply -= _value;                      // Updates totalSupply
        emit Burn(msg.sender, _value);
        return true;
    }

    /**
     * Destroy tokens from other account
     *
     * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
     *
     * @param _from the address of the sender
     * @param _value the amount of money to burn
     */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);                // Check if the targeted balance is enough
        require(_value <= allowance[_from][msg.sender]);    // Check allowance
        balanceOf[_from] -= _value;                         // Subtract from the targeted balance
        allowance[_from][msg.sender] -= _value;             // Subtract from the sender's allowance
        totalSupply -= _value;                              // Update totalSupply
        emit Burn(_from, _value);
        return true;
    }
}

$ brownie compile
$ ganache-cli
Ganache CLI v6.12.2 (ganache-core: 2.13.2)
(node:179457) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node –trace-deprecation …` to show where the warning was created)

Available Accounts
==================
(0) 0xe866BE96aA793C69dc4CB69D717D12e7b0d5267d (100 ETH)
(1) 0x0696f9fB2fFe037F6E13Deba40912562f97faDC2 (100 ETH)
(2) 0x3785c546Fe6Fc72a7468059d4f7eE6f3d4727F2C (100 ETH)
(3) 0x11165cCc75b3E917C9918C529778c9cE4E58d513 (100 ETH)
(4) 0x3B26Bfe04381231728b9ca3bbC42435aa6D2155e (100 ETH)
(5) 0x9aA0b1bd92d42Da1cA1e842A05Ec5c69F3Dcd123 (100 ETH)
(6) 0x0aC021eCA14d61880693fd6Cd0FAAD598f208778 (100 ETH)
(7) 0xbd07f6ad435698D878f94D9A29337E09c51fd900 (100 ETH)
(8) 0xb8d7f305778207E48A1b70D1D54226ABd76156De (100 ETH)
(9) 0x7e41f77B97d567178A1443E2fe44d3168111BaF6 (100 ETH)

Private Keys
==================
// 省略

HD Wallet
==================
Mnemonic: course acid cereal genuine old blind someone ticket thrive palace napkin time
Base HD Path: m/44’/60’/0’/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Call Gas Limit
==================
9007199254740991

Listening on 127.0.0.1:8545

script/deploy_token.py

from brownie import accounts, config, TokenERC20

initial_supply = 1000000000000000000000  # 1000
token_name = "Hpscript"
token_symbol = "HPS"

def main():
    account = accounts.add(config["wallets"]["from_key"])
    erc20 = TokenERC20.deploy(
        initial_supply, token_name, token_symbol, {"from": account} , publish_source=True 
    )

brownie-config.yaml

dependencies:
  - OpenZeppelin/openzeppelin-contracts@3.4.0
compiler:
  solc:
    remappings:
      - '@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0'
dotenv: .env
wallets:
  from_key: ${PRIVATE_KEY}

.env

export WEB3_INFURA_PROJECT_ID=''
export PRIVATE_KEY=''
export ETHERSCAN_TOKEN=''

$ source .env
$ brownie run scripts/deploy_token.py –network sepolia

スマートコントラクトで作るのか… なるほどね〜

【React.js】setTimoutでJsonファイルを取得して表示したい

jsonを用意します。

{
    "name": "Morpheush1"
}
let dom = document.querySelector('#root');

class Welcome extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: null,
      };
    }
  
    componentDidMount() {
        this.timer = setInterval(
            () => 
                fetch('./data/test.json').then(response => {
                    return response.json();
                    }).then(json => {
                        this.setState({ data: json});
                    }),
            1000,
        );
    }

    componentWillUnmount() {
        clearInterval(this.timer);
    }
  
    render() {
      if (this.state.data) {
        return <p>{this.state.data.name}</p>
      }
      else {
        return <div>Loading...</div>
      }
    }
  }

let el = (
    <div>
        <Welcome/>
    </div>
);

ReactDOM.render(el, dom);

jsonを更新すると、ページも更新されるのがわかります。

OKやな

jsonが入れ子の場合

[{"name": "Morpheush4"},{"name": "Morpheush5"}]

js側
this.state.data[0]

サーバ側でデータを作る際に、入れ子のjsonデータを作らないといけない。
なるほど〜 これはちょっと厄介やな…

【Next.js】レイアウトを作っていく

components/Layout.js

import React, { Component } from 'react';
import Header from '../components/Header';
import Footer from '../components/Footer';
import style from '../static/Style';

class Layout extends Component {

    render() {
        return (<div>
            {style}
            <Header header={this.props.header}
                title={this.props.title} />
            {this.props.children}
            <Footer footer="copyright hogehoge."/>
        </div>)
    }
}
export default Layout;

components/Header.js

import React, {Component} from 'react';

class Header extends Component {
    render() {
        return (<header>
            <div>{this.props.header}</div>
            <h1>{this.props.title}</h1>
        </header>)
    }
}
export default Header;

components/Footer.js

import React, {Component} from 'react';

class Footer extends Component {
    render() {
        return (<footer>
            <div>{this.props.footer}</div>
        </footer>)
    }
}
export default Footer;

static/Style.js

export default <style>{`
    body {
        margin:10px;
        padding: 5px;
        color: #669;
    }
    header {
        font-size: 64pt;
        font-weight: bold;
        text-align:right;
        letter-spacing: -8px;
        color: #ddddff;
        margin: -32px 5px;
    }
    footer {
        color:#99c;
        font-size:12pt;
        text-align:right;
        border-bottom:1px solid #99c;
        margin: 50px 0px 10px 0px;
        position: relative;
        bottom: 10px;
        right: 10px;
        left: 10px;
    }
    h1 {
        font-size:68pt;
        font-weight:bold;
        text-align:right;
        letter-spacing:-8px;
        color:#f0f0f0;
        margin:-32px 0px;
    }
    p {
        margin:0px;
        color:#666;
        font-size:16pt;
    }
`}</style>

index.js

import Link from 'next/link';
import Layout from '../components/Layout';

export default () => (
    <Layout header="Next" title="Top page.">
        <p>Welcome to next.js!</p>
        <hr />
        <Link href="./other">
            <button>go to Other &gt;&gt;</button>
        </Link>
    </Layout>
);

other.js

import Link from 'next/link';
import Layout from '../components/Layout';


export default () => (
    <Layout header="Other" title="Other page.">
        <p>This is other page.</p>
        <hr />
        <Link href="./">
            <button>&lt;&lt; Back to Top</button>
        </Link>
    </Layout>
);

import React, { Component } from 'react';

class Image extends Component {
    constructor(props) {
        super(props);
        this.fname = "./static/" + props.fname;
        this.size = props.size + "px";
    }

    render() {
        return (
            <img width={this.size} border="1"
                src={this.fname} />
        );
    }
}
export default Image;

なるほど、面白いと言えば面白い。

【Next.js】基本的な使い方と特徴

– Next.jsはjsのみ。HTMLファイルは使わずに開発を行う
– Netx.jsでは、Reactとは異なり、複数ページ開発できる

{
    "scripts": {
        "dev": "next",
        "build": "next build",
        "start": "next start",
        "export": "next export"
    }
}

$ npm install –save next react react-dom

pages/index.js

export default () => <div>
    <h1>Next.js</h1>
    <div>Welcome to next.js!</div>
</div>

$ npm run dev

next.config.js

module.exports = {
    exportPathMap: function() {
        return {
            '/': {page: '/'}
        }
    }
}

$ npm run build

const h1 = {
    fontSize:'72pt',
    fontWeight:'bold',
    textAlign:'right',
    letterSpacing:'-8px',
    color:'#f0f0f0',
    margin:'-40px 0px'
}

const p = {
    margin:'0px',
    color:'#666',
    fontSize:'16pt'
}


export default () => <div>
    <h1 style={h1}>Next.js</h1>
    <p style={p}>Welcome to next.js!</p>
</div>

### 複数ページの開発
index.js

import Link from 'next/link';

const h1 = {
    fontSize:'72pt',
    fontWeight:'bold',
    textAlign:'right',
    letterSpacing:'-8px',
    color:'#f0f0f0',
    margin:'-40px 0px'
}

const p = {
    margin:'0px',
    color:'#666',
    fontSize:'16pt'
}


export default () => <div>
    <h1 style={h1}>Next.js</h1>
    <p style={p}>Welcome to next.js!</p>
    <hr />
    <div>
        <Link href="/other">
            Go to Other page &gt;&gt;
        </Link>
    </div>
</div>

other.js

import Link from 'next/link';

const h1 = {
    fontSize:'72pt',
    fontWeight:'bold',
    textAlign:'right',
    letterSpacing:'-8px',
    color:'#f0f0f0',
    margin:'-40px 0px'
}

const p = {
    margin:'0px',
    color:'#666',
    fontSize:'16pt'
}


export default () => <div>
    <h1 style={h1}>Next.js</h1>
    <p style={p}>This is Other page.</p>
    <hr />
    <div>
        <Link href="/">
            &lt;&lt;Back to Index page
        </Link>
    </div>
</div>

### Component
Counter.js

import React, { Component } from 'react';

export default class Counter extends Component {
    msgStyle = {
        fontSize:"16pt",
        backgroundColor:"#eef",
        padding:"5px"
    }

    constructor(props) {
        super(props);
        this.state = {
            counter:0,
            msg: 'counter: 0',
        };
        this.doAction = this.doAction.bind(this);
    }

    doAction() {
        this.setState((state) => {
            const num = state.counter + 1;
            return ({
                counter: num,
                msg: "counter: " + num
            });
        });
    }

    render() {
        return <p onClick={this.doAction}
            style={this.msgStyle}>
            {this.state.msg}
        </p>;
    }
}
import Counter from '../components/Counter';
import style from '../static/Style';

export default () => <div>
    {style}
    <h1>Next.js</h1>
    <p>Welcome to next.js!</p>
    <hr />
    <Counter />
</div>

Reactをより使いやすくした って感じやね

【React.js】コンポーネントの様々な機能

import React, {Component} from 'react';
import Rect from "./Rect";
import './App.css';

class App extends Component {

  input = '';

  msgStyle = {
    fontSize:"20pt",
    color:"#900",
    margin:"20px 0px",
    padding: "5px",
  }
  inputStyle = {
    fontSize: "12pt",
    padding: "5px"
  }

  constructor(props) {
    super(props);
    this.state = {
      message:'type your name:'
    };
    this.doChange = this.doChange.bind(this);
    this.doSubmit = this.doSubmit.bind(this);
  }

  doChange(event) {
    this.input = event.target.value;
  }

  doSubmit(event) {
    this.setState({
      message: 'Hello, ' + this.input + '!!'
    });
    event.preventDefault();
  }
  render() {
    return <div className="App">
    <h1>React</h1>
    <h2>{this.state.message}</h2>
    <form onSubmit={this.doSubmit}>
      <label>
        <span style={this.inputStyle}></span>Message:
        <input type="text" style={this.inputStyle} onChange={this.doChange} required pattern="[A-Za-z _,.]+"/>
      </label>
      <input type="submit" style={this.inputStyle} value="Click" />
    </form>
  </div>;
  }
}

import React, {Component} from 'react';
import Rect from "./Rect";
import './App.css';

class App extends Component {

  input = '';

  msgStyle = {
    fontSize:"20pt",
    color:"#900",
    margin:"20px 0px",
    padding: "5px",
  }
  constructor(props) {
    super(props);
    this.state = {
      message:'type your name:'
    };
    this.doCheck = this.doCheck.bind(this);
  }

  doCheck(event) {
    alert(event.target.value +
      "は長すぎます。(最大10文字)"
    );
  }

  render() {
    return <div className="App">
    <h1>React</h1>
    <h2>{this.state.message}</h2>
    <Message maxlength="10" onCheck={this.doCheck} />
  </div>;
  }
}

class Message extends Component {
  inputStyle = {
    fontSize:"12pt",
    padding:"5px"
  }

  constructor(props) {
    super(props);
    this.doChange = this.doChange.bind(this);
  }

  doChange(e) {
    if(e.target.value.length > this.props.maxlength) {
      this.props.onCheck(e);
      e.target.value =
        e.target.value.substr(0,this.props.maxlength);
    }
  }

  render() {
    return <input type="text" style={this.inputStyle} onChange={this.doChange} />
  }
}

export default App;

### コンテキスト

import React, {Component} from 'react';
import Rect from "./Rect";
import './App.css';

let data = {title: 'Title',
  message: 'this is sample message.'
};

const SampleContext = React.createContext(data);

class App extends Component {

  render() {
    return <div className="App">
    <h1>Context</h1>
    <Title />
    <Message />
  </div>;
  }
}

class Title extends Component {
  static contextType = SampleContext;

  render() {
    return (
      <div>
        <h2>{this.context.title}</h2>
      </div>
    );
  }
}

class Message extends Component {
  static contextType = SampleContext;

  render() {
    return (
      <div>
        <p>{this.context.message}</p>
      </div>
    )
  }
}

export default App;
import React, {Component} from 'react';
import Rect from "./Rect";
import './App.css';

let theme = {
  light: {
    backgroundColor: "#eef",
    color: "#006",
    padding:"10px",
  },
  dark: {
    backgroundColor:"#006",
    color:"#eef",
    padding:"10px",
  }
};

const ThemeContext = React.createContext(theme.dark);

class App extends Component {

  static contextType = ThemeContext;

  render() {
    return <div className="App" style={this.context}>
    <h1>Context</h1>
    <Title value="Content page" />
    <Message value="This is Content sample."/>
    <Message value="これはテーマのサンプルです。"/>
  </div>;
  }
}

class Title extends Component {
  static contextType = ThemeContext;

  render() {
    return (
      <div>
        <h2 style={this.context}>{this.props.value}</h2>
      </div>
    );
  }
}

class Message extends Component {
  static contextType = ThemeContext;

  render() {
    return (
      <div>
        <p style={this.context}>{this.props.value}</p>
      </div>
    )
  }
}

export default App;