SQLの窓

2012年09月29日

App クラスを介してページ間の参照 / Windows Phone(C#)

App.xaml.css 全体

App クラスにプロパティを定義
// メインページのインスタンスを格納
public MainPage mainPage { get; set; }
public Page1 page1 { get; set; }

※ 宣言を static にすると、キャストが必要無くなります。


MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage
{
	// コンストラクター
	public MainPage()
	{
		InitializeComponent();

		// メインページの参照を App のプロパティにセット
		(App.Current as App).mainPage = this;
	}

	private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
	{

		if ((App.Current as App).page1 != null)
		{
			// ページ1のクラス
			Debug.WriteLine((App.Current as App).page1.GetType());
			// Page1 のページタイトル
			Debug.WriteLine((App.Current as App).page1.PageTitle.Text);
		}

		Debug.WriteLine(((ApplicationBarMenuItem)sender).Text + " がクリックされました");
		this.NavigationService.Navigate(new Uri("/Page1.xaml", UriKind.Relative));

	}

}

Page1.xaml.cs
public partial class Page1 : PhoneApplicationPage
{
	public Page1()
	{
		InitializeComponent();

		// ページ1の参照を App のプロパティにセット
		(App.Current as App).page1 = this;

	}
}




posted by at 2012-09-29 14:42 | Windows Phone | このブログの読者になる | 更新情報をチェックする

『Windows8(C#) 2ページテンプレート』で、2ページ目で HttpClient で JSON データをバインドする

テンプレート

Windows8(C#) 2ページテンプレート

データ

http://textt.net/sworc/20120924055943.txt

JSON処理

JSON.net の文字列から内容の参照のバターンサンプルがわりと全く無かったので作成
Json.NET - James Newton-King

BasicPage1.xaml.cs 内では、直接 DataContext にセットしているので、その時点でバインドされて表示されます。
<!-- HttpClient で取り出すデータの為に追加した TextBox -->
<TextBox
	x:Name="TextBox1"
	HorizontalAlignment="Left"
	Height="26" 
	Margin="128,34,0,0" 
	Grid.Row="1" 
	TextWrapping="Wrap" 
	Text="{Binding Path=id}" 
	VerticalAlignment="Top" 
	Width="143">
</TextBox>


BasicPage1.xaml.cs
namespace App74
{
	public sealed partial class BasicPage1 : App74.Common.LayoutAwarePage
	{
		private HttpClient httpClient;
		private string responseBodyAsText;
		private Class1 class1 = new Class1();

		public BasicPage1()
		{
			this.InitializeComponent();
			this.init();
		}

		private async void init()
		{
			httpClient = new HttpClient();
			httpClient.MaxResponseContentBufferSize = 256000;
			httpClient.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
			HttpResponseMessage response = await httpClient.GetAsync("http://textt.net/sworc/20120924055943.txt");
			response.EnsureSuccessStatusCode();

			responseBodyAsText = await response.Content.ReadAsStringAsync();
			class1 = JsonConvert.DeserializeObject<Class1>(responseBodyAsText);
			TextBox1.DataContext = class1;
//			class1.NotifyPropertyChanged("id");

		}

		protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
		{
		}

		protected override void SaveState(Dictionary<String, Object> pageState)
		{
		}
	}
}

オブジェクトのすべてのプロパティが変更されたことを示すには、PropertyChangedEventArgs の PropertyName プロパティに String.Empty を使います

HttpClient のサンプルソースは、こちらから参照できます。

Microsoft のドキュメントならこのページです。

バイント用のクラス : Class1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;



namespace App74
{
	class Class1 : INotifyPropertyChanged
	{

		public Class1()
		{
		}

		public event PropertyChangedEventHandler PropertyChanged;

		public string id { get; set; }

		public void NotifyPropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
			{
				PropertyChanged(this,
					new PropertyChangedEventArgs(propertyName));
			}
		}
	}
}

※ id のみ実装しています

ドキュメントリンク

windows8


posted by at 2012-09-29 13:56 | Windows8 Metro style | このブログの読者になる | 更新情報をチェックする

2012年09月24日

JSON.net の文字列から内容の参照のバターンサンプルがわりと全く無かったので作成

だいぶ前、VB.net で同じような事したんですが、だいぶ変わっていたし、全部見て無いですが、対象によって違うかもしれません。これは Windows Phone の C# です(Windows8 のC# でも動作しました)。

JSON データの整形は、http://winofsql.jp/php/cnvtext/frame.htm から、『JavaScript整形』で可能です。

※ DynamicJson は Windows Phone の環境で使えません。
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Diagnostics;
// PropertyChangedEventHandler
using System.ComponentModel;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace PhoneApp1
{
	public class Class1 : INotifyPropertyChanged
	{
		public Class1(){

			WebClient webClient = new WebClient();

			webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
			// 外部サービスから文字列を取得
			webClient.DownloadStringAsync(new System.Uri("http://textt.net/sworc/20120924055943.txt"));
		}

		// ページ名プロパティ( バインド用 )
		public string pageName { get; set; }

		private void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
		{
			if (e.Error != null)
			{
				Deployment.Current.Dispatcher.BeginInvoke(() =>
				{
					Debug.WriteLine(e.Error.Message);
				});
			}
			else
			{
				// オーソドックスなデシリアライズ
				Class2 JsonObject = JsonConvert.DeserializeObject<Class2>(e.Result);

				// 定義済のクラスとして参照( 未定義のプロパティは無視 )
				Debug.WriteLine(JsonObject.id);
				Debug.WriteLine(JsonObject.profile_background_image_url_https);

				// 文字列から JObject を作成
				JObject jo =  JObject.Parse(e.Result);

				// JObject で参照
				Debug.WriteLine(jo["id"]);
				Debug.WriteLine(jo["profile_background_image_url_https"]);

				// JToken で参照
				foreach (JToken jt in jo.Children())
				{
					Debug.WriteLine("-->" + jt.ToString());
					Debug.WriteLine("-->" + jt.First);
					
				}

				// JProperty で参照
				foreach (JProperty jp in jo.Properties())
				{
					Debug.WriteLine( jp.Name + "-->" + jp.Value.ToString());
				}

			}
		}

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

	}
}


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace PhoneApp1
{
	public class Class2
	{
		public int id { get; set; }
		public string profile_background_image_url_https { get; set; }
	}
}




posted by at 2012-09-24 21:42 | C# | このブログの読者になる | 更新情報をチェックする

2012年09月23日

家に持ち帰った mdb で簡単に php からアクセスしてテストプログラムを作る( DBクラス付き )

もう、いまどき PHP + DB なんてのは、仕事でしか書かないですが・・・

こんなことする人もまれだとは思いますが、知ってると結構便利だと思いますよ。
<?
header( "Content-Type: text/html; Charset=shift_jis" );
header( "pragma: no-cache" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "Cache-control: no-cache" );

require_once("db.php");

$connect_string = "Provider=MSDASQL;";
$connect_string .= "Driver={Microsoft Access Driver (*.mdb)};";
$connect_string .= "dbq=C:\\httpd142p\\lightbox\\work\\allad.mdb;";

$db = new DB( "", $connect_string );

$query = "select * from [TMP_当日出席者一覧] order by [時限],[科目],[氏名]";

$column = $db->query_ex( $query );

while ( $column ) {
	print "<pre>";
	print_r( $column );
	print "</pre>";

	$column = $db->query_ex( );
};

$db->close();

?>


<?
# **********************************************************
# データベースクラス
# **********************************************************
class DB {
 
	var $connect;
	var $result;
 
# **********************************************************
# コンストラクタ
# **********************************************************
	function DB( $server='127.0.0.1', $db_name='lightbox', $user='', $password='' ) {

		$this->connect = odbc_connect($db_name, $user, $password);
	}
 
# **********************************************************
# 接続解除
# **********************************************************
	function close( ) {
		odbc_close( $this->connect );
	}
 
# **********************************************************
# クエリー
# **********************************************************
	function query( $sql_query ) {

		$ret = odbc_exec( $this->connect, $sql_query );
		return $ret;
	}
 
# **********************************************************
# フェッチ
# **********************************************************
	function fetch( $result ) {

		$ret = odbc_fetch_array( $result );
		$ret2 = $ret;
		$cnt = 0;
		while (list($_key, $_value) = @each($ret)) {
			$ret2[$cnt] = $_value;
			$cnt++;
		}
		return $ret2;
	}
 
# **********************************************************
# クエリーとフェッチ
# **********************************************************
	function query_ex( $sql_query='' ) {
 
		if ( $sql_query != '' ) {
			$this->result = $this->query( $sql_query );
			if ( !$this->result ) {
				return false;
			}
			return $this->fetch( $this->result );
		}
		else {
			return $this->fetch( $this->result );
		}
 
	}
 
# **********************************************************
# 実行
# **********************************************************
	function Execute( $sql_exec ) {
		$ret = odbc_exec( $this->connect, $sql_exec );
		return $ret;
	}
 
 
}
?>
最近仕事場の古い SQLServer がぶっ壊れて( ハードが古かった )、新しい OS やら、新しい SQLServer やらで結局 PHP からアクセスする DB のドライバは ODBC で総とっかえしました。これが一番簡単で安全だという結果になっています( 複雑な事してないので )

ちょっと関係する記事

ODBC の動的接続
ピンポイントですが、SQLServer 2008 は SQLServer 7.0 のデータをロード出来ないのです
SQLExpress2005 で副問い合わせを含む VIEW が異常終了しました
Microsoft Drivers 3.0 for PHP for SQL Server が実運用では役に立たない件について


posted by at 2012-09-23 23:57 | PHP+DB | このブログの読者になる | 更新情報をチェックする

android-binding で、BindingActivityV30 を使う方法



赤い枠の中が重要ですが、res の下に xml フォルダを作成して以下のように xml レイアウトファイルを作成した下さい
<?xml version="1.0" encoding="utf-8"?>
<activity xmlns:binding="http://www.gueei.com/android-binding/">
		<rootView
            binding:dataSource="RootViewViewModel"
                binding:layoutId="@layout/activity_main"/>
        <optionsMenu
            binding:dataSource="OptionsMenuViewModel"
            binding:menu="@menu/activity_main"/>
</activity>

後は、バインド用のクラスを3つ作ってそれぞれを順に作成してバインドさせます。
★ MainActivity.java
package com.example.allbind;

import gueei.binding.v30.app.BindingActivityV30;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.support.v4.app.NavUtils;

public class MainActivity extends BindingActivityV30 {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ViewModel vm = new ViewModel();
        this.inflateAndBind(R.xml.bav30, vm);
    }
    
}


★ ViewModel.java
package com.example.allbind;

import gueei.binding.observables.ObjectObservable;
import gueei.binding.pojo.PojoViewModel;
import gueei.binding.pojo.PojoViewModelHelper;

public class ViewModel  implements PojoViewModel {

    private PojoViewModelHelper helper = new PojoViewModelHelper();
    
    public final ObjectObservable RootViewViewModel =
    		new ObjectObservable(new RootViewViewModel()); 
    public final ObjectObservable OptionsMenuViewModel = 
    		new ObjectObservable(new OptionsMenuViewModel()); 
 
    @Override
    public PojoViewModelHelper getHelper() {
        return helper;
    }
 
    @Override
    public void notifyPropertyChanged( String propertyName ) {
        helper.notifyPropertyChanged( propertyName );
    }

}


★ RootViewViewModel.java
package com.example.allbind;

import gueei.binding.observables.StringObservable;
import gueei.binding.pojo.PojoViewModel;
import gueei.binding.pojo.PojoViewModelHelper;

public class RootViewViewModel implements PojoViewModel {

    private PojoViewModelHelper helper = new PojoViewModelHelper();
    
    public final StringObservable hello = new StringObservable("こんにちは");
 
    @Override
    public PojoViewModelHelper getHelper() {
        return helper;
    }
 
    @Override
    public void notifyPropertyChanged( String propertyName ) {
        helper.notifyPropertyChanged( propertyName );
    }

}


★ OptionsMenuViewModel.java
package com.example.allbind;

import gueei.binding.observables.StringObservable;
import gueei.binding.pojo.PojoViewModel;
import gueei.binding.pojo.PojoViewModelHelper;

public class OptionsMenuViewModel implements PojoViewModel {

    private PojoViewModelHelper helper = new PojoViewModelHelper();
    
    public final StringObservable menu_settings = new StringObservable("設定");
 
    @Override
    public PojoViewModelHelper getHelper() {
        return helper;
    }
 
    @Override
    public void notifyPropertyChanged( String propertyName ) {
        helper.notifyPropertyChanged( propertyName );
    }

}





▼ プロジェクトの作成の基本は以下から参照して下さい
android-binding を使って Windows C#(XAML) のようなバインド処理の実装


posted by at 2012-09-23 01:30 | Android | このブログの読者になる | 更新情報をチェックする

2012年09月20日

android-binding を使って Windows C#(XAML) のようなバインド処理の実装

プロジェクト作成











コンパイラのバージョン設定( 一般 )



android-binding-v30-0.52.jar を参照

( lib に保存して参照します )





Appication クラス作成





android-binding を初期化して使用可能にします。
package com.example.textbinding;

import android.app.Application;
import gueei.binding.Binder;

public class BindTest extends Application {
	
    @Override
    public void onCreate() {
        super.onCreate();
 
        Binder.init(this);
        // BinderV30.init(this); と書くのが最新のようです
    }

}

AndroidManifest に Application を登録



画面定義

binding: で記述される部分がバインド用です。これを使用すると、イベント名を記述してその名前に対してイヘント処理を java 側で記述可能になります。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:binding="http://www.gueei.com/android-binding/"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:padding="@dimen/padding_medium"
        tools:context=".MainActivity" 
        binding:text="hello" />

</RelativeLayout>


Activity と バインド用クラス

(MainActivity.java)

package com.example.textbinding;

import gueei.binding.Binder;
import gueei.binding.app.BindingActivity;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.support.v4.app.NavUtils;

public class MainActivity extends BindingActivity {

    private TestViewModel viewModel = new TestViewModel();
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        View view = Binder.bindView( 
        		this,
        		Binder.inflateView( this, R.layout.activity_main, null, false ),
        		viewModel );
        
        setContentView( view );
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    
}

this.setAndBindRootView(R.layout.activity_main, viewModel);
( 20 〜 25 のかわりにこうするのが最新のようです )
※ BindingActivity が重要

(TestViewModel.java)

package com.example.textbinding;

import gueei.binding.observables.StringObservable;
import gueei.binding.pojo.PojoViewModel;
import gueei.binding.pojo.PojoViewModelHelper;

public class TestViewModel implements PojoViewModel {

    private PojoViewModelHelper helper = new PojoViewModelHelper();
    
    public final StringObservable hello = new StringObservable("こんにちは");
 
    @Override
    public PojoViewModelHelper getHelper() {
        return helper;
    }
 
    @Override
    public void notifyPropertyChanged( String propertyName ) {
        helper.notifyPropertyChanged( propertyName );
    }

}




関連する記事

android-binding を使用した、固定値、イベント、オプションメニューの構築


posted by at 2012-09-20 22:24 | Android | このブログの読者になる | 更新情報をチェックする

Windows8 の最新版で、C#のテンプレート(Windows ストア)で、ページを追加すると固まるというバグがあるので、テンプレートを作って回避しています。

v6.2 build 9200




「C:\Users\ユーザ名\Documents\Visual Studio 2012\Templates\ProjectTemplates\Visual C#」ディレクトリに「Windows Store」ディレクトリを作成し、その中にテンプレートを入れる

かなり酷いバグです。Windows8 の問題では無く、Visual Studio の問題だとは思いますが、10数人で実行してとてもとても高い確率(ほぼ、殆ど)で発生します。

ページを追加する際に、新しいクラステンプレートファイルがいくつか Common フォルダに追加され、BasicPage1.xaml と BasicPage1.xaml.cs が追加されるのですが( MainPage.xaml と同じ場所 )、その後プロジェクトに登録するところでフリーズします。

ですから、いったん Visual Studio を強制終了させて、それらの追加されたファイルを『既存』として追加登録すれば正常な状態になります・・・が、いちいちフリーズさせてられないので、『クイック スタート: アプリ バーの追加』にある内容を実装してテンプレート化してあります。
( アプリバーの『HELP』をクリックすると、BasicPage1に移動 )

この際、Common フォルダにある StandardStyles.xaml の該当するコメント部分を解除しないと、StaticResource EditAppBarButtonStyle 等がエラーになるのでその処理も済ませてあります。

しかし・・・相当酷いバグですね・・・。

ページをさらに追加したい場合は、BasicPage1.xaml 部分で CTRL+C して CTRL+V すると、通常のエクスプローラと同様にコピーされるので( .cs も同時コピーされます )、名前を BasicPage2.xaml に変更してから、中身の BasicPage1 の 1 を 2 を全て変更するとページ追加になります。( BasicPage1.xaml と BasicPage1.xaml.cs と両方行って下さい )



posted by at 2012-09-20 03:55 | Windows8 Metro style | このブログの読者になる | 更新情報をチェックする

2012年09月19日

Three.js r50(2012/08/15) のわけの解らないバグ?と対処方法

3D データをロードすると、テクスチャがめちゃめちゃになるんですが、テクスチャデータを上下反転させると正しく描画されます。

バグというより、仕様変更のようです。最新の ColladaLoader.js で表示すると正しく描画されます。しかし、古いデータ(JSON) を JSONLoader で表示するとやはり上下反転が必要になります。





かなり新しい機能がたくさん実装されているのでいろいろ試したいところですが、とりあえず IEWebGL に対応したという記述があったので試すと、まあなんとか同じ動きを再現できましたなんですが、COLLADA(dae)は loader で XPath(evaluate)使ってるのでIEはそもそも動かないです。 JSONデータ(Blender で作成)だと、JSONLoaderなんで( XMLじゃないので使われる予定も無い )動作します。

IEWebGL のサイトでは、Three.js でテクスチャ使ったサンプル動かしてますし・・・。ウチでは、3Dフォントが動きました。今後まだまだいろいろ動きがあるかもしれません。

※ 追記 : さらに、COLLADA(dae)+Opera NEXT は酷い事になりました




▼ データ( dae ) の phong。emission が 1 なので、ライトは無しでレンダリング。
          <phong>
            <emission>
              <color sid="emission">1 1 1 1</color>
            </emission>
            <ambient>
              <color sid="ambient">0 0 0 1</color>
            </ambient>
            <diffuse>
              <texture texture="eyes_png-sampler" texcoord="UVMap"/>
            </diffuse>
            <specular>
              <color sid="specular">0 0 0 1</color>
            </specular>
            <shininess>
              <float sid="shininess">50</float>
            </shininess>
            <index_of_refraction>
              <float sid="index_of_refraction">1</float>
            </index_of_refraction>
          </phong>



posted by at 2012-09-19 00:10 | Three.js : その他 | このブログの読者になる | 更新情報をチェックする

2012年09月10日

DAZ3D : ドラゴンの相棒 / DAZStudio4 / Victoria ベース、エルフ系 Night Hawk



WindowsXP+DAZStudio3 で過去に作成したデータを Windows7+DAZStudio4 に移行して、DAZStudio4 に付属していたドラゴン(角を一番長い状態に調整)を背後に追加。レンダリングデータを Pixlr Express で加工して出力したもの。( エルフの耳は D-Former で作成 )


000



001



002



003



004




背景は、透過( レンダリング時は黒 )ですが、shadowbox だと黒で表示されていい感じ。


タグ:DAZ3D
posted by at 2012-09-10 00:21 | DAZ3D | このブログの読者になる | 更新情報をチェックする

2012年09月06日

Windows Phone 8 SDK

Windows Phone 8 SDK について

先日来校されて Windows Phone の講義をしていただいた、高橋 忍さんのブログで紹介されていましたが、高橋さんは訳しておられるだけで、本編はこちらです。

結局、完全な SDK がリリースされるのは年明けだろうと思われます。早くても、年末のようなニュアンスなので、本編のコメント欄は結構な不満だらけになっています。

確かに、昨日( 米国時間の9/5 )、ノキアは 『Nokia Lumia 920』を発表したばかりですが、価格や発売時期には言及されなかった上に、投資家が興味を持つような『革新的』な材料は無いとして逆に株価は落ちたそうです。






関連する記事

ノキアが「ウィンドウズフォン8」搭載のスマホ発表、株価は急落 | Reuters


こんなタイミングで不完全な Windows Phone 8 SDK に関する良く解らない記事はとても褒められたものでは無いと思うのですが、本当に Microsoft は大丈夫なんでしょうか。冗談抜きで心配です。



posted by at 2012-09-06 20:04 | Windows | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します


Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX