2018년 5월 27일 일요일

java8 map

package test.map;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.ArrayUtils;

public class TestOfMap {

/** 対応コード : XX1 */
private static final Map<String, String> cdValOfXx1 = new HashMap<String, String>() {
{
put("new01", "old01");
put("new02", "old01");
put("new03", "old01");
put("new04", "old01");
put("new05", "old01");
}
};

/** 対応コード:XX2 */
private static final Map<String, String> cdValOfXx2 = new HashMap<String, String>() {
{
put("new11", "old11");
put("new12", "old11");
put("new13", "old11");
put("new14", "old11");
put("new15", "old11");
}
};

/** コード */
private static final Map<String, Map<String, String>> cdOfXx1 = new HashMap<String, Map<String, String>>() {
{
put("101", cdValOfXx1);
put("201", cdValOfXx2);
}
};

/** データリストXxx1 */
private static final String[] tblListOfXx1 = {
Tbl1Entity.class.getSimpleName(), Tbl2Entity.class.getSimpleName(),
Tbl3Entity.class.getSimpleName(), };

/** データリストXxx2「 */
public static final String[] tblListOfXx2 = {
Tbl1Entity.class.getSimpleName(), Tbl2Entity.class.getSimpleName(),
Tbl3Entity.class.getSimpleName(), };

/**
* Testメソッド
*/
public void test(){
boolean isRegistOfTbl1 = ArrayUtils.contains(tblListOfXx1, Tbl1Entity.class.getSimpleName());
if (isRegistOfTbl1) {
// Mapから値取得、デフォルートは空
cdValOfXx1.getOrDefault("new11", "");
// TODO 登録処理など

}
}
}

java Iterator list重複削除

Iterator<InfoBean> itr = userCpDepList.iterator();
List<String> dupList = new ArrayList<String>();
while (itr.hasNext()) {
InfoBean info = itr.next();
if (dupList.contains(info.getBuso())){
itr.remove();
}
else{
dupList.add(info.getBuso());
}
}

java8 sort

// ソート
List<InfoBean> userCpDepList = new ArrayList<InfoBean>();
Comparator<InfoBean> orderByItem1 = Comparator.comparing(InfoBean::getItem1).reversed();
Comparator<InfoBean> orderByItem2 = Comparator.comparing(InfoBean::getItem2);
Comparator<InfoBean> orderByItem3 = Comparator.comparing(InfoBean::getItem3);

userCpDepList = userCpDepList.stream()
.sorted(orderByItem1
.thenComparing(orderByItem2
.thenComparing(orderByItem3))).collect(Collectors.toList());

2018년 2월 4일 일요일

log4j

Log4jでログ出力
参考
https://itsakura.com/java_log4jxml

■mavenのpom.xmlにlog4j定義(またはjarを入手し、クラスパスに設定)
■プルジェクト直下にlog4j.xml定義
■テストクラス作成、テスト
-----------pom.xml------------------------------------------------------
<!-- 追加4 log4j -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!-- 追加4 log4j end -->
----------log4j.xml----------------------------------------------------------
説明
<param name="File" value="./log/log.log" />は<!-- log作成場所 -->
<param name="ConversionPattern" value="%d{yyyy/MM/dd HH:mm:ss.SSS} [%t] %-6p %m%n"/><!--log出力時フォーマット -->
<level value="debug" /><!--log出力レベル debug以上出力 -->
<!-- 上記の定義:ログレベルの順番は、trace – debug – info – warn – error – fatal -->
---------------------------------------------
<?xml version="1.0" encoding="MS932" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
   <appender name="Appender1" class="org.apache.log4j.FileAppender">
      <param name="File" value="./log/log.log" />
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d{yyyy/MM/dd HH:mm:ss.SSS} [%t] %-6p %m%n"/>
      </layout>
   </appender>
   <root>
      <level value="debug" />
      <appender-ref ref="Appender1" />
   </root>
</log4j:configuration>
-----------テストクラス作成、テスト----------------------------------------------
package com.mybatis;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

public class LogTest {
public static void main(String[] args) {
// Logger
Logger logger = Logger.getLogger(LogTest.class);
DOMConfigurator.configure("log4j.xml");
logger.trace("trace "+"1");
logger.debug("debug "+"1");
logger.info("info "+"1");
logger.warn("warn "+"1");
logger.error("error "+"1");
}
}
-----------------------------------------------------------------


---------------------------------------------------
※Log4j.propertiesを使う場合、
resources直下に配置
log4j.xmlが存在したら、xmlを優先にするため、注意
mybatisのsqlログを出力したい場合:下記のlog4j.logger.com.example.dao=DEBUG
特定のDaoクラスを定義も可能log4j.logger.com.example.dao.Test1Dao=DEBUG
------------------Log4j.properties-----------------------------------
# Global logging configuration
#log4j.logger.java.sql=DEBUG
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.example.dao=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
------------------------------------------------------------------------------



2018년 2월 3일 토요일

MyBatis2

MyBatisを使って、entity,daoを自動で作成する。

■mavenプロジェクト作成
 (pom.xml修正:mybatis、generator定義、generator拡張時は、拡張クラスを定義)、
■maven-install
■generator(拡張pluginがある場合、plugin定義), mybatis用xml定義
■generator拡張クラス作成
■maven-build(ゴール追加:generator..)
   generatorによって、Dao(Mapper, Mapper.xml), Entityクラスが自動生成される。
 ※build前にDB環境構築(該当テーブル生成して置く)
---------------------------------------------------------------------
■mavenプロジェクト作成
  1.mavenプロジェクト作成
  2.pom.xml修正
  下記追加
---------------------------------------------------------------
  <!-- 追加1 start ※</dependencies>前に-->
    <!-- http://mvnrepository.com/artifact/org.mybatis/mybatis -->
      <dependency>
         <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.0</version>
  </dependency>
<!-- 追加1 end -->

<!-- 追加3 mybatis generator pluginを使うため  start -->
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.6</version>
</dependency>
<!-- 追加3 end -->

  </dependencies>


<!-- 追加2 starat  ※ </project>前に-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.1</version>
<!-- 追加2 end -->

  <!-- 私のjar(generatorをカスタムしたplugin)を追加  -->
          <dependencies>
            <dependency>
              <groupId>com.mybatis2.plugin</groupId>
              <artifactId>plugin</artifactId>
              <version>1.0.0</version>
            </dependency>
          </dependencies>
           </plugin>
  <!-- 私のjar end -->

 <!--  C:\Users\user\.m2\repository\com\mybatis\plugin\plugin\1.0.0\plugin-1.0.0.jar  プラグインのクラスパスを認識させるため、カスタムpluginクラスのjar作成し、こちらの場所に配置しておく-->
        </plugins>
    </build>

</project>
-----------------------------------------------------------------------
■maven-install
 3.Maven Install
      C:\Users\user\.m2\repositoryにinstallされたこと確認
  Maven依存関係
   mybatis-3.4.0.jar ー--> 追加されたこと確認
■generator(拡張pluginがある場合、plugin定義), mybatis用xml定義
 4. resources追加(src/main/resources/)
    ・mybatis-config.xml,
    ・generatorConfig.xml

------------- mybatis-config.xml ---------------------------------------
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!--     JDBCの設定です(1) -->
    <environments default="gissn">
        <environment id="gissn">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="oracle.jdbc.driver.OracleDriver" />
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:XE" />
                <property name="username" value="gissn" />
                <property name="password" value="oracle" />
            </dataSource>
        </environment>
    </environments>

<!--     mapperパッケージを指定します -->
    <mappers>
        <package name="com.example.dao" />
    </mappers>

</configuration>
-----------------------------generatorConfig-------------------------------------
xxx.xxx.xx.x --> localhost

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
    <classPathEntry      location="C:\work\tools\oracle\app\oracle\product\11.2.0\server\jdbc\lib\ojdbc6.jar" />
    <context id="context1" targetRuntime="MyBatis3">

<!-- ★com.mybatis2パッケージに拡張pluginクラスがあるか 確認! start -->
<plugin type="com.mybatis.plugin.MapperClassNamePlugin" />
<plugin type="com.mybatis.plugin.BeanClassNamePlugin" />
<!-- ★com.mybatis2パッケージに拡張pluginクラスがあるか 確認! end -->

<!--     JDBCの設定です (1) -->
        <jdbcConnection
            driverClass="oracle.jdbc.driver.OracleDriver"
            connectionURL="jdbc:oracle:thin:@localhost:1521:XE"
            userId="gissn"
            password="oracle"
        />

<!--     自動生成するエンティティの設定です (2) -->
        <javaModelGenerator
            targetPackage="com.example.entity"
            targetProject="src/main/java/"
        />
        <sqlMapGenerator
            targetPackage="com.example.dao"
            targetProject="src/main/java/"
        />
        <javaClientGenerator
            targetPackage="com.example.dao"
            targetProject="src/main/java/"
            type="XMLMAPPER"
        />

<!--     生成対象のテーブルです(3) -->
        <table schema="gissn" tableName="%" />
    </context>
</generatorConfiguration>
-------------------------------------------------
■generator拡張クラス作成
----BeanClassNamePlugin (~Entityクラス名にするためプラグインクラス作成)---------
package com.mybatis.plugin;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;

/**
 * MyBatis Generatorで生成するクラス名を変更するプラグイン。
 */
public class BeanClassNamePlugin extends PluginAdapter {

    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public void initialized(IntrospectedTable table) {
        super.initialized(table);

        table.setBaseRecordType(table.getBaseRecordType() + "Entity");
        table.setExampleType(replace(table.getExampleType(), "Example", "Filter") );
    }

private String replace(String target, String search, String replace) {
Pattern pattern = Pattern.compile(search);
Matcher matcher = pattern.matcher(target);
target = matcher.replaceAll(replace);
return target;
}
}

---MapperClassNamePlugin (MapperクラスをDaoクラウス名に生成させるため)--------
package com.mybatis.plugin;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
public class MapperClassNamePlugin extends PluginAdapter {
public boolean validate(List<String> warnings) {
return true;
}
@Override
public void initialized(IntrospectedTable introspectedTable) {
introspectedTable.setMyBatis3JavaMapperType(replace(introspectedTable.getMyBatis3JavaMapperType(), "Mapper", "Dao"));//~Mapper.java を変更
introspectedTable.setMyBatis3XmlMapperFileName(replace(introspectedTable.getMyBatis3XmlMapperFileName(), "Mapper", "Dao")); //~Mapper.xml を変更
}
private String replace(String target, String search, String replace) {
Pattern pattern = Pattern.compile(search);
Matcher matcher = pattern.matcher(target);
target = matcher.replaceAll(replace);
return target;
}
}

※pluginクラスをjarでエクスポートし、pom.xml定義場所に配置
 ex)C:\Users\user\.m2\repository\com\mybatis2\plugin\plugin\1.0.0\plugin-1.0.0.jar

----------------------------------------------------
■maven-build(ゴール追加:generator..)
  6.maven ビルドに新規追加し、実行
 ・基底ディレクトリーにmavenプロジェクトのワークスペースを設定
 ・ゴール設定:mybatis-generator:generate

  7. 設定path通り、entity,daoが作成されていればOK
------------------------------------------------------------------





-------------------------------------------------------

■sqlログ出力するため、pom.xmlにlog4j.jar定義
-----------pom.xml--------------------------------------------
<!-- 追加4 log4j -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!-- 追加4 log4j end -->
---------------------------------------------------
※Log4j.propertiesを使う
resources直下に配置
log4j.xmlが存在したら、xmlを優先にするため、注意
mybatisのsqlログを出力したい場合:下記のlog4j.logger.com.example.dao=DEBUG
特定のDaoクラスを定義も可能log4j.logger.com.example.dao.Test1Dao=DEBUG
------------------Log4j.properties-----------------------------------
# Global logging configuration
#log4j.logger.java.sql=DEBUG
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.example.dao=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
------------------------------------------------------------------------------





■insertとinsertSelectiveの違い
insert:
   insert項目がすべて指定されてsql発行される。
  ・パラメータを指定しなかった場合、nullが指定されてしまう。
             ex)
Test1Entity entity = new Test1Entity();
entity.setCol1("insert_1");
entity.setCol2("1");
int result = dao.insert(entity);

実行結果LOG
DEBUG [main] - ==>  Preparing: insert into GISSN.TEST1 (COL1, COL2, COL3 ) values (?, ?, ? )
DEBUG [main] - ==> Parameters:
insert_1(String), 1(String), null
DEBUG [main] - <==    Updates: 1

insertSelective:
 insert項目が指定した項目のみ、指定されてsql発行される。
  ・パラメータを指定しなかった場合、insert項目に指定されない。
  ・null設定してもinsert項目に指定されない。
               ex)
Test1Entity entity = new Test1Entity();
entity.setCol1("insertSv_1");
entity.setCol2("1");
int result = dao.insertSelective(entity);

実行結果LOG
DEBUG [main] - ==>  Preparing: insert into GISSN.TEST1 ( COL1, COL2 ) values ( ?, ? ) 
DEBUG [main] - ==> Parameters: insertSv_1(String), 1(String)
DEBUG [main] - <==    Updates: 1

テーブルTEST1確認
※col3は、default '0':insertメソッドではデフォルト指定カラムがある場合、指定しないとdefault値でinsertできない。null指定したら、nullでinsert。defaultカラムが存在した場合、insertSelectiveメソッドを使った方がいいかもしれない。
--------------------------------------
col1             col2      col3
--------------------------------------
insert_1         1        (NULL)    
insertSv_1      1         0
--------------------------------------

■updateByPrimaryKeyとupdateByPrimaryKeySelective
 ・updateByPrimaryKeyメソッド
    PK以外のすべての項目を更新する。
  設定しない項目は、nullで更新されてしまう。(updateのset文に設定しない項目も追加され、さらにnullで更新)
               ex)col4は、設定してない
Test1Entity entity = new Test1Entity();
entity.setCol1("key1");
entity.setCol2("key2");
entity.setCol3("col3");
int result = dao.updateByPrimaryKey(entity);

実行結果LOG
DEBUG [main] - ==>  Preparing: update GISSN.TEST1 set COL3 = ?, COL4 = ? where COL1 = ? and COL2 = ?
DEBUG [main] - ==> Parameters: col3(String), null, insert1(String),  (String)
DEBUG [main] - <==    Updates: 1

・ updateByPrimaryKeySelectiveメソッド
 PK以外の設定した項目のみ更新する。
 nullで設定した項目は更新されない。(updateのset文に追加されない)

               ex)col4は、設定してない
Test1Entity entity = new Test1Entity();
entity.setCol1("key1");
entity.setCol2("key2");
entity.setCol3("col3");
int result = dao.updateByPrimaryKeySelective(entity);

実行結果LOG
DEBG [main] - ==>  Preparing: update GISSN.TEST1 SET COL3 = ? where COL1 = ? and COL2 = ?
DEBUG [main] - ==> Parameters: col3(String), insertSv1(String),  (String)
DEBUG [main] - <==    Updates: 1



2017년 1월 3일 화요일

Timing Control For script based Animations

描画のアニメーションは、setInterval, setTimeoutを使っていたが
requestAnimationFrameを使うと
ブラウザの負荷状況によって最も適したタイミングでアニメーションを開始し、
バックグラウンドにある場合は、速度が低くなるため、メモリ消費を抑えることができる
アニメーションを終了したい場合は requestCanselAnimationFrameを呼び出す


https://liginc.co.jp/web/js/130758

requestAnimationFrameの特徴
  • ブラウザの描画更新単位と同じ単位で呼び出される
  • 次の再描画が行われる前に次のアニメーションをする関数を呼び出す
  • タブが非アクティブの時はFPSを落とす
setInteval、setTimeoutの特徴
  • ブラウザで準備ができていなくても必ず実行
  • タブが非アクティブの状態でも常に実行
------------------------------------------
loop();
function loop() {
    console.log('requestAnimationFrame直前');
    requestId = window.requestAnimationFrame(loop);
    var currentTime = new Date().getTime();
    var now = window.performance.now();
    console.log('now() :' + (now));
    //経過時刻を取得
    var status = currentTime - startTime // 描画開始時刻から経過時刻を引く
    // 経過時間が2000ミリ秒すぎたらアニメーション終了
    if (status > 2000) {
        console.log('END!! ');
        console.log('requestId : ' + requestId);
        // loopを終了させる
        window.cancelAnimationFrame(requestId);
    }
    console.log(status);
}
---------------------------------------------------------------
canvasとrequestAnimationFrameを使いサンプル作成
---------------------------------------------------------------

        <div id="info"></div>
        <canvas id="sample" width="500" height="500"></canvas>
        <button id="move">move</button>
        <button id="stop">stop</button>      
        <script type="text/javascript">
            var startTime = new Date().getTime();
            console.log(startTime);
            (function () {
                var sample = document.getElementById('sample');
                sample.width = 500;
                sample.height = 500;
                var ctx = sample.getContext('2d');
                var sizeX = 50;
                var sizeY = 50;
                var _amount = 5;
                var _x = 0;
                var _y = 0;
                var _w = sample.width;
                var _h = sample.height;
                var requestId;

                render(_x, _y);
                document.getElementById('move').addEventListener('click', loop);
                document.getElementById('stop').addEventListener('click', stop);

                var dirX = _amount;
                var dirY = _amount * 5;

                function render(_x, _y) {
                    ctx.clearRect(0, 0, _w, _h);
                    ctx.beginPath();
                    ctx.fillRect(_x, _y, sizeX, sizeY);
                    ctx.closePath();
                }
                var start;
                function loop() {

                    if (!start) {
                        start = window.performance.now();
                    }

                    requestId = window.requestAnimationFrame(loop);

                    if (_x > _w || _x < 0) {
                        dirX *= -1;
                        _y += dirY;
                    }

                    if (_y > _h || _y < 0) {
                        dirY *= -1;
                    }
                    _x += dirX;

                    render(_x, _y);
                }

                function stop() {
                    var end = window.performance.now();
                    document.getElementById('info').innerHTML = floatFormat((end - start) / 1000, 2);
                    start = null;
                    window.cancelAnimationFrame(requestId);
                }
               
                // 小数点n位までを残す関数
                // number=対象の数値
                // n=残したい小数点以下の桁数
                function floatFormat( number, n ) {
                        var _pow = Math.pow( 10 , n ) ;
                        return Math.round( number * _pow ) / _pow ;
                }

            })();
        </script>
--------------------------------------------------------------


performance

http://ohgyun.com/335
http://html5.ohtsu.org/html5advent2011/
http://d.hatena.ne.jp/jovi0608/20111209/1323428049
http://qiita.com/mamo/items/ff336b5cc0a1a95e03a7

1. performance.timing 




여기서는 performance.timing 객체와 관련된 PerformanceTiming 인터페이스의 속성에 대해 정리해보려고 한다.
(스펙에 기재된 내용을 이해하기 쉽게 번역한 정리본이다. 원문 링크) 


navigationStart     
    이전 페이지에서 도큐먼트가 unload를 시작한 시점('prompt to unload a document'를 끝낸 시점)(1).
    이전 페이지가 없을 경우 fetchStart와 동일하다.

unloadEventStart
    
이전 페이지와 현재 페이지가 동일 근원(same origin)일 때, unload 이벤트를 시작하는 시점.
    이전 페이지가 없거나 동일 근원이 아닐 경우 0.
unloadEventEnd     unload 이벤트가 끝나는 시점.

redirectStart  
    HTTP 리다이렉트나 동일 근원 상의 리다이렉트가 수행되는 경우, 그 시작 시점을 의미하며 fetchStart와 동일하다.
    없을 경우 0.
redirectEnd  
    위와 같은 조건에서 마지막으로 리다이렉트된 응답의 첫 번째 바이트를 받은 시점. 없을 경우 0.

fetchStart  
    HTTP 요청으로 새로운 리소르를 불러오기 시작하는 시점.
    애플리케이션 캐시가 있을 경우 캐시 존재 여부를 체크하기 시작하는 시점.
    캐시가 없는 경우, 리소스를 받아오기 시작하는 시점.

domainLookupStart     
    
도메인에 해당하는 IP를 검색(DNS Lookup)하기 시작하는 시점.
    이미 연결되어 있거나(2), 캐시되어 있거나, 로컬 리소스일 경우, fetchStart와 동일한 값.
domainLookupEnd     
    
DNS Lookup이 종료되는 시점. 조건에 해당하지 않을 경우, fetchStart와 동일.


connectStart     
    
브라우저(3)가 문서를 받기 위해 서버와 연결을 시도하는 시점.
    이미 연결되어 있거나, 캐시되어 있거나, 로컬 리소스일 경우, domainLookupEnd와 동일한 값.
connectEnd     
    
브라우저가 서버와 연결을 맺은 시점.
    조건에 해당하지 않을 경우, domainLookupEnd와 동일.

requestStart     
    
브라우저가 서버, 애플리케이션 캐시 또는 로컬 리소스에 현재 문서에 대한 요청을 시작하는 시점(4).

responseStart     
    
브라우저가 서버로부터 응답 데이터의 첫 번째 바이트를 받은 시점.
responseEnd     
    
브라우저가 응답 데이터의 마지막 바이트를 받은 시점 또는 연결이 끊기 시점 중 빠른 값.

domLoading     
    브
라우저가 문서를 만들기 시작하는 시점. 문서 준비 상태(5)가 "loading"이 되었을 때. (6)
domInteractive     
    브라우저가 문서 준비 상태를 "interactive"로 변경하는 시점.
domContentLoadedEventStart     
    문서에서 DOMContentLoaded 이벤트가 호출되는 시점.
domComplete     
    브라우저가 문서 준비 상태를 "complete"로 변경하는 시점.


loadEventStart     
    
문서의 "load" 이벤트가 발생하는 시점. 이벤트가 호출되지 않았다면 0이다.
loadEventEnd     
    문서의 load 이벤트가 완료된 시점.

----------------------------------------------------------------------------------------------------------
(1) prompt to unload a document : http://dev.w3.org/html5/spec/history.html#prompt-to-unload-a-document
(2) persistent connection : '영구적인 접속' 또는 '지속적인 접속'이지만 문맥상 '이미 연결되어 있다'고이라고 번역
(3) User Agent 이지만 여기서는 이해를 위해 브라우저라고 번역
(4) requestEnd는 스펙에 포함되어 있지 않다. request 완료 시점이 네트워크 완료 시점과 정확히 일치하지 않는 경우가 있고,  몇몇 User Agent는 HTTP Layer 캡슐화 때문에 request 종료 시점을 파악하는데 비용이 들기 때문이다.
(5) 문서 준비 상태(current document readiness). 문서 상태가 변경될 때마다 readystatechange 이벤트가 호출되며, document.readyState 속성에서 확인할 수 있다.
     "loading": 문서를 생성하고 파싱하는 단계.

     "interactive": 파싱이 종료되고, 남은 리소스를 가져오는 단계.
     "complete": 로드가 완료된 상태. 

2.performance.navigation.type
アクセスの状態を表す(どうやってアクセスしたかがわかる)

0  urlを打ち込んだかクリックでアクセスした場合
1  リロードでアクセス
2 history.back(), history.forward()でアクセス
3. 将来のための予約


3.hight solution Time
performance.now()メソッドを使い、ページを開いた時からnow()メソッドを実行するまでの時刻を
DOMHighResTimeStamp 型で取得できる
(ミリ秒の整数値.浮動小数点は1/1000 ex.2025.6950000000002)

DOMHighResTimeStamp 型
従来、Web アプリケーションの時間を計測しようとする場合は、DOMTimeStamp を返す Date.now() のようなものを使っていました。DOMTimeStamp は値としてミリ秒の整数値を返します。高精度計時に必要とされる、より高い精度を提供するために、DOMHighResTimeStamp と呼ばれる新しい型が導入されました。この型は浮動小数点の値であり、ミリ秒で時間を返します。しかし、その値は浮動小数点なので、ミリ秒より小さい値を表現できるため、1/1000 ミリ秒の精度を生成できます。