package rabbit.haa;

import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Toolkit;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.Stack;
import java.util.concurrent.Semaphore;

import javax.swing.text.html.HTML;

import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.LocationAdapter;
import org.eclipse.swt.browser.LocationEvent;
import org.eclipse.swt.browser.LocationListener;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolder2Adapter;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.CoolItem;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import rabbit.haa.HaAForm.Factor;
import rabbit.util.HTMLTokenizer;
import rabbit.util.SWTDialog;
import rabbit.util.SWTMoveWindow;
// Help bg 0xf0,0xf5,0xf0
public class HaAggregater {
	private static final boolean _DEBUG_MODE = false;

	static final boolean _TRACE = false;
	static final boolean _HELP_DELETE_ON_EXIT = true;
	private long _exec_time = System.currentTimeMillis();

	static final int HELP_BUF_SIZE = 1024 * 1024 * 5;

	boolean _isLogin;

	Shell _shell;

	Browser _browser;

	String _prefix = "HAA（はてなアクセス集計）";

	String _title;
	
	JAFactor _jaf;

	Button _bRefresh;

	Label _lStatus;

	Button _bLExec;

	Button _cbExecAll;

	CTabFolder _folder;

	Hashtable<String, Object> _hData = new Hashtable<>();

	private static final int _DEFAULT_SASH_WIDTH = 8;

	private static final String _KEY_SASH_WEIGHTS = "SASH_WEIGHTS";

	private static final String _KEY_PAGE_REFRESH = "PAGE_REFRESH";
	private static final String _KEY_PAGE_STOP = "PAGE_STOP";

	private static final String _KEY_TEXT_WRITER = "TEXT_WRITER";
	private static final String _KEY_CSV_WRITER = "_CSV_WRITER";

	private static final String _KEY_TARGET_ID = "_TARGET_ID";
	private static final String _KEY_TARGET_COND = "_TARGET_COND";

	private static final String _KEY_FROM_TO_YEAR = "_FROM_TO_YEAR";
	private static final String _KEY_SORT_DIR = "SORT_DIR";

	protected static final String _KEY_SELECTED_IMAGE = "SELECTED_IMAGE";
	protected static final String _KEY_DESELECTED_IMAGE = "DESELECTED_IMAGE";

	protected static final String _VAL_ACCESS_COUNTS = "\"access-counts\"";
	protected static final String _ID_ACCESS_COUNTS = "access-counts";
	protected static final String _ID_DATA_TIME = "data-time";
	protected static final String _ID_DATA_COUNT = "data-count";

	int _topType;

	static final int _IDX_YYYY = 0;
	static final int _IDX_MM = 1;
	static final int _IDX_DD = 2;
	static final int _IDX_DAYS = 3;
	static final int _IDX_WEEK = 4;
	static final int _IDX_HH = 5;
	static final int _IDX_MM2 = 6;

	static final int _TTYPE_ERROR = -1;

	static final int _TTYPE_BLANK = 0;

	static final int _TTYPE_TOP = 1;

	static final int _TTYPE_HOME = 2;

	static final int _TTYPE_LOGIN = 3;

	static final int _TTYPE_MANAGE= 4;

	int _progressType;

	static final int _PTYPE_END = 0;

	static final int _PTYPE_ACTIVE = 1;

	static final int _PTYPE_STOP = 2;

	static final int _PTYPE_CANCEL = -1;

	static final int _PTYPE_ERROR = -9;

	SWTDialog _pdlg;

	Semaphore _sem = new Semaphore(0);

	Stack<HaACharger> _sCharger = new Stack<>();
	Stack<HaACharger> _sGen = new Stack<>();

	ArrayList<HaAForm> _elist = new ArrayList<>();

	int _BUF_SIZE = 0x100000;
	Properties _prop;

	Spinner _spYearB;
	Spinner _spYearE;

	boolean _isAccessLog;

//	boolean _isParse;

	boolean _about_blank;

	boolean _is_logout;

	String _uid;

	static final long _WAIT_TIME = 1000;

	static final String _PREFIX = "HAA";

	static final String _HAA_HOME = "haa";

	static final String _HAA_TEXT = "txt";

	static int _URL_LENGTH = 200;

	static final String _haa_home_full = "https://blog.hatena.ne.jp";

	static final String _haa_home = _haa_home_full;
	
	static final String _haa_error = "://error.hatena.jp"; // DEBUG


	static final String _haa_suffix = "https://blog.hatena.ne.jp/";

	static final String _haa_login = "https://accounts.hatena.ne.jp/login";

	static final String _haa_login_form = "document.getElementsByName('account_name')[0].value='%s';";

	static final String _haa_id_focus = "document.getElementsByName('account_name')[0].focus();";

	static final String _haa_passwd_focus = "document.getElementsByName('password')[0].focus();";

	static final String _haa_save_passwd = "document.getElementsByName('isSavePass')[0].checked = false;";

	static final String _manage_form = "/manage/";

	static final String _manage_prefix = "/manage/?mode=";

	static final String _manage_top = "/manage/?mode=top";

	static final String _manage_ym = "&ym=";

	static final String _manage_access_form = "/manage/?mode=access&ym=%d%02d";

	static final String _properties_name = ".properties";

	static final String _property_key_bounds = "bounds";
	static final String _property_key_weights = "weights";
	static final String _property_key_uid = "userid";
	static final String _property_key_target = "target";
	static final String _property_key_option = "option";
	static final String _property_key_taboverrided = "taboverrided";
	static final String _property_key_years = "years";
	static final String _property_key_execall = "execall";

	public static void main(String[] args) {
		try {
			new HaAggregater();
		} catch(Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		System.exit(0);
	} // main

	public HaAggregater() {
		setWidgets();
		view();
	}

	static Hashtable<Character, Character> _hDays = new Hashtable<>();

	static {
		Character[] days = {
			(Character)'日',
			(Character)'月',
			(Character)'火',
			(Character)'水',
			(Character)'木',
			(Character)'金',
			(Character)'土',
		};
		Character[] ns = {
				(Character)'0',
				(Character)'1',
				(Character)'2',
				(Character)'3',
				(Character)'4',
				(Character)'5',
				(Character)'6',
			};
		int i, len = days.length;

		for(i=0;i<len;i++) {
			_hDays.put(days[i], ns[i]);
		}
	} // static

	static Image createImage(String path, int alpha) {
		boolean found = false;
		Image image = null;
		InputStream is = HaAggregater.class.getResourceAsStream(path);
		if (is != null) {
			ImageData data = new ImageData(is);
			int w = data.width;
			int h = data.height;
			for(int y=0;y<h;y++) {
				for(int x=0;x<w;x++) {
					if (data.getPixel(x, y) == alpha) {
						data.setAlpha(x, y, 0);
					} else {
						found = true;
					}
				}
			}
			if (!found) {
			// すべてが透明の時
				// Alpha が無効になるので１点最小値を付ける
				data.setAlpha(0, 0, 0x01);
			}
			image = new Image(Display.getDefault(), data);
		}
		return image;
	} // createImage

	void setWidgets() {
		String str;
		Display display = new Display ();
		Shell shell = _shell = new Shell(display);
		_graphFgColor = new Color(display, 0xff, 0xff, 0xe8);
		_graphBgColor = new Color(display, 0xff, 0xa0, 0x00);
		_graphTextColor = new Color(display, 0x00, 0x30, 0x38);
		// ウィンドウのタイトルを指定
		shell.setText(_prefix);
		shell.setLayout(new FillLayout());
		Color scolor = getSeasonColor();
		Properties prop = _prop = new Properties();
		try {
			loadProperties(prop);
		} catch (IOException e) {
			e.printStackTrace();
			MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
			mbox.setText(_prefix);
			mbox.setMessage(e.getMessage());
			mbox.open();
		}
		Image image, simage;
		GridLayout gl;
		GridData gd;
//
		SashForm sf = new SashForm(shell, SWT.VERTICAL);
		sf.setSashWidth(_DEFAULT_SASH_WIDTH);
		sf.setBackground(new Color(null, 0xb0, 0xb0, 0xe0)); // レシーバーの背景色
		sf.setLayout(new FillLayout());
		Composite compSashUpper = new Composite(sf,SWT.NONE);
		compSashUpper.setLayout(new FillLayout());		
// 上段
		Composite compUpper = new Composite(compSashUpper, SWT.NONE);
		compUpper.setBackground(scolor);
		compUpper.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		gl = new GridLayout(1, false);
		gl.marginWidth = 4;
		gl.marginHeight = 2;
		gl.verticalSpacing = 0;
		compUpper.setLayout(gl);

		int lred = Math.min(255, Math.round(1.2f * scolor.getRed()));
		int lgreen = Math.min(255, Math.round(1.2f * scolor.getGreen()));
		int lblue = Math.min(255, Math.round(1.2f * scolor.getBlue()));
		int dred = Math.round(0.7f * scolor.getRed());
		int dgreen = Math.round(0.7f * scolor.getGreen());
		int dblue = Math.round(0.7f * scolor.getBlue());
		int sred = Math.round(0.8f * scolor.getRed());
		int sgreen = Math.round(0.8f * scolor.getGreen());
		int sblue = Math.round(0.8f * scolor.getBlue());
		Color lbcolor = new Color(display, lred, lgreen, lblue);
		Color dbcolor = new Color(display, dred, dgreen, dblue);
		Color dscolor = new Color(display, sred, sgreen, sblue);
// UR
		Composite compH = new Composite(compUpper, SWT.NONE);
		compH.setBackground(scolor);
		compH.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL));
		gl = new GridLayout(6, false);
		gl.marginWidth = gl.marginHeight = 0;
		gl.verticalSpacing = 0;
		gl.horizontalSpacing = 2;
		compH.setLayout(gl);
//
		Composite compLURL = new Composite(compH, SWT.NONE);
		compLURL.setBackground(scolor);
		compLURL.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING|GridData.VERTICAL_ALIGN_FILL));
		gl = new GridLayout(1, false);
		gl.marginWidth = 3;
		gl.marginHeight = 3;
		compLURL.setLayout(gl);
		Label labelURL = new Label(compLURL, SWT.HORIZONTAL);
		labelURL.setBackground(scolor);
		labelURL.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING|GridData.VERTICAL_ALIGN_FILL));
		labelURL.setText("URL");

		Composite compURL = new Composite(compH, SWT.NONE);
		compURL.setBackground(scolor);
		compURL.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		gl = new GridLayout(1, false);
		gl.marginWidth = 0;
		gl.marginHeight = 4;
		gl.horizontalSpacing = gl.verticalSpacing = 0;
		compURL.setLayout(gl);
		compURL.setToolTipText("URL の直接入力はできません");
		Text tURL = new Text(compURL, SWT.NONE);
		tURL.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_END
				|GridData.GRAB_HORIZONTAL));
		tURL.setBackground(new Color(display, 0xfa, 0xfa, 0xe0));
		tURL.setToolTipText("URL の直接入力はできません");
// リフレッシュ・ボタン
		Button bRefresh = _bRefresh = new Button(compH, SWT.PUSH);
		bRefresh.setImage(image =  createImage("images/page_refresh.png", 0xFFFFFF));
		bRefresh.setToolTipText("ページの再読み込み");
// ヘルプ・ボタン
		Button bHelp = new Button(compH, SWT.PUSH);
		bHelp.setImage(createImage("images/help_help.png", 0xFFFFFF));
		bHelp.setToolTipText(_prefix+"ヘルプ");
// 集計
		Composite compBody = new Composite(compUpper, SWT.NONE);
		compBody.setBackground(scolor);
		compBody.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		gl = new GridLayout(2, false);
		gl.marginWidth = 0;
		gl.marginHeight = 2;
		compBody.setLayout(gl);

// 右
		Composite compBorder = new Composite(compBody, SWT.NONE);
		compBorder.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		gl = new GridLayout(1, false);
		gl.marginWidth = gl.marginHeight = 4;
		compBorder.setLayout(gl);
		compBorder.setBackground(dscolor);	// Border Line
		Browser browser = _browser = new Browser(compBorder, SWT.BORDER);
		browser.setData(_KEY_PAGE_REFRESH, image);
		browser.setData(_KEY_PAGE_STOP, createImage("images/page_stop.png", 0xFFFFFF));
		browser.setJavascriptEnabled(true);
		gd = new GridData();
		gd.horizontalAlignment = GridData.FILL;
		gd.verticalAlignment = GridData.FILL;
		gd.horizontalSpan = 10;
		gd.grabExcessHorizontalSpace = true;
		gd.grabExcessVerticalSpace = true;
		browser.setLayoutData(gd);
// 解析--------------------------------------------------------------------------------------------------------
		Composite compSashLower = new Composite(sf,SWT.NONE);
		compSashLower.setLayout(new FillLayout());
		Composite compLower = new Composite(compSashLower, SWT.NONE);
		compLower.setBackground(scolor);
		compLower.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		gl = new GridLayout(1, false);
		gl.marginWidth = gl.marginHeight = 4;
		gl.verticalSpacing = 0;
		compLower.setLayout(gl);
		Composite compLBody = new Composite(compLower, SWT.NONE);
		compLBody.setBackground(scolor);
		compLBody.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		gl = new GridLayout(2, false);
		gl.marginWidth = 0;
		gl.marginHeight = 2;
		compLBody.setLayout(gl);
// 左
		Composite compLL = new Composite(compLBody, SWT.NONE);
		compLL.setBackground(scolor);
		compLL.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_VERTICAL));
		gl = new GridLayout(1, false);
		compLL.setLayout(gl);
// 年の範囲
		Composite compRangeYear = new Composite(compLL, SWT.NONE);
		compRangeYear.setBackground(scolor);
		compRangeYear.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
			|GridData.GRAB_HORIZONTAL));
		gl = new GridLayout(2, false);
		gl.marginWidth = gl.marginHeight = 0;
		gl.verticalSpacing = 8;
		compRangeYear.setLayout(gl);
		Label label = new Label(compRangeYear, SWT.HORIZONTAL);
		label.setBackground(scolor);
		label.setText("年の範囲");
// 開始年
		Composite compYearB = new Composite(compRangeYear, SWT.NONE);
		gl = new GridLayout(1, false);
		gl.horizontalSpacing = 0;
		gl.marginHeight = 0;
		gl.marginWidth = 0;
		gl.verticalSpacing = 0;
		compYearB.setLayout(gl);
//
		Spinner spYearB = _spYearB = new Spinner(compYearB, SWT.NONE);
		GC gc = new GC(spYearB);
		Point sp = gc.stringExtent("99999");
		GridData sgd = new GridData();
		sgd.widthHint = sp.x;
		spYearB.setLayoutData(sgd);
		synchToolTip(spYearB, "作表する年の範囲を指定してください");
		gc.dispose();
// 終了年
		label = new Label(compRangeYear, SWT.HORIZONTAL);
		label.setBackground(scolor);
		label.setAlignment(SWT.RIGHT);
		label.setText("～");
		label.setAlignment(SWT.RIGHT);
		label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
//
		Composite compYearE = new Composite(compRangeYear, SWT.NONE);
		gl = new GridLayout(1, false);
		gl.horizontalSpacing = 0;
		gl.marginHeight = 0;
		gl.marginWidth = 0;
		gl.verticalSpacing = 0;
		compYearE.setLayout(gl);
//
		Spinner spYearE = _spYearE = new Spinner(compYearE, SWT.NONE);
		spYearE.setLayoutData(sgd);
		synchToolTip(spYearE, "作表する年の範囲を指定してください");
		Composite compPad = new Composite(compLL, SWT.NONE);
		compPad.setBackground(scolor);
		gd = new GridData();
		gd.widthHint = 2;
		gd.heightHint = 8;
		compPad.setLayoutData(gd);
// 抽出項目
		label = new Label(compLL, SWT.HORIZONTAL);
		label.setBackground(scolor);
		label.setText("対象／抽出項目");
// 対象項目
		Composite compLSel = new Composite(compLL, SWT.NONE);
		compLSel.setBackground(scolor);
		compLSel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL));
		gl = new GridLayout(2, false);
		gl.marginWidth = gl.marginHeight = 0;
		gl.verticalSpacing = 0;
		compLSel.setLayout(gl);
// 選択項目
		Composite compLTargetL = new Composite(compLSel, SWT.NONE);
		compLTargetL.setBackground(scolor);
		compLTargetL.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL));
		gl = new GridLayout(1, false);
		gl.marginWidth = gl.marginHeight = 2;
		gl.verticalSpacing = 0;
		compLTargetL.setLayout(gl);
// ダミー
		Composite compPad2 = new Composite(compLTargetL, SWT.NONE);
		compPad2.setBackground(scolor);
// 年
		Button rbTargetYear = new Button(compLTargetL, SWT.RADIO);
		rbTargetYear.setBackground(scolor);
		rbTargetYear.setToolTipText("作表する対象項目を選択してください");
// 月
		Button rbTargetMonth = new Button(compLTargetL, SWT.RADIO);
		rbTargetMonth.setBackground(scolor);
		rbTargetMonth.setToolTipText("作表する対象項目を選択してください");
// 曜日
		Button rbTargetDay = new Button(compLTargetL, SWT.RADIO);
		rbTargetDay.setBackground(scolor);
		rbTargetDay.setToolTipText("作表する対象項目を選択してください");
// 日
		Button rbTargetDate = new Button(compLTargetL, SWT.RADIO);
		rbTargetDate.setBackground(scolor);
		rbTargetDate.setToolTipText("作表する対象項目を選択してください");
// 時
		Button rbTargetHour = new Button(compLTargetL, SWT.RADIO);
		rbTargetHour.setBackground(scolor);
		rbTargetHour.setToolTipText("作表する対象項目を選択してください");

// 選択項目
		Composite compLSelL = new Composite(compLSel, SWT.NONE);
		compLSelL.setBackground(scolor);
		compLSelL.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL));
		gl = new GridLayout(1, false);
		gl.marginWidth = gl.marginHeight = 2;
		gl.verticalSpacing = 0;
		compLSelL.setLayout(gl);
// すべて選択
		Button cbSelAll = new Button(compLSelL, SWT.CHECK);
		cbSelAll.setBackground(scolor);
		cbSelAll.setText("すべて選択");
		cbSelAll.setToolTipText("抽出する項目を選択してください");
// 高さを揃える
		gd = new GridData();
		gd.heightHint = cbSelAll.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
		gd.widthHint = 2;
		compPad2.setLayoutData(gd);
// 年
		Button cbSelYear = new Button(compLSelL, SWT.CHECK);
		cbSelYear.setBackground(scolor);
		cbSelYear.setText("年");
		cbSelYear.setToolTipText("抽出する項目を選択してください");
// 月
		Button cbSelMonth = new Button(compLSelL, SWT.CHECK);
		cbSelMonth.setBackground(scolor);
		cbSelMonth.setText("月");
		cbSelMonth.setToolTipText("抽出する項目を選択してください");
// 曜日
		Button cbSelDay = new Button(compLSelL, SWT.CHECK);
		cbSelDay.setBackground(scolor);
		cbSelDay.setText("曜日");
		cbSelDay.setToolTipText("抽出する項目を選択してください");
// 日
		Button cbSelDate = new Button(compLSelL, SWT.CHECK);
		cbSelDate.setBackground(scolor);
		cbSelDate.setText("日");
		cbSelDate.setToolTipText("抽出する項目を選択してください");
// 時（ダミー　これが選択されることはない）
		Button cbSelHour = new Button(compLSelL, SWT.CHECK);
		cbSelHour.setBackground(scolor);
		cbSelHour.setText("時");
		cbSelHour.setToolTipText("抽出する項目を選択してください");
//
		String btrue = new Boolean(true).toString();
		cbSelAll.setSelection(btrue.equals(prop.getProperty(_property_key_option+"0")));
		cbSelYear.setSelection(btrue.equals(prop.getProperty(_property_key_option+"1")));
		cbSelMonth.setSelection(btrue.equals(prop.getProperty(_property_key_option+"2")));
		cbSelDay.setSelection(btrue.equals(prop.getProperty(_property_key_option+"3")));
		cbSelDate.setSelection(btrue.equals(prop.getProperty(_property_key_option+"4")));
		cbSelHour.setSelection(btrue.equals(prop.getProperty(_property_key_option+"5")));
		// 抽出したすべての条件を実行
		Button cbExecAll = _cbExecAll = new Button(compLL, SWT.CHECK);
		cbExecAll.setBackground(scolor);
		cbExecAll.setText("すべての組合せ");
		cbExecAll.setToolTipText("選択した抽出項目のすべての組合せを作表します");
		str = prop.getProperty(_property_key_execall);
		if (String.valueOf(true).equals(str)) {
			cbExecAll.setSelection(true);
		}
// 対象項目
		Composite compLSelB = new Composite(compLL, SWT.NONE);
		compLSelB.setBackground(scolor);
		compLSelB.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
		gl = new GridLayout(1, false);
		gl.marginWidth = 0;
		gl.marginHeight = 8;
		gl.verticalSpacing = 0;
		compLSelB.setLayout(gl);
// 作表実行
		Button bLExec = _bLExec = new Button(compLSelB, SWT.PUSH);
		gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL);
		gd.widthHint = 100;
		gd.heightHint = 50;
		bLExec.setLayoutData(gd);
		bLExec.setText(" 作表 ");
		// 作表可／不可
		bLExec.setEnabled(false);
// 右
//テーブル
		Composite compLBorder = new Composite(compLBody, SWT.NONE);
		compLBorder.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		gl = new GridLayout(1, false);
		gl.marginWidth = gl.marginHeight = 4;
		compLBorder.setLayout(gl);
		compLBorder.setBackground(dscolor);	// Border Line
//
		CTabFolder folder = _folder = new CTabFolder(compLBorder, SWT.BORDER);
		gd = new GridData();
		gd.horizontalAlignment = GridData.FILL;
		gd.verticalAlignment = GridData.FILL;
		gd.horizontalSpan = 10;
		gd.grabExcessHorizontalSpace = true;
		gd.grabExcessVerticalSpace = true;
		folder.setLayoutData(gd);
// フォルダー・コントロール
		CoolBar coolBar = new CoolBar(folder, SWT.FLAT);
		CoolItem citem = new CoolItem (coolBar, SWT.NONE);
	    ToolBar toolBar = new ToolBar(coolBar, SWT.HORIZONTAL);
	    ToolItem tiOverrided = new ToolItem(toolBar, SWT.CHECK);
	    ToolItem tiDeleteOld = new ToolItem(toolBar, SWT.PUSH);
	    ToolItem tiDeleteAll = new ToolItem(toolBar, SWT.PUSH);
		image = createImage("images/overrided.png", -1);
		simage = createImage("images/overridedP.png", -1);
		citem.setControl(toolBar);
//
		tiOverrided.setData(_KEY_DESELECTED_IMAGE, image);
		tiOverrided.setData(_KEY_SELECTED_IMAGE, simage);
		tiDeleteOld.setImage(createImage("images/delete_old.png", -1));
		tiDeleteAll.setImage(createImage("images/delete_all.png", -1));
		tiDeleteOld.setToolTipText("同じ抽出条件の古いタブを削除");
		tiDeleteAll.setToolTipText("すべてのタブを削除");
//
	    toolBar.pack();
	    Point size = toolBar.getSize();
	    citem.setControl(toolBar);
	    Point preferred = citem.computeSize(size.x, size.y);
	    citem.setPreferredSize(preferred);
//
	    FormData coolData = new FormData();
	    coolData.left = new FormAttachment(0);
	    coolData.right = new FormAttachment(100);
	    coolData.top = new FormAttachment(0);
	    coolBar.setLayoutData(coolData);
		folder.setTopRight(coolBar, SWT.RIGHT | SWT.WRAP);
//
		folder.setBackground(lbcolor);
		folder.setSelectionBackground(new Color[]{display.getSystemColor(SWT.COLOR_WHITE),
				lbcolor,dscolor,dbcolor,dbcolor,lbcolor},
				new int[] {10, 80, 96, 100}, true);
		folder.setSimple(false);
//!!		folder.setMRUVisible(true); // 最近開いたタブを優先する
//		folder.setUnselectedImageVisible(false);
//		folder.setUnselectedCloseVisible(false);
//		folder.setMinimizeVisible(true);
		folder.setMaximizeVisible(true);
//================================================================================================
		checkFromTo();
		if (prop.size() == 0) {
		// 初回の時
			sf.setWeights(new int[] { 70, 30 });
		} else {
			int[] aint = toIntArray(_prop.getProperty(_property_key_weights), ":");
			if (aint != null && aint.length >= 2) {
				sf.setWeights(aint);
			}
			aint = toIntArray(_prop.getProperty(_property_key_years), ":");
			if (aint != null) {
				_spYearB.setSelection(aint[0]);
				_spYearE.setSelection(aint[1]);
			}
		}
		shell.addControlListener(new ControlListener() {
			@Override
			public void controlResized(ControlEvent evt) {
				Rectangle r = getShellBounds(shell.getBounds());
				if (r != null) {
					prop.setProperty(_property_key_bounds, r.x+":"+r.y+":"+r.width+":"+r.height);
				}
			}
			@Override
			public void controlMoved(ControlEvent evt) {
				Rectangle r = getShellBounds(shell.getBounds());
				if (r != null) {
					prop.setProperty(_property_key_bounds, r.x+":"+r.y+":"+r.width+":"+r.height);
				}
			}
		});
		ShellListener shellListener = new ShellAdapter() {
			@Override
			public void shellActivated(ShellEvent evt) {
				int[] aint = toIntArray(_prop.getProperty(_property_key_weights), ":");
				if (aint != null && aint.length >= 2) {
					sf.setWeights(aint);
				}
				tURL.setText(_haa_home_full);
				setUrl(tURL.getText());
				createHome();
				shell.removeShellListener(this);
			}
		};
		shell.addShellListener(shellListener);
		shell.addShellListener(new ShellAdapter() {
			@Override
			public void shellClosed(ShellEvent evt) {
		//
				prop.setProperty(_property_key_option+"5", ((Boolean)cbSelHour.getSelection()).toString());
				prop.setProperty(_property_key_option+"4", ((Boolean)cbSelDate.getSelection()).toString());
				prop.setProperty(_property_key_option+"3", ((Boolean)cbSelDay.getSelection()).toString());
				prop.setProperty(_property_key_option+"2", ((Boolean)cbSelMonth.getSelection()).toString());
				prop.setProperty(_property_key_option+"1", ((Boolean)cbSelYear.getSelection()).toString());
				prop.setProperty(_property_key_option+"0", ((Boolean)cbSelAll.getSelection()).toString());
				try {
					saveProperties(_prop);
				} catch (IOException e) {
					e.printStackTrace();
					MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
					mbox.setText(_prefix);
					mbox.setMessage(e.getMessage());
					mbox.open();
					System.exit(1);
				}
				Browser.clearSessions();
			}
		});
//----------------------------------------------------------------------------------------------------
		Image[] himage = new Image[1];
		ToolItem[] hitem = new ToolItem[1];
		folder.addControlListener(new ControlListener() {
			@Override
			public void controlResized(ControlEvent evt) {
				if (folder.getMaximized()) {
					return;
				}
				int[] aw = sf.getWeights();
				prop.setProperty(_property_key_weights, aw[0]+":"+aw[1]);
			}
			@Override
			public void controlMoved(ControlEvent evt) {
//				System.err.println("CTabFolder.controlMoved: Shell bounds "+shell.getBounds());
			}
		});
		folder.addCTabFolder2Listener(new CTabFolder2Adapter() {
			public void minimize(CTabFolderEvent event) {
			}
			public void maximize(CTabFolderEvent event) {
				hitem[0] = new ToolItem(toolBar, SWT.PUSH);
				himage[0] = createImage("images/help_help.png", -1);
				hitem[0].setToolTipText(_prefix+"ヘルプ");
				hitem[0].setImage(himage[0]);
				hitem[0].addSelectionListener(new SelectionListener() {
					@Override
					public void widgetSelected(SelectionEvent evt) {
						try {
							helpHelp();
						} catch (IOException e) {
							e.printStackTrace();
							MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
							mbox.setText(_prefix);
							mbox.setMessage(e.getMessage());
							mbox.open();
						}
					}
					@Override
					public void widgetDefaultSelected(SelectionEvent evt) {
					}
				});
			    toolBar.pack();
			    Point size = toolBar.getSize();
			    citem.setControl(toolBar);
			    Point preferred = citem.computeSize(size.x, size.y);
			    citem.setPreferredSize(preferred);

			    folder.setMaximized(true);
				sf.setData(_KEY_SASH_WEIGHTS, sf.getWeights());
				sf.setWeights(new int[] {0, 100});
				// サッシ幅を無くさないと拡げられてしまう
				sf.setSashWidth(0);
			}
			public void restore(CTabFolderEvent event) {
				hitem[0].dispose();
				himage[0].dispose();
				hitem[0] = null;
				himage[0] = null;
			    toolBar.pack();
			    Point size = toolBar.getSize();
			    citem.setControl(toolBar);
			    Point preferred = citem.computeSize(size.x, size.y);
			    citem.setPreferredSize(preferred);
//
			    folder.setMaximized(false);
				sf.setWeights((int[])sf.getData(_KEY_SASH_WEIGHTS));
				sf.setSashWidth(_DEFAULT_SASH_WIDTH);
			}
		});
		if (!_DEBUG_MODE) {
			tURL.setEditable(false);
		} else {
			tURL.addKeyListener(new KeyListener() {
				@Override
				public void keyReleased(KeyEvent evt) {
				}
				@Override
				public void keyPressed(KeyEvent evt) {
					if (evt.keyCode == SWT.CR) {
						setUrl(tURL.getText());
					}
				}
			});
		}
		PaintListener paintListener = new PaintListener() {
			@Override
			public void paintControl(PaintEvent evt) {
				evt.gc.setForeground(dbcolor);
				evt.gc.drawRectangle(0, 0, evt.width-1, evt.height-1);
				evt.gc.drawRectangle(1, 1, evt.width-3, evt.height-3);
				evt.gc.setForeground(lbcolor);
				// 下
				evt.gc.drawLine(2, evt.height-2, evt.width-1, evt.height-2);
				evt.gc.drawLine(1, evt.height-1, evt.width-1, evt.height-1);
				// 右
				evt.gc.drawLine(evt.width-2, 2, evt.width-2, evt.height-1);
				evt.gc.drawLine(evt.width-1, 1, evt.width-1, evt.height-1);
			}
		};
		compUpper.addPaintListener(paintListener);
		compLower.addPaintListener(paintListener);
		bRefresh.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				if ("about:blank".equals(_browser.getUrl())) {
				// URL が設定されていない時
					return;
				}
				new Thread(new Runnable() {
					@Override
					public void run() {
						_shell.getDisplay().asyncExec(new Thread(new Runnable() {
							public void run() {
								_browser.refresh();
							} // run
						}));
					}
				}).start();
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
		bHelp.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				try {
					helpHelp();
				} catch (IOException e) {
					e.printStackTrace();
					MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
					mbox.setText(_prefix);
					mbox.setMessage(e.getMessage());
					mbox.open();
				}
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
//---------------------------------------------------------------------------------------
		Button[] rbs = new Button[] {
			rbTargetYear, rbTargetMonth, rbTargetDay, rbTargetDate, rbTargetHour,
		};
		Button[] cbs = new Button[] {
			cbSelYear, cbSelMonth, cbSelDay, cbSelDate, cbSelHour,
		};
		int[] conds = {
			_COND_YEAR, _COND_MONTH, _COND_DAY, _COND_DATE, _COND_HOUR,
		};
		SelectionListener tselectionListener = new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				Button rb = (Button)evt.widget;
				_cond_type = (Integer)rb.getData(_KEY_TARGET_COND);
				int idx = (Integer)rb.getData(_KEY_TARGET_ID);
				int i, len = cbs.length;
				for(i=0; i<len; i++) {
					cbs[i].setEnabled(i <= idx);	// (i < idx) が正しいが、表示が不可になるのを避ける
				}
				prop.setProperty(_property_key_target, String.valueOf(idx));
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		};
		str = prop.getProperty(_property_key_target);
		int tidx = 3;
		if (str == null) {
		// 初期値
			rbTargetDate.setSelection(true);
			_cond_type = _COND_DATE;
			cbSelAll.setSelection(true);
			cbSelYear.setSelection(true);
			cbSelMonth.setSelection(true);
			cbSelDay.setSelection(true);
			cbSelDate.setSelection(true);
			cbSelHour.setSelection(false);
			prop.setProperty(_property_key_target, String.valueOf(3));
			prop.setProperty(_property_key_taboverrided, String.valueOf(true));
		} else {
			try {
				tidx = Integer.parseInt(str);
			} catch(NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (String.valueOf(true).equals(prop.getProperty(_property_key_taboverrided))) {
			tiOverrided.setSelection(true);
			tiOverrided.setImage(simage);
			tiOverrided.setToolTipText("同じ抽出条件のタブを上書き（選択）");
		} else {
			tiOverrided.setImage(image);
			tiOverrided.setToolTipText("同じ抽出条件のタブを上書き（非選択）");
		}
		int i, len = rbs.length;
		for(i=0;i<len;i++) {
			rbs[i].setData(_KEY_TARGET_ID, new Integer(i));
			rbs[i].setData(_KEY_TARGET_COND, new Integer(conds[i]));
			rbs[i].addSelectionListener(tselectionListener);
			if (i == tidx) {
				rbs[i].notifyListeners(SWT.Selection, new Event());
				rbs[i].setSelection(true);
			}
		}
//-----------------------------------------------------------------------------------
		SelectionListener selectionLListener = new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				if (((Button)evt.widget).getSelection()) {
				// 選択された時
					if (cbSelYear.getSelection() && cbSelMonth.getSelection()
					 && cbSelDate.getSelection() && cbSelDay.getSelection() && cbSelHour.getSelection()) {
					// すべて選択された時
						cbSelAll.setSelection(true);
					}
				} else if (!cbSelYear.getSelection() && !cbSelMonth.getSelection()
					 && !cbSelDate.getSelection() && !cbSelDay.getSelection() && !cbSelHour.getSelection()) {
				// すべて選択解除された時
					cbSelAll.setSelection(false);
				}
				// 作表可／不可
//				bLExec.setEnabled(checkCreate(cbSelYear, cbSelMonth, cbSelDate, cbSelDay, cbSelHour));
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		};
		cbSelAll.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				// すべて選択／解除
				boolean flag = cbSelAll.getSelection();
				int i, len = cbs.length;
				for(i=0;i<len;i++) {
					if (cbs[i].getEnabled()) {
						cbs[i].setSelection(flag);
					} else {
						break;
					}
				}
				// 作表可／不可
//!!				bLExec.setEnabled(checkCreate(cbSelYear, cbSelMonth, cbSelDate, cbSelDay, cbSelHour));
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
		cbSelYear.addSelectionListener(selectionLListener);
		cbSelMonth.addSelectionListener(selectionLListener);
		cbSelDay.addSelectionListener(selectionLListener);
		cbSelDate.addSelectionListener(selectionLListener);
		cbSelHour.addSelectionListener(selectionLListener);
		bLExec.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				// 作表不可
				bLExec.setEnabled(false);
				executeGraph(rbs, cbs, cbExecAll, spYearB, spYearE);
				// 作表可
				bLExec.setEnabled(true);
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
//-----------------------------------------------------------------------------------
		tiOverrided.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				boolean val = tiOverrided.getSelection();
				if (val) {
					tiOverrided.setImage((Image) tiOverrided.getData(_KEY_SELECTED_IMAGE));
					tiOverrided.setToolTipText("同じ抽出条件のタブは上書き（選択）");
				} else {
					tiOverrided.setImage((Image) tiOverrided.getData(_KEY_DESELECTED_IMAGE));
					tiOverrided.setToolTipText("同じ抽出条件のタブは上書き（非選択）");
				}
				prop.setProperty(_property_key_taboverrided, String.valueOf(val));
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
		tiDeleteOld.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				int cond, tcond = -1;
				int i, cnt = folder.getItemCount();
				for(i=cnt-1;i>=0;i--) {
					cond = (Integer)folder.getItem(i).getData(_KEY_TARGET_COND);
					if (cond == tcond) {
						MessageBox mbox = new MessageBox(_shell,SWT.ICON_WARNING|SWT.YES|SWT.NO);
						mbox.setText(_prefix);
						mbox.setMessage("同じ抽出条件の古いタブを削除しますか？");
						int ans = mbox.open();
						if (ans == SWT.YES) {
							for(;i>=0;i--) {
								cond = (Integer)folder.getItem(i).getData(_KEY_TARGET_COND);
								if (cond == tcond) {
									folder.getItem(i + 1).dispose();
								}
								tcond = cond;
							}
						}
					}
					tcond = cond;
				}
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
		tiDeleteAll.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				int i, cnt = folder.getItemCount();
				if (cnt > 0) {
					MessageBox mbox = new MessageBox(_shell,SWT.ICON_WARNING|SWT.YES|SWT.NO);
					mbox.setText(_prefix);
					mbox.setMessage("すべてのタブを削除しますか？");
					int ans = mbox.open();
					if (ans == SWT.YES) {
						for(i=cnt-1;i>=0;i--) {
							folder.getItem(i).dispose();
						}
					}
				}
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
//-----------------------------------------------------------------------------------
		browser.addProgressListener(new ProgressListener() {
			@Override
			public void completed(ProgressEvent evt) {
				String str = browser.getText();
				if (str.indexOf(_VAL_ACCESS_COUNTS) >= 0) {
					try {
System.out.println("completed: parse...");
						parse(str);
						checkFromTo();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			@Override
			public void changed(ProgressEvent evt) {
			}
		});
//================================================================================
		browser.addLocationListener(new LocationAdapter() {

			public void changed(LocationEvent evt) {
System.out.println("LocationEvent.changed: top? "+evt.top+": location "+evt.location+": evt "+evt);
try {
				String location;
				int llen = evt.location.length();
				if (evt.location.charAt(llen - 1) == '/') {
					location = evt.location.substring(0, llen - 1);
				} else {
					location = evt.location;
				}
				if (location.equals("https://accounts.hatena.ne.jp/logout")) {
					_is_logout = true;
					_about_blank = false;
				}
				if (!evt.top) {
					if (evt.location.matches(".*blog=.*.hatenablog.com.*")) {
						_uid = evt.location.replaceFirst(".*blog=(.*).hatenablog.com.*", "$1");
						_about_blank = true;
					} else if (_about_blank) {
						if (_is_logout) {
							_is_logout = false;
						} else {
							_about_blank = false;
//System.out.println("changed: browser.setUrl(\"https://blog.hatena.ne.jp/"+_uid+"/"+_uid+".hatenablog.com/accesslog");
							_browser.setUrl("https://blog.hatena.ne.jp/"+_uid+"/"+_uid+".hatenablog.com/accesslog");
						}
					}
				} else {
				// トップ・ページの時
System.out.println("changed: top");

					tURL.setText(evt.location);
//					_isParse = false;
					if (location.endsWith(_haa_home)) {	// ://haa.jp/?ref=
					// ホーム・ページの時
//System.out.println("changed: top home");
						_topType = _TTYPE_HOME;
						// 開始終了年設定
						checkFromTo();
					} else if (location.indexOf(_haa_error) >= 0) { // http://error.haa.jp/
					// エラー・ページの時
//System.err.println("changed: error");
						_topType = _TTYPE_ERROR;
					} else if (location.startsWith(_haa_login)) {
//System.out.println("changed: login");
					// ログイン・ページの時
						_topType = _TTYPE_LOGIN;
					}
					if (_sCharger.isEmpty()) {
//PRINT_LOG::printLogOut("SWTBriefBrowser.locationChanged: _sCharger.isEmpty()");
					// 残りがない時
						if (!_isLogin && checkExec(tURL)) {
//							browser.setUrl(getAccessLogPath(uid));
//System.out.println("changed2: browser.setUrl(\""+location+"\"");
							browser.setUrl(location);
							_isLogin = true;
						}
					} else {
					// 残りがある時
						// この URL を表示した HaAggregater を破棄
//PRINT_LOG::printLogOut("SWTBriefBrowser.locationChanged: _sCharger.pop()...");
						synchronized (_sCharger) {
							_sem.acquire();
							_sCharger.pop();
//PRINT_LOG::printLogOut("SWTBriefBrowser.locationChanged: _sCharger.pop() ok");
						}
						Display.getDefault().syncExec(new Thread(new Runnable() {
							public void run() {
								if (_lStatus != null && !_lStatus.isDisposed()) {
/*
http://rabbit2018.haa.jp/manage/?mode=access&ym=201804
http://rabbit2018.haa.jp/manage/?mode=access_plus_time&ym=201804&d=1
 */
									int yy, mm, dd;
									int idx = evt.location.indexOf(_manage_ym);
									String str = evt.location.substring(idx + _manage_ym.length());

									yy = Integer.parseInt(str.substring(0, 4));
									mm = Integer.parseInt(str.substring(4, 6));

									if ((idx = str.indexOf('&')) >= 0) {
									// 日次の時
										dd = Integer.parseInt(str.substring(idx + 3));
										str = String.format("%d年%2d月%2d日", (Integer)yy, (Integer)mm, (Integer)dd);
									} else {
										str = String.format("%d年%2d月", (Integer)yy, (Integer)mm);
									}
									synchronized (_sGen) {
										if (_lStatus != null && !_lStatus.isDisposed()) {
											_lStatus.setText(str);
										}
									}
								}
							} // run
						}));
						new Thread(new Runnable() {
							@Override
							public void run() {
								synchronized (_sCharger) {
									if (_progressType == _PTYPE_STOP) {
									// ユーザーにより閉じられた時
										try {
											_sCharger.wait();
										} catch (InterruptedException e) {
											e.printStackTrace();
										}
									}
									if (_progressType == _PTYPE_CANCEL) {
									// キャンセルの時
										return;
									}
								} // synchronized(_sCharger)
								try {
									createText();
								} catch (Exception e) {
									e.printStackTrace();
									cancel(e.getMessage());
								}
							} // run
						}).start();
					} // if (_sCharger.isEmpty())
				} // if (evt.top)
				if (location.matches(".*passkeys/suggestion")) {
					// Linux fireFox 対応、MacOS では無用
//System.out.println(".*passkeys/suggestion");
					_browser.setUrl("https://blog.hatena.ne.jp/rabbit0418/rabbit0418.hatenablog.com/accesslog");
				}
				if (location.matches(".*//blog.hatena.ne.jp/[^/]*/[^/]*.hatenablog.com/accesslog")) {
System.out.println("changed: access-log");
					_prop.setProperty(_property_key_uid, location.replaceFirst(".*blog.hatena.ne.jp/(.*)/.*.hatenablog.com/accesslog.*", "$1"));
					_isAccessLog = true;
				}
				if (_isAccessLog) {
					String str = browser.getText();
					if (str != null && str.length() >= 100) {
						if (str.indexOf(_VAL_ACCESS_COUNTS) >= 0) {
	System.out.println("changed: parse...");
							parse(str);
							checkFromTo();
						}
					}
				}
} catch (Exception e) {
	e.printStackTrace();
}
			} // changed
		});
	} // setWidgets

	void parse(String text) throws IOException {
		String atext[] = new String[2];
		Display.getDefault().syncExec(new Thread(new Runnable() {
			public void run() {
//PRINT_LOG::printLogOut(">createText: syncExec.run");
				atext[0] = text;
				atext[1] = _browser.getUrl();
//PRINT_LOG::printLogOut("<createText: syncExec.run");
			} // run
		}));
		int idx = atext[1].indexOf(_manage_ym) + _manage_ym.length();
		BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(atext[0].getBytes()));
		HTMLTokenizer tok = new HTMLTokenizer(bis, false);
		ArrayList<long[]> list = new ArrayList();
		long[] along;

loop_exit:
		while(tok.nextToken() != HTMLTokenizer.TT_EOF) {
			if (tok.ttype == HTMLTokenizer.TT_TAG
			 && tok.tag == HTML.Tag.TABLE
			 && tok.attrs != null
			 && _ID_ACCESS_COUNTS.equals(tok.attrs.get(HTML.Attribute.ID))) {
/*
<table id="access-counts">
  <tr>
    <td data-time="1780515000000"></td>
    <td data-count="1"></td>
  </tr>
 */
				
				while(tok.nextToken() != HTMLTokenizer.TT_EOF) {
					if (tok.ttype == HTMLTokenizer.TT_TAG) {
						if (tok.tag == HTML.Tag.TABLE) {
							break;
						} else if (tok.tag == HTML.Tag.TR
						 && !tok.isEndTag) {
							if (tok.findTag(HTML.Tag.TD, false) == HTMLTokenizer.TT_EOF) {
								break loop_exit;
							}
							along = new long[2];
							along[0] = Long.parseLong((String) tok.attrs.values().toArray()[0]);
							if (tok.findTag(HTML.Tag.TD, false) == HTMLTokenizer.TT_EOF) {
								break loop_exit;
							}
							along[1] = Long.parseLong((String) tok.attrs.values().toArray()[0]);
							list.add(along);
						}
					}
				}
			}
		}
		bis.close();
//
		int i, j, jlen, len = list.size();
		long[][] aalong = list.toArray(new long[len][]);
		Arrays.sort(aalong, new Comparator<long[]>() {
			@Override
			public int compare(long[] arg0, long[] arg1) {
				return(arg0[0] <  arg1[0]? -1: 1);
			}});
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd:DDD:u:HH:mm");
		Date date = new Date(aalong[0][0]);
		String bform = sdf.format(date);
		String[] astr = bform.split(":");
		int byyyy =  Integer.parseInt(astr[_IDX_YYYY]);
		int bMM =  Integer.parseInt(astr[_IDX_MM]);
		int bdays =  Integer.parseInt(astr[_IDX_DAYS]);
		File dir = getYearPath(byyyy);
		dir.mkdirs();
		File file = new File(dir, String.format("%02d.txt", bMM));
		String line;
		ArrayList<String> slist = null;
		if (file.exists()) {
			// 先頭のファイルが存在した場合、マージ
			slist = new ArrayList();
			BufferedReader br = new BufferedReader(new FileReader(file));
			while((line = br.readLine()) != null) {
				if (bform.equals(line.split("::")[0])) {
				// 時刻が等しい時
					break;
				}
				slist.add(line);
			}
			br.close();
		}
		PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
		if (slist != null) {
			// 先頭のファイルが存在した場合、マージ
			jlen = slist.size();
			for(j=0; j < jlen; j++) {
				ps.println(slist.get(j));
			}
		}
		for(i=0; i < len; i++) {
			date = new Date(aalong[i][0]);
			String str = sdf.format(date);
			astr = str.split(":");
			int nyyyy =  Integer.parseInt(astr[_IDX_YYYY]);
			int nMM =  Integer.parseInt(astr[_IDX_MM]);
			int ndays =  Integer.parseInt(astr[_IDX_DAYS]);
			int nhh =  Integer.parseInt(astr[_IDX_HH]);
			int nmm =  Integer.parseInt(astr[_IDX_MM2]);
			if ((byyyy < nyyyy
			 || (bMM < nMM
			 && !(bdays + 1 == ndays && nhh == 0 && nmm == 0)))) {
			// 年が変わっていた時
			// 又は月が変わっていた時
			// かつ（１日違いかつ時分がゼロ）ではない時
				ps.close();
				dir = getYearPath(nyyyy);
				dir.mkdirs();
				file = new File(dir, String.format("%02d.txt", nMM));
				ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
				byyyy = nyyyy;
				bMM = nMM;
				bdays = ndays;
			}
			ps.format("%s::%d\n", str, aalong[i][1]);
		}
		ps.close();
	}

	static String getAccessLogPath(String uid) {
		return(_haa_home_full + "/" + uid + "/" + uid + ".hatenablog.com/accesslog");
	}

	class HaAGenerator implements HaACharger {
		int cond;
		int byear;
		int eyear;
		String tcond;

		HaAGenerator(int cond, int byear, int eyear, String tcond) {
			this.cond = cond;
			this.byear = byear;
			this.eyear = eyear;
			this.tcond = tcond;
		}

		@Override
		public void charge() {
			_shell.getDisplay().asyncExec(new Thread(new Runnable() {
				public void run() {
					synchronized (_sGen) {
						if (_lStatus != null && !_lStatus.isDisposed()) {
							_lStatus.setText(tcond);
						}
					}
					createOneCondition(_folder, HaAGenerator.this.cond, HaAGenerator.this.byear, HaAGenerator.this.eyear, HaAGenerator.this.tcond);
//
					if (_sGen.isEmpty()) {
						synchronized (_sGen) {
							_progressType = _PTYPE_END;
							SWTDialog dlg = _pdlg;
							if (dlg != null && !dlg.getChild().isDisposed()) {
								dlg.getChild().close();
							}
							setProgress(null);
						}
					} else {
						new Thread(new Runnable() {
							@Override
							public void run() {
								synchronized (_sGen) {
									if (_progressType == _PTYPE_STOP) {
									// ユーザーにより閉じられた時
										try {
											_sGen.wait();
										} catch (InterruptedException e) {
											e.printStackTrace();
										}
									}
									if (_progressType == _PTYPE_CANCEL) {
									// キャンセルの時
										return;
									}
								} // synchronized(_sGen)
								try {
									_sGen.pop().charge();
								} catch (Exception e) {
									e.printStackTrace();
									cancel(e.getMessage());
								}
							} // run
						}).start();
					}
				} // run
			}));
		}
	}

	void setProgress(SWTDialog pdlg) {
		_pdlg = pdlg;
	}

	void synchToolTip(Control child, String str) {
		child.setToolTipText(str);
		child.getParent().setToolTipText(str);
	}

	int getConditionPosition(CTabFolder folder, int cond) {
		int i, len = folder.getItemCount();
		for(i=0;i<len;i++) {
			int tcond = (int) folder.getItem(i).getData(_KEY_TARGET_COND);
			if (tcond >= cond) {
				break;
			}
		}
		return i;
	}

	static Rectangle getShellBounds(Rectangle sr) {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Dimension sysd = toolkit.getScreenSize();
		if (sysd.width > sr.width - sr.x && sysd.height > sr.height - sr.y) {
		// 最大化ではない時
			return sr;
		}
		return null;
	}

	void checkFromTo() {
		int min = _spYearB.getSelection();
		int max = _spYearE.getSelection();
		if (max == 0) {
			max = Integer.MAX_VALUE;
		}
		int[] ayear = getBeginEnd();
		if (ayear == null) {
			_spYearE.setEnabled(false);
			_spYearB.setEnabled(false);
		} else {
			if (ayear[0] == ayear[1]) {
				_spYearE.setEnabled(false);
				_spYearB.setEnabled(false);
			} else {
				_spYearE.setEnabled(true);
				_spYearB.setEnabled(true);
			}
			_spYearB.setMaximum(ayear[1]);
			_spYearB.setMinimum(ayear[0]);
			_spYearE.setMaximum(ayear[1]);
			_spYearE.setMinimum(ayear[0]);
			_spYearB.setSelection(Math.max(ayear[0], Math.min(min, ayear[1])));
			_spYearE.setSelection(Math.max(ayear[0], Math.min(max, ayear[1])));
		}
		String str;
		if (ayear == null) {
			str = "データなし";
		} else {
			str = String.format("%04d～%04d", (Integer)ayear[0], (Integer)ayear[1]);
		}
		str = String.format("作表する年の範囲（%s）を指定してください", str);
		_spYearB.setToolTipText(str);
		_spYearE.setToolTipText(str);
		synchToolTip(_spYearB, str);
		synchToolTip(_spYearE, str);
		_bLExec.setEnabled(_spYearB.getSelection() > 0);
	}

	int[] getBeginEnd() {
		File tdir = getTextPath();
		if (tdir == null) {
			return null;
		}
		File[] childs = tdir.listFiles();
		if (childs == null) {
			return null;
		}
		int min = Integer.MAX_VALUE, max = 0;

		int i, len = childs.length;
		for(i=0;i<len;i++) {
			try {
				String name = childs[i].getName();
				if (name.matches("[0-9]+")) {
					int val = Integer.parseInt(name);
					min = Math.min(min, val);
					max = Math.max(max, val);
				}
			} catch(NumberFormatException e) {
				e.printStackTrace();
			}
		}
		if (max == 0) {
			return null;
		}
		return new int[] { min, max };
	}

	void setUrl(String url) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				_shell.getDisplay().asyncExec(new Thread(new Runnable() {
					public void run() {
//System.out.println("setUrl: browser.setUrl(\""+url+"\"");
						_browser.setUrl(url);
					} // run
				}));
			}
		}).start();
	}

	void loadProperties(Properties prop) throws IOException {
//PRINT_LOG::		openTrace();
		File hdir = getHome();
		File pfile = new File(hdir, _properties_name);
		if (!pfile.exists()) {
			return;
		}
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pfile));
		prop.loadFromXML(bis);
		bis.close();
	} // loadProperties

	void saveProperties(Properties prop) throws IOException {
		prop.setProperty(_property_key_years,
				String.valueOf(_spYearB.getSelection())+":"+String.valueOf(_spYearE.getSelection()));
		prop.setProperty(_property_key_execall, String.valueOf(_cbExecAll.getSelection()));
		File hdir = getHome();
		File pfile = new File(hdir, _properties_name);
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(pfile));
		prop.storeToXML(bos, null, "UTF-8");
	}

	static int getSeasonIndex() {
		if (false) {
			return 0;
		}
		// Zero origin なので春は 2 （３月）から始まる
		return(((Calendar.getInstance().get(Calendar.MONTH) + 10) / 3) % 4);
	} // getSeasonIndex

	static Color getSeasonColor() {
		switch(getSeasonIndex()) {
		default:
		case 0:
			return new Color(null, 0xb8, 0xf0, 0xc0);
		case 1:
			return new Color(null, 0xc8, 0xd0, 0xf0);
		case 2:
			return new Color(null, 0xff, 0xd8, 0xb0);
		case 3:
			return new Color(null, 0xde, 0xde, 0xe4);
		}
	}

	void createHome() {
		File hdir = getHome();
		if (hdir.exists()) {
			if (!hdir.isDirectory()) {
				MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
				mbox.setText(_prefix);
				mbox.setMessage("以下のファイルを削除、又は移動してから HAA を実行し直してください！\n"+hdir.toString());
				mbox.open();
				System.exit(1);
			}
			return;
		}
		if (!hdir.mkdirs()) {
			MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
			mbox.setText(_prefix);
			mbox.setMessage("HAA のホーム・ディレクトリを作れません！\n"+hdir.toString());
			mbox.open();
			System.exit(1);
		}
	}

	class JAMonthly implements HaACharger {
		String _path;

		JAMonthly(String path) {
			_path = path;
		}

		@Override
		public void charge() {
			setUrl(_path);
		}
	}

	class JAFactor implements HaACharger {

		boolean _running;
		String _path;
		boolean[] _amonth;
		int _mi;

		public JAFactor(String path, boolean[] amonth) {
			this._path = path;
			this._amonth = amonth;
			this._running = true;
		}

		public boolean isRunning() {
			return _running;
		}

		public String getPathPrefix() {
			int idx = _path.lastIndexOf(_manage_prefix); // "/manage/?mode="
			if (idx < 0) {
				MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
				mbox.setText(_prefix);
				mbox.setMessage("URL が管理者ページではありません！\n"+_path);
				mbox.open();
				_running = false;
				return null;
			}
			return _path.substring(0, idx) + _manage_form; // "/manage/"
		} // getPathPrefix

		public int getValidCount() {
			int i, cnt = 0;
			for(i=0; i < _amonth.length; i++) {
				if (_amonth[i]) {
					cnt++;
				}
			}
			return cnt;
		}

		public void charge() {
			boolean stat = false;
//PRINT_LOG::	printLogOut(">JAFactor.charge: _mi("+_mi+")<_amonth.length("+_amonth.length+")? "+(_mi<_amonth.length)+": _running? "+_running);
			_elist.clear();
			try {
				for(; _mi < _amonth.length; _mi++) {
					if (_amonth[_mi]) {
						Calendar calendar = Calendar.getInstance();
						int year = calendar.get(Calendar.YEAR);
						int month = calendar.get(Calendar.MONTH) + 1 - _mi;
						if (month <= 0) {
							year--;
							month = 12;
						}
						int idx = _path.lastIndexOf(_manage_prefix); // "/manage/?mode="
						if (idx < 0) {
							MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
							mbox.setText(_prefix);
							mbox.setMessage("URL が管理者ページではありません！\n"+_path);
							mbox.open();
							break;
						}
						String str = _path.substring(0, idx) + _manage_access_form; // "/manage/?mode=access&ym=%d%02d"
						String tpath = String.format(str, (Integer)year, (Integer)month);
//PRINT_LOG::	printLogOut("JAFactor.charge: "+tpath+"? _mi("+_mi+")...");
						setUrl(tpath);
//PRINT_LOG::	printLogOut("<JAFactor.charge: _running? "+_running);
						_mi++;
						stat = true;
						break;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
				mbox.setText(_prefix);
				mbox.setMessage(e.getMessage());
				mbox.open();
			}
//PRINT_LOG::printLogOut("<JAFactor.chargeZZZ: _running? "+_running);
			_running = stat;
		} // charge
	} // JAFactor

	long _atime;
	long _wtime;

	void closeWriter() {
		PrintWriter pw = (PrintWriter) _hData.get(_KEY_TEXT_WRITER);
		if (pw != null) {
			pw.close();
			_hData.remove(_KEY_TEXT_WRITER);
		}
		pw = (PrintWriter) _hData.get(_KEY_CSV_WRITER);
		if (pw != null) {
			pw.close();
			_hData.remove(_KEY_CSV_WRITER);
		}
	} // closeWriter

	void createText() throws IOException {
//PRINT_LOG::printLogOut(">createText: -------------------------------------------------------------------------------");
//PRINT_LOG:://!!printLogOut( _browser.getText());
//		PrintWriter tpw;
		PrintWriter cpw;
		String atext[] = new String[2];
		Display.getDefault().syncExec(new Thread(new Runnable() {
			public void run() {
//PRINT_LOG::printLogOut(">createText: syncExec.run");
				atext[0] = _browser.getText();
				atext[1] = _browser.getUrl();
//PRINT_LOG::printLogOut("<createText: syncExec.run");
			} // run
		}));
		int idx = atext[1].indexOf(_manage_ym) + _manage_ym.length();
//PRINT_LOG::printLogOut(String.format("createText: URL(%d)%s", (Integer)idx, atext[1]));
		int year = Integer.parseInt(atext[1].substring(idx, idx + 4));
		HaAParser parser = new HaAParser();
		BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(atext[0].getBytes()));
		HaAForm form = parser.parse(bis, year);
		bis.close();
		Factor factor;
		int i, len = form.lines.size();
		factor = form.lines.get(0);
		if (factor.count != form.total) {
		// 合計が合わない時
			_elist.add(form);
		}
		int sum = 0;
		String str, tstr;
		File cfile, ydir, aydir[] = new File[1];

		Display.getDefault().syncExec(new Thread(new Runnable() {
			public void run() {
				aydir[0] = getYearPath(year);
		} // run
		}));
		ydir = aydir[0];
//		mdir = new File(ydir, String.format("%04d%02d", (Integer)year, (Integer)factor.MM_mm));

		if (form.type == HaAForm.TYPE_MONTHLY) {
		// 月次の時
//PRINT_LOG::printLogErr("createText: TYPE_MONTHLY "+year+"----------------------------------------------");
			if (!ydir.exists()) {
				if (!ydir.mkdirs()) {
					cancel("以下のディレクトリーを作成できません！\n"+ydir.toString());
					return;
				}
			}
			closeWriter();
			str = String.format("%s%04d%02d.csv", _PREFIX, (Integer)year, (Integer)factor.MM_mm);
			cfile = new File(ydir, str);

			cpw = new PrintWriter(cfile, "UTF-8");
			str = String.format("%04d年%02d月 合計:%5d",
					(Integer)factor.yy_hh, (Integer)factor.MM_mm, (Integer)factor.count);
			cpw.println("日,曜日,件数,累計");
			tstr = String.format("%04d年%02d月,合計,%d", (Integer)factor.yy_hh, (Integer)factor.MM_mm, (Integer)factor.count);

			ArrayList<HaACharger> list = new ArrayList<>();
			for(i=1; i<len; i++) {
				String dpath;
				factor = form.lines.get(i);
				sum += factor.count;
				str = String.format("%02d,%s,%d,%d",
						(Integer)factor.dd, HaAForm.toDayValue(factor.day),
						(Integer)factor.count, (Integer)sum);
				cpw.println(str);

				if (factor.count > 0) {
				// 件数がある時
					dpath = form.getDayPath(i);
					list.add(new JAMonthly(_jaf.getPathPrefix() + dpath));
				}
			}
			cpw.println(tstr); // 合計
			_hData.put(_KEY_CSV_WRITER, cpw);

			for(i=list.size() - 1; i>=0; i--) {
			// 後ろから押し込む
				_sCharger.push(list.get(i));
			}
		} else {
		// 日次の時
//PRINT_LOG::printLogErr("createText: TYPE_DAILY "+year+"----------------------------------------------------------------------");

//PRINT_LOG::printLogOut("createText: 日次の時: ydir "+ydir);
			cpw = (PrintWriter) _hData.get(_KEY_CSV_WRITER);
			cpw.println("時,分,件数,累計");
			tstr = String.format("%04d年%02d月%02d日,合計,%d", (Integer)factor.yy_hh, (Integer)factor.MM_mm, (Integer)factor.dd, (Integer)factor.count);

			for(i=1; i<len; i++) {
				factor = form.lines.get(i);
				sum += factor.count;
				str = String.format("%02d,%02d,%d,%d",
						(Integer)factor.yy_hh, (Integer)factor.MM_mm, (Integer)factor.count, (Integer)sum);
				cpw.println(str);
			} // for(...)
			cpw.println(tstr); // 合計
		}
		if (_sCharger.isEmpty()) {
		// 残りがない時
//PRINT_LOG::printLogErr("createText: _sCharger.isEmpty()");
			_jaf = null;
			closeWriter();
			Display.getDefault().asyncExec(new Thread(new Runnable() {
				public void run() {
					SWTDialog pdlg = _pdlg;
//PRINT_LOG::printLogOut("clearLaf: pdlg == null? "+(pdlg == null));
					if (pdlg != null) {
						// 開始終了年設定
						checkFromTo();
						synchronized (_sGen) {
							_lStatus = null;
						}
						setProgress(null);
//PRINT_LOG::printLogOut("clearLaf: pdlg.getChild().close()...");
						pdlg.getChild().close();
					}
				} // run
			}));
		} else {
		// 残りがある時
			try {
				long wtime, ctime = System.currentTimeMillis();
				if (_atime == 0) {
					wtime = _WAIT_TIME;
				} else {
//PRINT_LOG::printLogOut(String.format("createText: (ctime - _atime)%d", (ctime - _atime)));
					wtime = Math.max(1, _WAIT_TIME - (ctime - _atime));
				}
				_atime = ctime;
				Thread.sleep(wtime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
//PRINT_LOG::printLogOut("createText: ((HaACharger)_sCharger.peek()).charge()...");
			_shell.getDisplay().asyncExec(new Thread(new Runnable() {
				public void run() {
//PRINT_LOG::printLogOut(">createText: ((HaACharger)_sCharger.peek()).charge()...");
			synchronized (_sCharger) {
				((HaACharger)_sCharger.peek()).charge();
				_sem.release();
			}
//PRINT_LOG::printLogOut("<createText: ((HaACharger)_sCharger.peek()).charge() ok.");
				} // run
			}));
		}
//PRINT_LOG::printLogOut("<createText: -------------------------------------------------------------------------------");
	} // createText

	void cancel(String message) {
//PRINT_LOG::printLogOut(">cancel");
		Display.getDefault().syncExec(new Thread(new Runnable() {
			public void run() {
//PRINT_LOG::printLogOut(">cancel: syncExec.run");
				_progressType = _PTYPE_ERROR;
				if (_pdlg != null) {
					Shell child = _pdlg.getChild();
					if (!child.isDisposed()) {
						child.close();
					}
					setProgress(null);
				}
				synchronized (_sGen) {
					_lStatus = null;
				}
				MessageBox mbox = new MessageBox(_shell,SWT.ICON_ERROR);
				mbox.setText(_prefix);
				mbox.setMessage(message);
				mbox.open();
				_jaf = null;
			} // run
		}));
//PRINT_LOG::printLogOut(">cancel");
	} // cancel

	void executeGraph(Button[] rbs, Button[] cbs, Button cbExecAll, Spinner spYearB, Spinner spYearE) {
//PRINT_LOG::printLogOut("executeGraph: "+_browser.getUrl()+"------------------------");
		Button cbSelYear = cbs[_SEL_YEAR];
		Button cbSelMonth = cbs[_SEL_MONTH];
		Button cbSelDay = cbs[_SEL_DAY];
		Button cbSelDate = cbs[_SEL_DATE];
		Button cbSelHour = cbs[_SEL_HOUR];

		_sGen.clear();
		new Thread(new Runnable() {
			public void run() {
//PRINT_LOG::printLogOut("executeGraph: >Runnable.run");
				int[] astat = new int[1];
				for(;;) {
					_progressType = _PTYPE_ACTIVE;

					// プログレス・ダイアログ
					_shell.getDisplay().syncExec(new Thread(new Runnable() {
						public void run() {
//PRINT_LOG::printLogOut("executeGraph: >Runnable.run: asyncExec.run...");

							SWTDialog dlg = new SWTDialog(_shell) {
								int _result = SWT.OK;

								@Override
								public void setWidgets(Shell child) {
									Display display = child.getDisplay();
									Color scolor = getSeasonColor();
									GridData gd;
									Composite compB = new Composite(child, SWT.NONE);
									compB.setBackground(scolor);
									compB.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
											|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
									compB.setLayout(new GridLayout(1, false));

									Composite compBody = new Composite(compB, SWT.NONE);
									compBody.setBackground(scolor);
									gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_CENTER
											|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL);
									gd.heightHint = 80;
									compBody.setLayoutData(gd);
									compBody.setLayout(new GridLayout(2, false));
									Label labelCond = new Label(compBody, SWT.HORIZONTAL);
									labelCond.setBackground(scolor);
									labelCond.setLayoutData(new GridData());
									labelCond.setText("処理中のグラフ");
									Label lCond = _lStatus = new Label(compBody, SWT.HORIZONTAL);
//									lCond.setBackground(new Color(display, 0xfa, 0xfa, 0xe0));
									lCond.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
									gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL
											|GridData.GRAB_HORIZONTAL);
									gd.widthHint = _URL_LENGTH;
									lCond.setLayoutData(gd);
									Button bCancel = new Button(compB, SWT.PUSH);
									bCancel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER|GridData.VERTICAL_ALIGN_CENTER));
									bCancel.setText("キャンセル");
									bCancel.addSelectionListener(new SelectionListener() {
										@Override
										public void widgetSelected(SelectionEvent evt) {
											_pdlg.getChild().close();
										}
										@Override
										public void widgetDefaultSelected(SelectionEvent evt) {
										}
									});
									Point p = child.computeSize(SWT.DEFAULT, SWT.DEFAULT);
									child.setBounds(300, 300, p.x, p.y);
									SWTMoveWindow.moveTo(child, SWTMoveWindow.CENTER);
									synchronized (_sGen) {
										_sGen.notifyAll();
									}
								} // setWidgets

								@Override
								public Object getResult() {
									return _result;
								}
								@Override
								public void cancelClosed() {
//PRINT_LOG::printLogOut("executeGraph: SWTDialog.cancelClosed: _pdlg "+_pdlg);

									if (_pdlg != null && _progressType == _PTYPE_ACTIVE) {
//PRINT_LOG::printLogOut("executeGraph: SWTDialog.cancelClosed: _result = SWT.CANCEL");
									// ユーザーにより閉じられた時
										synchronized (_sGen) {
											if (_sGen.isEmpty()) {
												return;
											}
											_lStatus = null;
										}
										_progressType = _PTYPE_STOP;
										_result = SWT.CANCEL;
										setProgress(null);
									}
								}
							};
							setProgress(dlg);
							dlg.setText(_prefix);
//PRINT_LOG::printLogOut("executeGraph: SWTDialog.open()...");
							astat[0] = (Integer)dlg.open();
//PRINT_LOG::printLogOut("executeGraph: <Runnable.run: asyncExec.run");
						} // run
					}));

					if (astat[0] == SWT.OK) {
//PRINT_LOG::printLogOut("executeGraph: SWTDialog.open()==SWT.OK break");
						_progressType = _PTYPE_END;
						break;
					}
					// エラーの時
					if (_progressType == _PTYPE_ERROR) {
//PRINT_LOG::printLogOut("executeGraph: SWTDialog.open()==SWT.ERROR break");
						break;
					}
//PRINT_LOG::printLogOut("executeGraph: SWTDialog.open()==SWT.CANCEL? "+(astat[0]==SWT.CANCEL));
					// キャンセル確認ダイアログ
					_shell.getDisplay().syncExec(new Thread(new Runnable() {
						public void run() {
//PRINT_LOG::printLogOut("executeGraph: >Runnable.run: asyncExec.run... 2");
							MessageBox mbox = new MessageBox(_shell,SWT.ICON_QUESTION|SWT.RETRY | SWT.CANCEL);
							mbox.setText(_prefix);
							mbox.setMessage("処理を中止しますか？");
//PRINT_LOG::printLogOut("executeGraph: new MessageBox.open()...");
							astat[0] = mbox.open();
//PRINT_LOG::printLogOut("executeGraph: <Runnable.run: asyncExec.run 2");
						} // run
					}));
//PRINT_LOG::printLogOut("executeGraph: astat[0]("+astat[0]+") == SWT.CANCEL? "+(astat[0] == SWT.CANCEL));
					if (astat[0] == SWT.CANCEL) {
					// キャンセルの時
//PRINT_LOG::printLogOut("executeGraph: astat[0] == SWT.CANCEL");
						_progressType = _PTYPE_CANCEL;
//						_jaf = null;
						closeWriter();
//PRINT_LOG::printLogOut("executeGraph: for(;;) break");
						// ループから抜ける
						break;
					}
//PRINT_LOG::printLogOut("executeGraph: astat[0]("+astat[0]+") == SWT.RETRY? "+(astat[0] == SWT.RETRY));
					_progressType = _PTYPE_ACTIVE;
					new Thread(new Runnable() {
						@Override
						public void run() {
//PRINT_LOG::printLogOut(">executeGraph: Runnable.run");
							try {
								synchronized (_sGen) {
//PRINT_LOG::printLogOut("executeGraph: _sGen.notifyAll()");
									_sGen.notifyAll();
								}
							} catch(Exception e) {
								e.printStackTrace();
							}
//PRINT_LOG::printLogOut("<executeGraph: Runnable.run");
						}
					}).start();
				} // for(;;)
//PRINT_LOG::printLogOut("executeGraph: <Runnable.run");
			} // run
		}).start();

		int cond =  getCondition(new boolean[] {
				cbSelYear.getSelection(), cbSelMonth.getSelection(),
				cbSelDay.getSelection(), cbSelDate.getSelection(), cbSelHour.getSelection(), });

		int byear = spYearB.getSelection();
		int eyear = spYearE.getSelection();
		if (byear > eyear) {
		// 範囲が逆の時
			int tmp = byear;
			byear = eyear;
			eyear = tmp;
			spYearB.setSelection(byear);
			spYearE.setSelection(eyear);
		}
		int[] abyear = new int[] { byear };
		int[] aeyear = new int[] { eyear };
		_sGen.clear();

		if (cbExecAll.getSelection()) {
		// すべて実行の時
			int bcond = cond;
			for(cond = _cond_type; cond <= bcond; cond++) {
				if ((~bcond & cond) != 0) {
				// 別オプションがある時
					continue;
				}
//System.out.println(String.format("cond(0%06o) <= bcond(0%06o)", (Integer)cond, (Integer)bcond));
				boolean[] flags = new boolean[cbs.length];
				for(int i=0;i<cbs.length; i++) {
					flags[i] = cbs[i].getSelection();
					cbs[i].setSelection((cond & (Integer) rbs[i].getData(_KEY_TARGET_COND)) != 0);
				}
				String tcond = getTextCondition(rbs, cbs);
				for(int i=0;i<cbs.length; i++) {
					cbs[i].setSelection(flags[i]);
				}
				_sGen.push(new HaAGenerator(cond, abyear[0], aeyear[0], tcond));
			}
		} else {
			String tcond = getTextCondition(rbs, cbs);
			_sGen.push(new HaAGenerator(cond, abyear[0], aeyear[0], tcond));
		}
		new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (_sGen) {
					if (_lStatus == null) {
						try {
							_sGen.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						};
					}
				}
				_sGen.pop().charge();
			}
		}).start();
//PRINT_LOG::printLogOut("<executeGraph---------------------------------------------------------------------");
	} // executeGraph
//-------------------------------------------------------------------------------------

	private static final int _SEL_YEAR = 0;
	private static final int _SEL_MONTH = 1;
	private static final int _SEL_DAY = 2;
	private static final int _SEL_DATE = 3;
	private static final int _SEL_HOUR = 4;

	static final int _COND_YEAR		= 00000000001;
	static final int _COND_MONTH		= 00000000002;
	static final int _COND_DAY		= 00000000004;
	static final int _COND_DATE		= 00000000010;
	static final int _COND_DAILY		= 00000000020;	// 日次
	static final int _COND_HOUR		= 00000000020;
	static final int _COND_ALL = (_COND_YEAR | _COND_MONTH | _COND_DAY | _COND_DATE);

	int _cond_type;

	protected Color _graphFgColor;
	protected Color _graphBgColor;
	protected Color _graphTextColor;

	String getTextCondition(Button[] rbs, Button[] cbs) {
		String tcond, str = null;
		int i, j, len = rbs.length;
		for(i=0;i<len;i++) {
			if (rbs[i].getSelection()) {
				str = cbs[i].getText();
				break;
			}
		}
		j = i;
		tcond = "";
		for(i=0;i<len;i++) {
			if (i >= j) {
				break;
			}
			if (cbs[i].getSelection()) {
				tcond += cbs[i].getText() + " ";
			}
		}
		if (tcond == "") {
			tcond = str;
		} else {
			tcond = str + ": " + tcond;
		}
		return tcond;
	}

	int getCondition(boolean[] asel) {
		int cond = _cond_type; // ラジオ・ボタン
		if (asel[_SEL_YEAR]) {
			if (cond > _COND_YEAR) {
				cond |= _COND_YEAR;
			}
		}
		if (asel[_SEL_MONTH]) {
			if (cond > _COND_MONTH) {
				cond |= _COND_MONTH;
			}
		}
		if (asel[_SEL_DAY]) {
			if (cond > _COND_DAY) {
				cond |= _COND_DAY;
			}
		}
		if (asel[_SEL_DATE]) {
			if (cond > _COND_DATE) {
				cond |= _COND_DATE;
			}
		}
		if (asel[_SEL_HOUR]) {
			if (cond > _COND_HOUR) {
				cond |= _COND_HOUR;
			}
		}
		return cond;
	}

	void createOneCondition(CTabFolder folder, int cond, int byear, int eyear, String tcond) {
		String beyear = String.format("（%04d年%s）",
				(Integer)byear, byear == eyear? "": String.format("～%04d年", (Integer)eyear));
//PRINT_LOG::		printTrace("B:"+tcond+beyear);
		Table table = createTable(folder, cond, byear, eyear, beyear);
/*左端から挿入したい*
		if (folder.getItemCount() > 0) {
			folder.setInsertMark(0, false);
		}
/**/
		int pos = getConditionPosition(folder, cond);
		if (pos < folder.getItemCount()) {
		// 同じ抽出条件以上のタブがあった時
			CTabItem citem = folder.getItem(pos);
			if (cond == (Integer)citem.getData(_KEY_TARGET_COND)) {
			// 同じ抽出条件の時
				if (String.valueOf(true).equals(_prop.getProperty(_property_key_taboverrided))) {
					citem.dispose();
				}
			}
		}
		// 手前に挿入
		CTabItem nitem = new CTabItem(folder, SWT.CLOSE, pos);
		Object data = folder.getData(_KEY_TARGET_COND+String.valueOf(cond));
		int ccnt = 0;
		if (data == null) {
			nitem.setText(tcond);
		} else {
		// 同じ抽出条件のタブを生成してある時
			ccnt = (Integer)data;
			nitem.setText(tcond+"("+(ccnt+1)+")");
		}
		ccnt++;
		folder.setData(_KEY_TARGET_COND+String.valueOf(cond), ccnt);
		nitem.setToolTipText(tcond + table.getData(_KEY_FROM_TO_YEAR));

		nitem.setControl(table);
		nitem.setData(_KEY_TARGET_COND, cond);
		folder.setSelection(nitem);
//PRINT_LOG::printTrace("E:"+nitem.getToolTipText());
	}

	Table createTable(Composite parent, int cond, int byear, int eyear, String beyear) {
		SumAll psum = new SumAll(cond);
		int i;

		for(i=byear; i<= eyear; i++) {
			try {
				SumYearly ysum = createYear(i, cond);
				if (ysum != null) {
					psum.add(ysum);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Generator gen = null;
		switch(_cond_type) {
		case _COND_YEAR:	// 年
			gen = new GeneratorYear();
			break;
		case _COND_MONTH:	// 月
			gen = new GeneratorMonth();
			break;
		case _COND_DAY:	// 曜
			gen = new GeneratorDay();
			break;
		case _COND_DATE:	// 日
			gen = new GeneratorDate();
			break;
		case _COND_HOUR:	// 時
			gen = new GeneratorHour();
			break;
		}
		ArrayList<String[]> list = printDest(gen, psum, cond, _cond_type);

		String[][] data = list.toArray(new String[list.size()][2]);
		Arrays.sort(data, new Comparator<String[]>() {
			@Override
			public int compare(String[] prev, String[] next) {
				String val1 = prev[0];
				String val2 = next[0];
				int i1 = val1.indexOf('（');
				int i2 = val2.indexOf('（');
				Character c1, c2;

				if (i1 >= 0) {
					c1 = _hDays.get((Character)val1.charAt(i1 + 1));
					if (c1 != null) {
						val1 = val1.substring(0, i1 + 1) + c1 + val1.substring(i1 + 2);
					}
				}
				if (i2 >= 0) {
					c2 = _hDays.get((Character)val2.charAt(i2 + 1));
					if (c2 != null) {
						val2 = val2.substring(0, i2 + 1) + c2 + val2.substring(i2 + 2);
					}
				}
				return(val1.compareTo(val2));
			}
		});
		if (byear < eyear) {
		// 複数年の時
//PRINT_LOG::			HaAggregater.printLogOut(String.format("%04d年～%04d年 %5d件",
//PRINT_LOG::					(Integer)byear, (Integer)eyear, (Integer)psum._sum.count));
		} else {
//PRINT_LOG::			HaAggregater.printLogOut(String.format("%04d年 %5d件",
//PRINT_LOG::					(Integer)byear, (Integer)psum._sum.count));
		}
//-------------------------------------------------------------------------------------------
		final Table table = new Table(parent, SWT.VIRTUAL);
		Font font = table.getFont();
		FontData fdata = font.getFontData()[0];
		table.setFont(new Font(null, "Monospace", fdata.getHeight(), fdata.getStyle()));
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		table.setItemCount(data.length);
		// カラム・テキスト設定
		final TableColumn column1 = new TableColumn(table, SWT.NONE);
		column1.setText("抽出条件");
		final TableColumn column2 = new TableColumn(table, SWT.NONE);
		int[] cntMax = parseCountMax(list);
		column2.setText(String.format("アクセス件数　合計 %,d%s", (Integer)cntMax[0], beyear));
		table.setData(_KEY_FROM_TO_YEAR, beyear);
//
		String sss = "";
		if (data.length > 0) {
			sss = data[0][0];
		}
		int sw = 32;
		ScrollBar sb = table.getVerticalBar();
		if (sb != null) {
			sw = sb.getSize().x;
		}
		Rectangle r = parent.getClientArea();
		GC gc = new GC(table);
		int w = Math.max(gc.textExtent(sss).x + 32,
				gc.textExtent(column1.getText()).x + 16);
		gc.dispose();
		column1.setWidth(w);
		column2.setWidth(Math.round(0.8F * (r.width - w - sw)));

		table.addListener(SWT.SetData, new Listener() {
			public void handleEvent(Event evt) {
				if (data.length == 0) {
					return;
				}
				TableItem item = (TableItem) evt.item;
				int index = table.indexOf(item);
				String[] datum = data[index];
				item.setText(new String[] {datum[0], datum[1] });
			}
		});
		table.addListener(SWT.PaintItem, new Listener() {
			@Override
			public void handleEvent(Event evt) {
				TableItem item = (TableItem) evt.item;
				if (evt.index == 0) {
/*DEBUG*
					Display display = _shell.getDisplay();
					String str = item.getText(0);
					if (str.charAt(str.length() - 1) == '*') {
						// グラフィックコンテキスト取得
						GC gc = evt.gc;
						// 現在の前景色、背景色を記憶
						Color foreground = gc.getForeground();
						Color background = gc.getBackground();
						// 横幅指定
						Table table = (Table) evt.widget;
						TableColumn column = table.getColumn(evt.index);
						int width = (column.getWidth() - 1);
						// 背景色描画
						gc.setBackground(_graphFgColor);
						gc.fillRectangle(evt.x, evt.y, width, evt.height);
//
						gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
						Point strSize = gc.textExtent(str);
						int offset = Math.max(0, Math.round(0.5F * (evt.height - strSize.y)));
						Rectangle r = item.getTextBounds(0);
//						System.out.println("getTextBounds: "+r);
						gc.setForeground(_graphTextColor);
//						gc.drawText(str, evt.x+5, evt.y + offset, true);
						gc.drawText(str, r.x - 1, evt.y + offset, true);
						// 前景色、背景色を元に戻す
						gc.setForeground(foreground);
						gc.setBackground(background);
					}
/*DEBUG*/
				} else if (evt.index == 1) {
					int quantity = Integer.parseInt(item.getText(1).replaceAll(",", ""));
					if (quantity == 0) {
						return;
					}
					Display display = _shell.getDisplay();
					// グラフィックコンテキスト取得
					GC gc = evt.gc;
					// 現在の前景色、背景色を記憶
					Color foreground = gc.getForeground();
					Color background = gc.getBackground();
					// 横幅指定
					Table table = (Table) evt.widget;
					TableColumn column = table.getColumn(evt.index);
					int width = (column.getWidth() - 1) * quantity / cntMax[1];
					// グラフ描画
					gc.setForeground(_graphFgColor);
					gc.setBackground(_graphBgColor);
					gc.fillGradientRectangle(evt.x, evt.y, width, evt.height, false);
					// グラフの枠を描画
					gc.setForeground(display.getSystemColor(SWT.COLOR_YELLOW));
					Rectangle rect = new Rectangle(evt.x, evt.y, width - 1, evt.height - 1);
					gc.drawRectangle(rect);
					gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
					String str = item.getText(1);
					Point strSize = gc.textExtent(str);
					int offset = Math.max(0, Math.round(0.5F * (evt.height - strSize.y)));
					Rectangle r = item.getTextBounds(1);
					gc.setForeground(_graphTextColor);
					gc.drawText(str, r.x - 1, evt.y + offset, true);
					// 前景色、背景色を元に戻す
					gc.setForeground(foreground);
					gc.setBackground(background);
				}
			}
		});
		Listener sortListener = new Listener() {
			public void handleEvent(Event evt) {
				TableColumn sortColumn = table.getSortColumn();
				TableColumn currentColumn = (TableColumn) evt.widget;
				int dir = table.getSortDirection();
				Integer bdir = (Integer) currentColumn.getData(_KEY_SORT_DIR);
				if (sortColumn == currentColumn) {
				// 反転の時
					dir = (bdir == SWT.UP? SWT.DOWN: SWT.UP);
				} else {
				// カラムを変えた時
					table.setSortColumn(currentColumn);
					if (currentColumn == column1) {
					// 抽出条件の時
						dir = (bdir == null || bdir == SWT.UP? SWT.UP: SWT.DOWN);
					} else {
					// 件数	の時
						// 多い順
						dir = (bdir == null || bdir == SWT.DOWN? SWT.DOWN: SWT.UP);
					}
				}
				currentColumn.setData(_KEY_SORT_DIR, dir);
				final int index = currentColumn == column1 ? 0 : 1;
				final int direction = dir;
				Arrays.sort(data, new Comparator<String[]>() {
					@Override
					public int compare(String[] prev, String[] next) {
						int val;
						String val1 = prev[index];
						String val2 = next[index];
						if (index == 0) {
							int i1 = val1.indexOf('（');
							int i2 = val2.indexOf('（');
							Character c1, c2;

							if (i1 >= 0) {
								c1 = _hDays.get((Character)val1.charAt(i1 + 1));
								if (c1 != null) {
									val1 = val1.substring(0, i1 + 1) + c1 + val1.substring(i1 + 2);
								}
							}
							if (i2 >= 0) {
								c2 = _hDays.get((Character)val2.charAt(i2 + 1));
								if (c2 != null) {
									val2 = val2.substring(0, i2 + 1) + c2 + val2.substring(i2 + 2);
								}
							}
							val = val1.compareTo(val2);
						} else {
							val = Integer.parseInt(val1.replaceAll(",", "")) -  Integer.parseInt(val2.replaceAll(",", ""));
						}
						return(direction == SWT.UP? val: -val);
					}
				});
				table.setSortDirection(dir);
				table.clearAll();
			}
		};
		column1.addListener(SWT.Selection, sortListener);
		column2.addListener(SWT.Selection, sortListener);
		table.setSortColumn(column1);
		table.setSortDirection(SWT.UP);
		column1.setData(_KEY_SORT_DIR, SWT.UP);
		return table;
	} // createTable

	int[] parseCountMax(ArrayList<String[]> list) {
		int cnt = 0;
		int max = 0;
		int i, len = list.size();
		for(i=0; i<len; i++) {
			String str;
			String[] row = list.get(i);
			int idx = row[1].indexOf('件');
			if (idx >= 0) {
				str = row[1].substring(0, idx).trim();
			} else {
				str = row[1].trim();
			}
			int val = Integer.parseInt(str);
			cnt += val;
			max = Math.max(max, val);
			// 9,999,999
			row[1] = String.format("%,d", (Integer)val);
		}
		return new int[] { cnt, max };
	} // parseCount

	ArrayList<String[]> printDest(Generator gen, SumAll psum, int cond, int target) {
		ArrayList<String[]> list = new ArrayList<>();
try {
		DateRow drow;
		Sum[] osums = null;
		Sum[][] osums3 = null;
		SumYearly ysum;
		SumMonthly msum;
		int i, j, k, len2, len3, len;
		int option = (cond & ~target);

		if (option == 0) {
		// オプションがない時
			gen.generateNonOption(list, psum);
			return list;
		}
/*
年*
年月*
年日*
年曜*
年月日####曜日省略可
年月曜*
年日曜*
年月日曜###ALL
月*
月日*
月曜*
月日曜*
日*
日曜*
曜*
 */
		switch(option) {
		case (_COND_MONTH ):
		// オプションが月の時
			osums = new Sum[13];
			break;
		case (_COND_MONTH | _COND_DATE ):
		// オプションが月日の時
			osums = new Sum[13 * psum._sum.dates.length];
		break;
		case (_COND_MONTH | _COND_DAY ):
		// オプションが月曜日の時
			osums = new Sum[13 * psum._sum.days.length];
		break;
		case (_COND_MONTH | _COND_DAY | _COND_DATE ):
		// オプションが月曜日日の時
			osums3 = new Sum[13 * psum._sum.days.length][psum._sum.dates.length];
		break;
		case (_COND_DAY ):
		// オプションが曜日の時
			osums = new Sum[psum._sum.days.length];
		break;
		case (_COND_DATE ):
		// オプションが日の時
			osums = new Sum[psum._sum.dates.length];
		break;
		case (_COND_DAY | _COND_DATE ):
		// オプションが曜日日の時
			osums = new Sum[psum._sum.dates.length * psum._sum.days.length];
		break;
		}
		len = psum.size();
		if (len == 0) {
			return list;
		}
		int byear = psum.get(0).year;
		int eyear = psum.get(len - 1).year;
		for(i=0;i<len;i++) {
			ysum = psum.get(i);
			switch(option) {
			case (_COND_YEAR ):
				// オプションが年の時
				gen.generateYear(list, ysum);
				continue;
			case (_COND_YEAR | _COND_DATE ):
			// オプションが年日の時
				osums = new Sum[ysum._sum.dates.length];
				break;
			case (_COND_YEAR | _COND_DAY ):
			// オプションが年曜日の時
				osums = new Sum[ysum._sum.days.length];
				break;
			case (_COND_YEAR | _COND_DAY | _COND_DATE ):
			// オプションが年曜日日の時
				osums = new Sum[ysum._sum.dates.length * ysum._sum.days.length];
				break;
			}
			len2 = ysum.size();
			for(j=0;j<len2;j++) {
				msum = ysum.get(j);
				switch(option) {
				case (_COND_YEAR | _COND_MONTH ):
				// オプションが年月の時
					if (target == _COND_DATE) {
						checkDate(msum);
					}
					gen.generateYearMonth(list, msum);
					continue;
				case (_COND_YEAR | _COND_MONTH | _COND_DAY ):
				// オプションが年月曜日の時
					osums = new Sum[ysum._sum.days.length];
					break;
				}
				len3 = msum.size();
				for(k=0;k<len3;k++) {
					drow = msum.get(k);
					switch(option) {
					case (_COND_DAY ):
					// オプションが曜日の時
						if (osums[drow.day] == null) {
							osums[drow.day] = new Sum();
						}
						osums[drow.day].add(drow);
						continue;
					case (_COND_DATE ):
					// オプションが日の時
						if (osums[drow.date] == null) {
							osums[drow.date] = new Sum();
						}
						osums[drow.date].add(drow);
						continue;
					case (_COND_YEAR | _COND_DATE ):
					// オプションが年日の時
						if (osums[drow.date] == null) {
							osums[drow.date] = new Sum();
						}
						osums[drow.date].add(drow);
						continue;
					case (_COND_YEAR | _COND_DAY ):
					// オプションが年曜日の時
						if (osums[drow.day] == null) {
							osums[drow.day] = new Sum();
						}
						osums[drow.day].add(drow);
						continue;
					case (_COND_YEAR | _COND_MONTH | _COND_DAY ):
					// オプションが年月曜日の時
						if (osums[drow.day] == null) {
							osums[drow.day] = new Sum();
						}
						osums[drow.day].add(drow);
						continue;
					case (_COND_YEAR | _COND_DAY | _COND_DATE ):
					// オプションが年曜日日の時
						if (osums[drow.day * ysum._sum.dates.length + drow.date] == null) {
							osums[drow.day * ysum._sum.dates.length + drow.date] = new Sum();
						}
						osums[drow.day * ysum._sum.dates.length + drow.date].add(drow);
						continue;
					case (_COND_MONTH ):
					// オプションが月の時
						if (osums[drow.month] == null) {
							osums[drow.month] = new Sum();
						}
						osums[drow.month].add(drow);
						continue;
					case (_COND_MONTH | _COND_DATE ):
					// オプションが月日の時
						if (osums[drow.month * ysum._sum.dates.length + drow.date] == null) {
							osums[drow.month * ysum._sum.dates.length + drow.date] = new Sum();
						}
						osums[drow.month * ysum._sum.dates.length + drow.date].add(drow);
						continue;
					case (_COND_MONTH | _COND_DAY | _COND_DATE ):
					// オプションが月曜日日の時
						if (osums3[drow.month * ysum._sum.days.length + drow.day][drow.date] == null) {
							osums3[drow.month * ysum._sum.days.length + drow.day][drow.date] = new Sum();
						}
						osums3[drow.month * ysum._sum.days.length + drow.day][drow.date].add(drow);
						continue;
					case (_COND_MONTH | _COND_DAY ):
					// オプションが月曜日の時
						if (osums[drow.month * psum._sum.days.length + drow.day] == null) {
							osums[drow.month * psum._sum.days.length + drow.day] = new Sum();
						}
						osums[drow.month * psum._sum.days.length + drow.day].add(drow);
						continue;
					case (_COND_DAY | _COND_DATE ):
					// オプションが曜日日の時
						if (osums[drow.date * ysum._sum.days.length + drow.day] == null) {
							osums[drow.date * ysum._sum.days.length + drow.day] = new Sum();
						}
						osums[drow.date * ysum._sum.days.length + drow.day].add(drow);
						continue;
					case (_COND_YEAR | _COND_MONTH | _COND_DATE ):
						// オプションが年月日の時（全てと同じデータ）
						gen.generateYearMonthDate(list, (TimeRow) drow);
						continue;
					case (_COND_ALL):
					// オプションが年月曜日日の時
						gen.generateYearMonthDayDate(list, (TimeRow) drow);
						break;
					}
				} // for(k=0;k<len3;k++)
				if ((cond & ~target) == (_COND_YEAR | _COND_MONTH | _COND_DAY )) {
				// オプションが年月曜日の時
					// 曜日(7)のチェック
					if (target == _COND_DATE) {
						checkYearMonthDayForDate(osums, ysum.year, msum.month);
					} else {
						checkDay(osums, ysum.year, msum.month);
					}
					gen.generateYearMonthDay(list, osums, ysum.year, msum.month);
				}
			} // for(j=0;j<len2;j++)
			switch(option) {
			case (_COND_YEAR | _COND_DATE ):
			// オプションが年日の時
				gen.generateYearDate(list, osums, ysum.year);
				break;
			case (_COND_YEAR | _COND_DAY ):
			// オプションが年曜日の時
				// 曜日(7)のチェック
				checkDay(osums, ysum.year);
				gen.generateYearDay(list, osums, ysum.year);
				break;
			case (_COND_YEAR | _COND_DAY | _COND_DATE ):
			// オプションが年曜日日の時
				gen.generateYearDayDate(list, osums, ysum.year);
				break;
			}
		} // for(i=0;i<len;i++)
		switch(option) {
		case (_COND_MONTH ):
		// オプションが月の時
//			gen.generateMonth(list, oysum);
			// 月(13)のチェック
			checkMonthForDate(osums, byear, eyear);
			gen.generateMonth(list, osums);
			break;
		case (_COND_DAY ):
		// オプションが曜日の時
			// 曜日(7)のチェック
			checkDayForDate(osums, byear, eyear);
			gen.generateDay(list, osums);
			break;
		case (_COND_DATE ):
		// オプションが日の時
			gen.generateDate(list, osums);
			break;
		case (_COND_MONTH | _COND_DATE ):
		// オプションが月日の時
			// 月日(13*32)のチェック
			checkMonthDate(osums, byear, eyear);
			gen.generateMonthDate(list, osums);
			break;
		case (_COND_MONTH | _COND_DAY ):
		// オプションが月曜日の時
			if (target == _COND_DATE) {
				checkMonthDayForDate(osums, byear, eyear);
			} else {
				checkMonthDayForTime(osums, byear, eyear);
			}
			gen.generateMonthDay(list, osums, byear, eyear);
			break;
		case (_COND_DAY | _COND_DATE ):
		// オプションが曜日日の時
			// 曜日日(32*7)のチェック
			checkDayDate(osums, byear, eyear);
			gen.generateDayDate(list, osums);
			break;
		case (_COND_MONTH | _COND_DAY | _COND_DATE ):
		// オプションが月曜日日の時
			// 月曜日(13*7)日(32)のチェック
			checkMonthDayDate(osums3, byear, eyear);
			gen.generateMonthDayDate(list, osums3, psum._sum.days.length);
			break;
		}
		} catch(Exception e) {
			e.printStackTrace();
			String str = e.getMessage();
			MessageBox mbox = new MessageBox(_shell, SWT.ICON_ERROR);
			mbox.setText(_prefix);
			mbox.setMessage(e.getClass().getName()+": "+(str == null?"Exception!!!": str));
			mbox.open();
		}
		return list;
	} // printDest

	// オプションが曜日の時
	// 曜日(7)のチェック
	void checkDayForDate(Sum[] osums, int byear, int eyear) {
//		days = new int[32][7];
		int[][] days = HaACalendar.getDaysForDate(byear, eyear);
		int i, len = days.length;
		int j, len2 = days[0].length;
		for(i=1;i<len;i++) {
			for(j=0;j<len2;j++) {
				if (osums[j] == null) {
					continue;
				}
				if (days[i][j] == 0) {
				// 日付が存在しない時
					if (osums[j].dates[i] == 0) {
						osums[j].dates[i] = -1;
					} else {
						System.err.println(String.format("checkDayForDate: %d～%d年%02d日（%s） (osums[%d].dates[%d] == %d)",
								(Integer)byear,(Integer)eyear,(Integer)i, HaAForm._days[j],(Integer)j,(Integer)i,(Integer)osums[j].dates[i]));
					}
				}
			}
		}
	} // checkDayForDate

	// オプションが月の時
	// 月(13)のチェック
	void checkMonthForDate(Sum[] osums, int byear, int eyear) {
		int[][] days = HaACalendar.getDatesForMonth(byear, eyear);
		int i, len = 13;
		int j, len2 = 32;
		for(i=1;i<len;i++) {
			if (osums[i] == null) {
			// 月が存在しない時
				continue;
			}
			for(j=0;j<len2;j++) {
				if (days[i][j] == 0) {
				// 日付が存在しない時
					if (osums[i].dates[j] <= 0) {
						osums[i].dates[j] = -1;
					} else {
						System.err.println(String.format("checkMonthForDate: %d～%d年%02d月%02d日（%s） (osums[%d].dates[%d] == %d)",
								(Integer)byear,(Integer)eyear,(Integer)i,(Integer)j,(Integer)i,(Integer)j,(Integer)(osums[i].dates[j])));
					}
				}
			}
		}
	} // checkMonthForDate

	// オプションが月曜日の時（日）
	void checkMonthDayForDate(Sum[] osums, int byear, int eyear) {
		int[][][] days = HaACalendar.getDaysForMonthDate(byear, eyear);
		int i, len = 13;
		int j, len2 = 32;
		int k, len3 = days[0][0].length;
		for(i=1;i<len;i++) {
			for(j=1;j<len2;j++) {
				for(k=0;k<len3;k++) {
					if (days[i][j][k] == 0) {
					// 日付が存在しない時
						if (osums[i * len3 + k] != null) {
						// 月曜日のデータが存在する時
							if (osums[i * len3 + k].dates[j] == 0) {
								osums[i * len3 + k].dates[j] = -1;
							} else {
								System.err.println(String.format("checkMonthDayForDate: %d～%d年%02d月（%s） (osums[month(%d) * days(%d) + day(%d)].dates[%d] > 0)",
										(Integer)byear,(Integer)eyear,(Integer)i, HaAForm._days[k],  (Integer)i, (Integer)len3, (Integer)k, (Integer)osums[i * len3 + k].dates[j]));
							}
						}
					}
				}
			}
		}
	} // checkMonthDayForDate

	// オプションが月曜日の時（時）
	void checkMonthDayForTime(Sum[] osums, int byear, int eyear) {
//		days = new int[13][7];
		int[][] days = HaACalendar.getDaysForMonth(byear, eyear);
		int i, len = days.length;
		int j, len2 = days[0].length;
		for(i=1;i<len;i++) {
			for(j=0;j<len2;j++) {
				if (days[i][j] == 0) {
				// 日付が存在しない時
					if (osums[i * len2 + j] != null) {
						System.err.println(String.format("checkMonthDayForTime: %d～%d年%02d月（%s） (osums[i(%d) * len2(%d) + j(%d)] != null)",
								(Integer)byear,(Integer)eyear,(Integer)i, HaAForm._days[j],  (Integer)i, (Integer)len2, (Integer)j));
					}
				}
			}
		}
	} // checkMonthDayForTime

	// オプションが年月曜日の時
	// 曜日(7)のチェック
	void checkYearMonthDayForDate(Sum[] osums, int year, int month) {
		int[][][] days = HaACalendar.getDaysForMonthDate(year, year);
		int j, len2 = 32;
		int k, len3 = days[0][0].length;
		for(j=1;j<len2;j++) {
			for(k=0;k<len3;k++) {
				if (osums[k] == null) {
				// 月曜日のデータが存在しない時
					continue;
				}
				if (days[month][j][k] == 0) {
				// 日付が存在しない時
					if (osums[k].dates[j] == 0) {
						osums[k].dates[j] = -1;
					} else {
						System.err.println(String.format("checkYearMonthDayForDate: %d年%2d月%2d日（%s） (osums[day(%d)].dates[%d](%d) > 0)",
								(Integer)year,(Integer)month,(Integer)j, HaAForm._days[k], (Integer)k, (Integer)j, (Integer)osums[k].dates[j]));
					}
				}
			}
		}
	} // checkYearMonthDayForDate

	// オプションが年曜日の時
	// 曜日(7)のチェック
	void checkDay(Sum[] osums, int year) {
//		days = new int[32][7];
		int[][] days = HaACalendar.getDaysForDate(year);
		int i, len = days.length;
		int j, len2 = days[0].length;
		for(i=1;i<len;i++) {
			for(j=0;j<len2;j++) {
				if (osums[j] == null) {
					continue;
				}
				if (days[i][j] == 0) {
				// 日付が存在しない時
					if (osums[j].dates[i] == 0) {
						osums[j].dates[i] = -1;
					} else {
						System.err.println(String.format("checkDay: %d年%02d日（%s） (osums[%d].dates[%d] == %d)",
								(Integer)year,(Integer)i, HaAForm._days[j],(Integer)j,(Integer)i,(Integer)osums[j].dates[i]));
					}
				}
			}
		}
	} // checkDay

	void checkDate(SumMonthly msum) {
		int i, len = msum._sum.dates.length;
		for(i=0;i<len;i++) {
			if (!HaACalendar.isValidDate(msum.year, msum.month, i)) {
			// 日付が存在しない時
				if (msum._sum.dates[i] == 0) {
					msum._sum.dates[i] = -1;
				} else {
System.err.println(String.format("checkDate: msum._sum.dates[%d]==%d", (Integer)i, (Integer)msum._sum.dates[i]));
				}
			}
		}
	} // checkDate

	// オプションが月曜日日の時
	// 月曜日(13*7)日(32)のチェック
//	osums3 = new Sum[13 * psum._sum.days.length][psum._sum.dates.length];
	void checkMonthDayDate(Sum[][] osums3, int byear, int eyear) {
	}

	// 曜日(7)のチェック
	void checkDay(Sum[] osums, int year, int month) {
		int i, j, len2, len = osums.length;
		for(i=0;i<len;i++) {
			if (osums[i] == null) {
				continue;
			}
			len2 = osums[i].dates.length;
			for(j=0;j<len2;j++) {
				if (!HaACalendar.isValidDate(year, month, j)) {
				// 日付が存在しない時
					if (osums[i].dates[j] <= 0) {
						osums[i].dates[j] = -1;
					} else {
	System.err.println(String.format("checkDay: osums[%d].dates[%d]==%d", (Integer)i, (Integer)j, (Integer)osums[i].dates[j]));
					}
				}
			}
		}
	} // checkDayDate

	// 条件が曜日日の時
	// 曜日日(32*7)のチェック
	void checkDayDate(Sum[] osums, int byear, int eyear) {
		int[][] days = HaACalendar.getDaysForDate(byear, eyear);
		int i, len = days.length;
		int j, len2 = days[0].length;
		for(i=1;i<len;i++) {
			for(j=0;j<len2;j++) {
				if (days[i][j] == 0) {
				// 日付が存在しない時
					if (osums[i * len2 + j] != null) {
						System.err.println(String.format("checkDayDate: osums[%d * %d + %d] != null", (Integer)i, (Integer)len2, (Integer)j));
					}
				}
			}
		}
	} // checkDayDate

	// 月日(13*32)のチェック
	void checkMonthDate(Sum[] osums, int byear, int eyear) {
		int i, len = 13;
		int j, len2;
		for(; byear<=eyear; byear++) {
			for(i=0;i<len;i++) {
				if (osums[i] == null) {
					continue;
				}
				len2 = osums[i].dates.length;
				for(j=1;j<len2;j++) {
					if (!HaACalendar.isValidDate(byear, i+1, j)) {
					// 日付が存在しない時
						if (osums[i * len2 + j] != null) {
							System.err.println(String.format("checkMonthDate: osums[%d * %d + %d] != null", (Integer)i, (Integer)len2, (Integer)j));
						}
						osums[i * len2 + j] = null;
					}
				}
			}
		}
	}

	SumMonthly getRows(ArrayList<DateRow> slist, int cond) {
		SumMonthly sum = new SumMonthly(cond);
		int i, len = slist.size();
		DateRow row;

		if ((cond & _COND_DAILY) == 0) {
		// 月次の時
			for(i=0;i<len;i++) {
				row = slist.get(i);
				if (row instanceof TimeRow) {
					break;
				}
				sum.add(row);
			}
		} else {
		// 日次の時
			for(i=0;i<len;i++) {
				row = slist.get(i);
				if (row instanceof TimeRow) {
					sum.add(row);
					for(i++;i<len;i++) {
						sum.add(slist.get(i));
					}
				}
			}
		}
		return sum;
	} // getRows


	SumYearly createYear(int year, int cond) throws IOException {
		SumYearly psum = new SumYearly(cond);
		File ydir = getYearPath(year);
		File[] childs = ydir.listFiles();
		if (childs == null) {
			return null;
		}
		int i, len = childs.length;
		for(i=0;i<len;i++) {
			if (childs[i].isFile() && childs[i].getName().matches("[0-9][0-9].txt")) {
				SumMonthly sum = getRows(createMonth(childs[i]), cond);
				psum.add(sum);
			}
		}
		return psum;
	} // createYear

	ArrayList<DateRow> createMonth(File file) throws IOException {
		/*
2026:06:04:155:4:00:00::3
2026:06:04:155:4:00:15::2
2026:06:04:155:4:00:30::4
2026:06:04:155:4:00:45::4
2026:06:04:155:4:03:30::1
2026:06:04:155:4:04:30::1
2026:06:04:155:4:04:45::2
2026:06:04:155:4:11:45::1
2026:06:04:155:4:22:30::1
2026:06:04:155:4:23:15::1
2026:06:05:156:5:02:30::2
			.
			.
			.
2026:06:13:164:6:19:00::4
2026:06:13:164:6:19:15::1
2026:06:14:165:7:08:45::1

日,曜日,件数,累計
01,火,16,16
02,水,13,29
03,木,24,53
	.
	.
	.
29,火,49,817
30,水,33,850
31,木,51,901
2023年08月,合計,901
		 */
		String[] sdays = {
				"月","火","水","木","金","土","日",
		};		
		ArrayList<String> hlist = new ArrayList();
		ArrayList<String> dlist = new ArrayList();
		String str, line;
		String[] astr, astr2 = null;
		dlist.add("日,曜日,件数,累計");	
		hlist.add("時,分,件数,累計");	
		BufferedReader br = new BufferedReader(new FileReader(file));
		int sday, bday = 0;
		int syyyy, byyyy = 0;
		int smm, bmm = 0;
		int sdd, bdd = 0;
		int shh, bhh = -1;
		int smm2, bmm2 = -1;
		int cnt, summm = 0, sumhh = 0, sumdd = 0;
		while((line = br.readLine()) != null) {
			astr = line.split("::");
			astr2 = astr[0].split(":");
			syyyy = Integer.parseInt(astr2[_IDX_YYYY]);
			smm = Integer.parseInt(astr2[_IDX_MM]);
			sdd = Integer.parseInt(astr2[_IDX_DD]);
			sday = Integer.parseInt(astr2[_IDX_WEEK]);
			shh = Integer.parseInt(astr2[_IDX_HH]);
			smm2 = Integer.parseInt(astr2[_IDX_MM2]);
//
			Calendar cal = Calendar.getInstance();
			cal.set(syyyy, smm - 1, sdd, shh, smm2 - 15); // 15分戻す
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd:DDD:u:HH:mm");
			str = sdf.format(cal.getTime());
			astr2 = str.split(":");
			syyyy = Integer.parseInt(astr2[_IDX_YYYY]);
			smm = Integer.parseInt(astr2[_IDX_MM]);
			sdd = Integer.parseInt(astr2[_IDX_DD]);
			sday = Integer.parseInt(astr2[_IDX_WEEK]);
			shh = Integer.parseInt(astr2[_IDX_HH]);
			smm2 = Integer.parseInt(astr2[_IDX_MM2]);
//
			cnt = Integer.parseInt(astr[1]);
			boolean isBreakDay = (bdd > 0 && sdd > bdd);
			if (bhh > -1 && shh > bhh
			 || isBreakDay) {
			// 時間が変わった時
			// 又は、日付が変わった時
				sumhh += summm;
				if (bhh != -1) {
				// 分累積データが有る時
					hlist.add(String.format("%02d,00,%d,%d",
							bhh, summm, sumhh));
				}
				summm = 0;
				if (isBreakDay) {
				// 日付が変わった時
					sumdd += sumhh;
					if (bdd != 0) {
					// 時累積データが有る時
						dlist.add(String.format("%02d,%s,%d,%d",
								bdd, sdays[bday - 1], sumhh, sumdd));
					}
					hlist.add(String.format("%d年%02d月%02d日,合計,%d", byyyy, bmm, bdd, sumdd));	
					
					sumhh = 0;
					hlist.add("時,分,件数,累計");	
				}
			}
			byyyy = syyyy;
			bmm = smm;
			bdd = sdd;
			bday = sday;
			bhh = shh;
			bmm2 = smm2;
			summm += cnt;
		}
		br.close();
		sumhh += summm;
		sumdd += sumhh;
		hlist.add(String.format("%02d,00,%d,%d",
				bhh, summm, sumhh));
		if (bday > 0) {
			dlist.add(String.format("%02d,%s,%d,%d",
					bdd, sdays[bday - 1], sumhh, sumdd));
		}
		int year, month, date, day, hour, minute, count;
// /Users/rabbit/haa/rabbit0418/txt/2022/01.txt
// .............................+...+...++.+
		str = file.getPath();
		int i = str.indexOf(_HAA_TEXT) + _HAA_TEXT.length() + 1;
		year = Integer.parseInt(str.substring(i, i + 4));
		month = Integer.parseInt(str.substring(i + 5, i + 7));
		hlist.add(String.format("%d年%02d月%02d日,合計,%d", year, month, bdd, sumdd));	
		dlist.add(String.format("%d年%02d月,合計,%d", year, month, sumdd));
		hlist.addAll(0, dlist);
		ArrayList<DateRow> list = new ArrayList<>();
		int len = _PREFIX.length();

		date = day = 0;
		Iterator<String> si = hlist.iterator(); 
		if ((line = findLine(si, "累計")) != null) {
		// 日,曜日,件数,累計
			while(si.hasNext()) {
				line = si.next();
				if (line.indexOf("合計") >= 0) {
				// 2018年05月,合計,317
					if ((line = findLine(si, "累計")) != null) {
					// 時,分,件数,累計
						DateRow parent = null;
						int pindex = 0;
						int psize = list.size();
						int cindex = psize;
						while(si.hasNext()) {
						// 時,分,件数,累計
							line = si.next();
							if (line.indexOf("合計") >= 0) {
							// 2017年3月1日,合計,5
								astr = line.split(",");
								str = astr[0].substring(astr[0].indexOf('月')+1, astr[0].indexOf('日'));
								int cdate = Integer.parseInt(str.trim());
								int size = list.size();
								for(;;) {
									if (pindex >= psize) {
										new Exception("不正データ："+file.toString()).printStackTrace();
										break;
									}
									parent = list.get(pindex++);
									if (parent.date == cdate) {
										break;
									}
								}
								parent.childIndex = size;
								for(; cindex < size; cindex++) {
									TimeRow child = (TimeRow) list.get(cindex);
									child.year = parent.year;
									child.month = parent.month;
									child.day = parent.day;
									child.date = parent.date;
									child.parent = parent;
								}
								findLine(si, "累計");
							} else {
// 01,00,15,15
								astr = line.split(",");
								if (astr.length >= 3) {
									hour = Integer.parseInt(astr[0].trim());
									minute = Integer.parseInt(astr[1].trim());
									count = Integer.parseInt(astr[2].trim());
									TimeRow child = new TimeRow(0, 0, 0, 0, hour, minute, count);
									list.add(child);
								}
							}
						}
					}
				} else {
				// 月次
// 01,火,33,33
					astr = line.split(",");
					if (astr.length >= 3) {
						date = Integer.parseInt(astr[0].trim());
						count = Integer.parseInt(astr[2].trim());

						switch(astr[1].trim().charAt(0)) {
						default:
						case '日':
							day = DateRow.DAY_SUN;
							break;
						case '月':
							day = DateRow.DAY_MON;
							break;
						case '火':
							day = DateRow.DAY_TUE;
							break;
						case '水':
							day = DateRow.DAY_WED;
							break;
						case '木':
							day = DateRow.DAY_TH;
							break;
						case '金':
							day = DateRow.DAY_FRI;
							break;
						case '土':
							day = DateRow.DAY_SAT;
							break;
						}
						list.add(new DateRow(year, month, date, day, count));
					}
				}
			}
		}
		return list;
	} // createMonth

	static int getDay(int yyyy, int mm, int dd) {
		Calendar cal = Calendar.getInstance();
		cal.set(yyyy, mm, dd);
		SimpleDateFormat sdf = new SimpleDateFormat("dd");
		String bform = sdf.format(cal.getTime());
		return Integer.parseInt(bform);
	}

	String findLine(Iterator<String> si, String key) {
		String line;
		while(si.hasNext()) {
			line = si.next();
			// 時,分,件数,累計
			if (line.indexOf(key) >= 0) {
				return line;
			}
		}
		return null;
	}

	//-------------------------------------------------------------------------------------
	String trimUserId(String text) {
		text = text.trim();
		int idx = text.indexOf("//");
		if (idx >= 0) {
			// http://USER_ID.haa.co.jp
			// USER_ID.haa.co.jp
			text = text.substring(idx+2);
		}
		idx = text.indexOf(".");
		if (idx >= 0) {
			// USER_ID.haa.co.jp
			// USER_ID
			text = text.substring(0, idx);
		}
		return text;
	}

	boolean checkExec(Text tURL) {
//PRINT_LOG::printLogOut("checkExec: "+_jaf+": ");
		if (_progressType == _PTYPE_ACTIVE || !tURL.getText().endsWith(_haa_home_full + '/')) {
			return false;
		}
		return true;
	}

	public void setTitle(String title) {
		_shell.setText(_prefix+" - "+title);
		_title = title;
	}

	void saveHelpData(File cdir, String path) throws IOException {
		BufferedInputStream bis;
		File cfile = new File(cdir, path);
		if (cfile.exists()) {
			if (_HELP_DELETE_ON_EXIT) {
				if (cfile.lastModified() == _exec_time) {
				// 同じ更新時刻の時
					return;
				}
			} else {
				return;
			}
		}
		URL hurl = HaAggregater.class.getResource(path);
		if (hurl == null) {
			return;
		}
		InputStream his = hurl.openStream();
		URLConnection ucon = hurl.openConnection();
		int rlen, bsize, size = ucon.getContentLength();
		boolean defaultSize;
		if (size <= 0) {
			bsize = HELP_BUF_SIZE;
			defaultSize = true;
		} else {
			bsize = Math.min(size, HELP_BUF_SIZE);
			defaultSize = false;
		}
		byte[] buf = new byte[bsize];
		bis = new BufferedInputStream(his);
if (_HELP_DELETE_ON_EXIT) {
		cfile.deleteOnExit(); // 毎回削除
}
		for(rlen=0;rlen < bsize; ) {
			int rcnt = bis.read(buf, rlen, bsize - rlen);
			if (rcnt < 0) {
//				if (!defaultSize && rlen < size || rlen == 0) {
//PRINT_LOG::HaAggregater.printLogErr("Unexpected EOF found! size("+size+") read("+rlen+") hurl "+hurl);
//				}
				break;
			}
			rlen += rcnt;
		}
		bis.close();
		// 中間ディレクトリーを生成（cdir とは異なる場合がある： path "help/index.html"）
		File pdir = cfile.getParentFile();
		if (!pdir.exists()) {
			makeDirs(pdir);
		}
		FileOutputStream fos;
		BufferedOutputStream bos = new BufferedOutputStream(fos = new FileOutputStream(cfile));
		bos.write(buf, 0, rlen);
		bos.close();
		fos.close();
		cfile.setLastModified(_exec_time);
		if (!path.toLowerCase().endsWith(".html")) {
		// HTML ではないので保存のみ
			return;
		}
		bis = new BufferedInputStream(new ByteArrayInputStream(buf, 0, rlen));
		// HTML 解析
		String value;
		HTMLTokenizer tok = new HTMLTokenizer(bis, true, rlen);
		while(tok.nextToken() != HTMLTokenizer.TT_EOF) {
			if (tok.ttype == HTMLTokenizer.TT_TAG && !tok.isEndTag) {
				if (tok.tag == HTML.Tag.A) {
				// アンカーの時
					// 150518: (tok.attrs == null) を考慮すべし
					value = tok.attrs.get(HTML.Attribute.HREF);
					if (value != null && value.indexOf('#') < 0) {
					// マーカー '#XXX' でない時
						saveHelpData(cdir, "help/"+value);
					}
				} else if (tok.tag == HTML.Tag.IMG
				 || tok.tag == HTML.Tag.FRAME) {
				// フレームの時
				// 又は、画像の時
					value = tok.attrs.get(HTML.Attribute.SRC);
					if (value != null) {
						saveHelpData(cdir, "help/"+value);
					}
				}
			}
		}
	} // saveHelpData()

	boolean makeDirs(File dir) {
		if (dir.exists()) {
			return true;
		}
		boolean success = false;
		// ループは御呪い
		for(int i=0;i<3;i++) {
			if (dir.mkdirs()) {
if (_TRACE) {
//PRINT_LOG::	HaAggregater.printLogOut("HaAggregater.mkdirs: "+true+": "+dir);
}
				success = true;
				break;
			}
//PRINT_LOG::HaAggregater.printLogErr("mkdirs: "+false+" "+(i+1)+": "+dir);
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return success;
	} // mkdirs

	Shell _helpShell;

	void helpHelp() throws IOException {
		if (_helpShell != null) {
			_helpShell.forceActive();
			_helpShell.forceFocus();
			return;
		}
		Color scolor = getSeasonColor();
		// アイコン化を解除できないため、SWT.MIN は不可
		Shell shell = _helpShell = new Shell((Shell)null, SWT.CLOSE | SWT.TITLE | SWT.MAX | SWT.RESIZE);
		GridLayout gl = new GridLayout(1, false);
		gl.marginWidth = gl.marginHeight = 0;
		gl.horizontalSpacing = gl.verticalSpacing = 0;
		shell.setLayout(gl);
		shell.setImage(_shell.getImage());
		shell.setText(_prefix+"－ヘルプ");
		shell.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		shell.setLayout(new GridLayout(1, false));

		Composite compH = new Composite(shell, SWT.NONE);
		compH.setBackground(scolor);
		compH.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_BEGINNING
				|GridData.GRAB_HORIZONTAL));
		gl = new GridLayout(3, false);
		gl.marginWidth = gl.marginHeight = 2;
		gl.verticalSpacing = 0;
		compH.setLayout(gl);
		Button bPrev = new Button(compH, SWT.PUSH);
		Button bNext = new Button(compH, SWT.PUSH);
		bPrev.setImage(createImage("images/page_prev.png", 0xffffff));
		bNext.setImage(createImage("images/page_next.png", 0xffffff));
		Composite compPad = new Composite(compH, SWT.NONE);
		GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_BEGINNING
				|GridData.GRAB_HORIZONTAL);
		gd.heightHint = 0;
		compPad.setLayoutData(gd);
//
		Browser browser = new Browser(shell, SWT.NONE);
		browser.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.VERTICAL_ALIGN_FILL
				|GridData.GRAB_HORIZONTAL|GridData.GRAB_VERTICAL));
		String name = "help/haa_help.html";
		saveHelpData(getHome(), name);
// names[1]("text/init.html") をオープン
		String path = new File(getHome(), name).toURI().toURL().toString();
		browser.setUrl(path);
		shell.pack();
//
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Dimension sysd = toolkit.getScreenSize();
		// popup がスクリーンからはみ出さないように調整
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice dgd = ge.getDefaultScreenDevice();
		GraphicsConfiguration dgc = dgd.getDefaultConfiguration();
		Insets ins = toolkit.getScreenInsets(dgc);
		int w = sysd.width - ins.left - ins.right;
		int h = sysd.height - ins.top - ins.bottom;
		float min = 0.95F * Math.min(w, h);
		if (w > h) {
			shell.setSize(Math.round(min * 1.2F), Math.round(min));
		} else {
			shell.setSize(Math.round(min), Math.round(min / 1.2F));
		}
//
		shell.addShellListener(new ShellAdapter() {
			@Override
			public void shellClosed(ShellEvent evt) {
				_helpShell = null;
			}
		});
		bPrev.setEnabled(false);
		bNext.setEnabled(false);
		bPrev.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				browser.back();
				if (!browser.isBackEnabled()) {
					bPrev.setEnabled(false);
				}
				bNext.setEnabled(true);
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {
			}
		});
		bNext.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				browser.forward();
				bPrev.setEnabled(true);
				if (!browser.isForwardEnabled()) {
					bNext.setEnabled(false);
				}
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent evt) {

			}
		});
		browser.addLocationListener(new LocationListener() {
			@Override
			public void changing(LocationEvent evt) {
			}
			@Override
			public void changed(LocationEvent evt) {
				 bPrev.setEnabled(browser.isBackEnabled());
				 bNext.setEnabled(browser.isForwardEnabled());
			}
		});
		SWTMoveWindow.moveTo(shell, SWTMoveWindow.NORTHEAST);
		shell.open();
	} // helpHelp

	void view() {
		Shell shell = _shell;
		Display display = shell.getDisplay();
		try {
			Image image = new Image(display,
					HaAggregater.class.getResourceAsStream(String.format("images/icon%d.png",
							(Integer)getSeasonIndex())));
			shell.setImage(image);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//
		int[] abounds = toIntArray(_prop.getProperty(_property_key_bounds), ":");
		if (abounds != null && abounds.length >= 4) {
//PRINT_LOG::System.out.println(String.format("setBounds %dx%d:%dx%d\n", abounds[0],abounds[1],abounds[2],abounds[3]));
			shell.setBounds(abounds[0], abounds[1], abounds[2], abounds[3]);
		} else {
//PRINT_LOG::System.out.println(String.format("setBounds NULL\n"));
			Toolkit toolkit = Toolkit.getDefaultToolkit();
			Dimension sysd = toolkit.getScreenSize();
			// popup がスクリーンからはみ出さないように調整
			GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
			GraphicsDevice dgd = ge.getDefaultScreenDevice();
			GraphicsConfiguration dgc = dgd.getDefaultConfiguration();
			Insets ins = toolkit.getScreenInsets(dgc);
			int w = sysd.width - ins.left - ins.right;
			int h = sysd.height - ins.top - ins.bottom;
			float min = 0.9F * Math.min(w, h);
			if (w > h) {
				shell.setSize(Math.round(min * 4 / 3), Math.round(min));
			} else {
				shell.setSize(Math.round(min), Math.round(min * 3 / 4));
			}
			SWTMoveWindow.moveTo(shell, SWTMoveWindow.NORTHWEST);
		}
		shell.open();
		while (!shell.isDisposed()){
			if (!display.readAndDispatch()){
				display.sleep();
			}
		}
		display.dispose();
	} // view

	static int[] toIntArray(String str, String der) {
		if (str == null) {
			return null;
		}
		String[] arect = str.split(der);
		int i, len = arect.length;
		int[] dest = new int[len];
		try {
			for(i=0;i<len;i++) {
				dest[i] = Integer.parseInt(arect[i]);
			}
		} catch(NumberFormatException e) {
			e.printStackTrace();
			dest = null;
		}
		return dest;
	} // toIntArray

	public static File getHome() {
		File hdir = new File(System.getProperty("user.home"));
		return new File(hdir, _HAA_HOME);
	}

	public static File getTextPath(String userId) {
		File hdir = new File(getHome(), userId);
		return new File(hdir, _HAA_TEXT);
	}

	public File getTextPath() {
		String str = _prop.getProperty(_property_key_uid);
		if (str == null) {
			return null;
		}
		return getTextPath(str);
	}

	public static File getYearPath(int year, String userId) {
		return new File(getTextPath(userId), String.valueOf(year));
	}

	public File getYearPath(int year) {
		return new File(getTextPath(), String.valueOf(year));
	}

//PRINT_LOG::	static final String _PW_PATH = "res\\_trace.txt";
//PRINT_LOG::	static PrintWriter _pw;

//PRINT_LOG::	void openTrace() throws IOException {
//PRINT_LOG::		if (_PRINT_TRACE) {
//PRINT_LOG::			if (_pw != null) {
//PRINT_LOG::				closeTrace();
//PRINT_LOG::			}
//PRINT_LOG::			File file =  new File(_PW_PATH);
//PRINT_LOG::			_pw = new PrintWriter(new FileWriter(file, false));
//PRINT_LOG::		}
//PRINT_LOG::	}

//PRINT_LOG::	static final boolean _PRINT_TRACE = true;
//PRINT_LOG::	void closeTrace() {
//PRINT_LOG::		if (_PRINT_TRACE) {
//PRINT_LOG::			if (_pw == null) {
//PRINT_LOG::				return;
//PRINT_LOG::			}
//PRINT_LOG::			_pw.close();
//PRINT_LOG::			_pw = null;
//PRINT_LOG::		}
//PRINT_LOG::	}

//PRINT_LOG::	public static void printTrace(String string) {
//PRINT_LOG::		if (_PRINT_TRACE) {
//PRINT_LOG::			if (_pw == null) {
//PRINT_LOG::				return;
//PRINT_LOG::			}
//PRINT_LOG::			_pw.println(string);
//PRINT_LOG::		}
//PRINT_LOG::	}

//PRINT_LOG::	static long _btime;
//PRINT_LOG::	public static void printLogOut(String text) {
//PRINT_LOG::							long ctime = System.currentTimeMillis();
//PRINT_LOG::	System.out.println((ctime - _btime)+": "+text);
//PRINT_LOG::							_btime = ctime;
//PRINT_LOG::	}

//PRINT_LOG::	public static void printLogErr(String text) {
//System.err.println(text);
//PRINT_LOG::	}
}


