diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000000000000000000000000000000000000..451ad67c29d11dc3c53b928bbbd87101f29440e3
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,6 @@
+{
+  "extends": "eslint:recommended",
+  "env": {
+    "browser": true
+  }
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..bca51b352e768f4c537189c215af810d65135580
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/dist/fonts/jQueryTimeline.eot b/dist/fonts/jQueryTimeline.eot
new file mode 100644
index 0000000000000000000000000000000000000000..b91e7e935212a59f1e9cfb22ceca624d4fe37509
Binary files /dev/null and b/dist/fonts/jQueryTimeline.eot differ
diff --git a/dist/fonts/jQueryTimeline.svg b/dist/fonts/jQueryTimeline.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ee61ae6a278ff412d22dd0b0550079ee97e11c3d
--- /dev/null
+++ b/dist/fonts/jQueryTimeline.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+<json>
+<![CDATA[
+{
+	"fontFamily": "jQueryTimeline",
+	"majorVersion": 1,
+	"minorVersion": 0,
+	"license": "MIT",
+	"copyright": "ka2.org",
+	"designer": "ka2@ka2.org",
+	"designerURL": "https://ka2.org/",
+	"version": "Version 1.0",
+	"fontId": "jQueryTimeline",
+	"psName": "jQueryTimeline",
+	"subFamily": "Regular",
+	"fullName": "jQueryTimeline",
+	"description": "Font generated by IcoMoon."
+}
+]]>
+</json>
+</metadata>
+<defs>
+<font id="jQueryTimeline" horiz-adv-x="1024">
+<font-face units-per-em="1024" ascent="960" descent="-64" />
+<missing-glyph horiz-adv-x="1024" />
+<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
+<glyph unicode="&#xea37;" glyph-name="pushpin" data-tags="pushpin, pin" d="M512 960c-141.384 0-256-114.616-256-256 0-119.286 81.586-219.516 192-247.934v-488.066l128 128v360.066c110.414 28.418 192 128.65 192 247.934 0 141.384-114.614 256-256 256zM448 704c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.652-64-64-64z" />
+<glyph unicode="&#xea60;" glyph-name="calendar" data-tags="calendar, date, schedule, time, day" d="M320 576h128v-128h-128zM512 576h128v-128h-128zM704 576h128v-128h-128zM128 192h128v-128h-128zM320 192h128v-128h-128zM512 192h128v-128h-128zM320 384h128v-128h-128zM512 384h128v-128h-128zM704 384h128v-128h-128zM128 384h128v-128h-128zM832 960v-64h-128v64h-448v-64h-128v64h-128v-1024h960v1024h-128zM896 0h-832v704h832v-704z" />
+<glyph unicode="&#xeb24;" glyph-name="spinner" data-tags="spinner, loading, loading-wheel, busy, wait" d="M512 656.904c-32.964 0-59.686 26.724-59.686 59.686v179.060c0 32.964 26.722 59.686 59.686 59.686 32.962 0 59.688-26.722 59.688-59.686v-179.060c0-32.964-26.726-59.686-59.688-59.686zM512-36.956c-20.602 0-37.304 16.702-37.304 37.304v179.060c0 20.602 16.702 37.304 37.304 37.304 20.604 0 37.304-16.704 37.304-37.304v-179.060c0-20.602-16.7-37.304-37.304-37.304zM377.756 624.64c-19.34 0-38.146 10.034-48.512 27.988l-89.53 155.070c-15.452 26.764-6.282 60.986 20.482 76.438 26.762 15.45 60.986 6.284 76.438-20.482l89.53-155.072c15.452-26.764 6.282-60.986-20.482-76.438-8.81-5.084-18.432-7.504-27.926-7.504zM735.856 26.744c-11.602 0-22.886 6.022-29.108 16.792l-89.53 155.070c-9.27 16.056-3.77 36.592 12.29 45.864 16.056 9.264 36.59 3.77 45.864-12.292l89.532-155.068c9.27-16.058 3.768-36.592-12.292-45.864-5.286-3.048-11.060-4.502-16.756-4.502zM279.344 530.060c-8.86 0-17.838 2.256-26.064 7.006l-155.072 89.53c-24.978 14.422-33.538 46.362-19.116 71.342 14.42 24.978 46.364 33.538 71.342 19.116l155.070-89.53c24.98-14.422 33.538-46.362 19.116-71.34-9.668-16.756-27.226-26.124-45.276-26.124zM899.648 194.326c-5.064 0-10.196 1.29-14.894 4.004l-155.068 89.53c-14.274 8.24-19.164 26.494-10.924 40.768 8.242 14.276 26.496 19.166 40.766 10.924l155.070-89.532c14.274-8.24 19.164-26.492 10.924-40.766-5.53-9.574-15.562-14.928-25.874-14.928zM243.41 399.504h-179.060c-26.784 0-48.496 21.712-48.496 48.496s21.712 48.496 48.496 48.496h179.060c26.784 0 48.496-21.712 48.496-48.496s-21.712-48.496-48.496-48.496zM959.65 418.156c-0.002 0 0 0 0 0h-179.060c-16.482 0.002-29.844 13.364-29.844 29.844s13.364 29.844 29.844 29.844c0.002 0 0 0 0 0h179.060c16.482 0 29.844-13.362 29.844-29.844 0-16.48-13.364-29.844-29.844-29.844zM124.366 179.402c-15.472 0-30.518 8.028-38.81 22.39-12.362 21.41-5.026 48.79 16.384 61.148l155.072 89.532c21.41 12.368 48.79 5.028 61.15-16.384 12.362-21.412 5.026-48.79-16.384-61.15l-155.072-89.53c-7.050-4.070-14.748-6.006-22.34-6.006zM744.632 552.448c-10.314 0-20.346 5.352-25.874 14.926-8.24 14.274-3.35 32.526 10.924 40.768l155.070 89.528c14.272 8.236 32.526 3.352 40.768-10.922 8.24-14.274 3.35-32.526-10.924-40.768l-155.070-89.528c-4.7-2.714-9.83-4.004-14.894-4.004zM288.136 19.284c-6.962 0-14.016 1.774-20.48 5.504-19.626 11.332-26.35 36.428-15.020 56.054l89.53 155.070c11.33 19.628 36.426 26.352 56.054 15.022 19.626-11.332 26.35-36.43 15.020-56.054l-89.53-155.072c-7.598-13.166-21.392-20.524-35.574-20.524zM646.266 650.758c-5.062 0-10.196 1.29-14.894 4.002-14.274 8.242-19.164 26.494-10.924 40.766l89.534 155.070c8.24 14.274 26.492 19.166 40.766 10.922 14.274-8.242 19.164-26.494 10.924-40.766l-89.532-155.070c-5.53-9.57-15.56-14.924-25.874-14.924z" />
+<glyph unicode="&#xec5b;" glyph-name="more" data-tags="more, dots, menu" d="M384 896h256v-256h-256zM384 576h256v-256h-256zM384 256h256v-256h-256z" />
+<glyph unicode="&#xec5c;" glyph-name="more-horizontal" data-tags="more, dots, menu" d="M384 768c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128zM384 448c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128zM384 128c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128z" />
+<glyph unicode="&#xec6a;" glyph-name="more-vertical" data-tags="menu, dots, more" d="M832 512c70.692 0 128-57.308 128-128s-57.308-128-128-128c-70.692 0-128 57.308-128 128s57.308 128 128 128zM512 512c70.692 0 128-57.308 128-128s-57.308-128-128-128c-70.692 0-128 57.308-128 128s57.308 128 128 128zM192 512c70.692 0 128-57.308 128-128s-57.308-128-128-128c-70.692 0-128 57.308-128 128s57.308 128 128 128z" />
+<glyph unicode="&#xec6b;" glyph-name="dot" data-tags="circle-small" d="M320 448c0 106.039 85.961 192 192 192s192-85.961 192-192c0-106.039-85.961-192-192-192s-192 85.961-192 192z" />
+<glyph unicode="&#xed5d;" glyph-name="plus" data-tags="plus, add, sum" d="M960 512h-384v384h-128v-384h-384v-128h384v-384h128v384h384z" />
+<glyph unicode="&#xed5e;" glyph-name="minus" data-tags="minus, subtract, line" d="M64 512h896v-128h-896v128z" />
+<glyph unicode="&#xed6d;" glyph-name="cross" data-tags="cross, cancel, close, quit, remove" d="M893.254 738.746l-90.508 90.508-290.746-290.744-290.746 290.744-90.508-90.506 290.746-290.748-290.746-290.746 90.508-90.508 290.746 290.746 290.746-290.746 90.508 90.51-290.744 290.744z" />
+<glyph unicode="&#xedee;" glyph-name="circle-right" data-tags="circle-right, right, circle-next, arrow" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM544 192l256 256-256 256-96-96 96-96h-288v-128h288l-96-96z" />
+<glyph unicode="&#xedf2;" glyph-name="circle-left" data-tags="circle-left, left, circle-previous, arrow" d="M512-64c282.77 0 512 229.23 512 512s-229.23 512-512 512c-282.77 0-512-229.23-512-512s229.23-512 512-512zM512 864c229.75 0 416-186.25 416-416s-186.25-416-416-416c-229.75 0-416 186.25-416 416s186.25 416 416 416zM480 704l-256-256 256-256 96 96-96 96h288v128h-288l96 96z" />
+<glyph unicode="&#xedf6;" glyph-name="circle-fill-right" data-tags="circle-right, right, circle-next, arrow" d="M512-64c282.77 0 512 229.23 512 512s-229.23 512-512 512-512-229.23-512-512 229.23-512 512-512zM192 512h351.998l-127.998 128 95.998 96 288.002-288-288.002-288-95.998 96 127.998 128h-351.998v128z" />
+<glyph unicode="&#xedfa;" glyph-name="circle-fill-left" data-tags="circle-left, left, circle-previous, arrow" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM832 384h-351.998l127.998-128-95.998-96-288.002 288 288.002 288 95.998-96-127.998-128h351.998v-128z" />
+<glyph unicode="&#xee29;" glyph-name="arrow-down" data-tags="arrow-down, down, arrow-bottom, download" d="M512-64l448 1024-448-192-448 192z" />
+</font></defs></svg>
\ No newline at end of file
diff --git a/dist/fonts/jQueryTimeline.ttf b/dist/fonts/jQueryTimeline.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..abe6b93e24a0dcd5dec924cb8d40d9fff7357cba
Binary files /dev/null and b/dist/fonts/jQueryTimeline.ttf differ
diff --git a/dist/fonts/jQueryTimeline.woff b/dist/fonts/jQueryTimeline.woff
new file mode 100644
index 0000000000000000000000000000000000000000..4da20d1381a765fbfc51629f01a9e04994dee129
Binary files /dev/null and b/dist/fonts/jQueryTimeline.woff differ
diff --git a/dist/timeline.min.css b/dist/timeline.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..d2db0cc955b0afaed0f886a89f5daeff025b811c
--- /dev/null
+++ b/dist/timeline.min.css
@@ -0,0 +1 @@
+@font-face{font-family:jQueryTimeline;src:url(fonts/jQueryTimeline.eot?t4qpol);src:url(fonts/jQueryTimeline.eot?t4qpol#iefix) format("embedded-opentype"),url(fonts/jQueryTimeline.ttf?t4qpol) format("truetype"),url(fonts/jQueryTimeline.woff?t4qpol) format("woff"),url(fonts/jQueryTimeline.svg?t4qpol#jQueryTimeline) format("svg");font-weight:400;font-style:normal}[class*=" jqtl-"],[class^=jqtl-]{font-family:jQueryTimeline!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.jqtl-pushpin:before{content:"\ea37"}.jqtl-calendar:before{content:"\ea60"}.jqtl-spinner:before{content:"\eb24"}.jqtl-more:before{content:"\ec5b"}.jqtl-more-horizontal:before{content:"\ec5c"}.jqtl-more-vertical:before{content:"\ec6a"}.jqtl-dot:before{content:"\ec6b"}.jqtl-plus:before{content:"\ed5d"}.jqtl-minus:before{content:"\ed5e"}.jqtl-cross:before{content:"\ed6d"}.jqtl-circle-right:before{content:"\edee"}.jqtl-circle-left:before{content:"\edf2"}.jqtl-circle-fill-right:before{content:"\edf6"}.jqtl-circle-fill-left:before{content:"\edfa"}.jqtl-arrow-down:before{content:"\ee29"}*,::after,::before{-webkit-box-sizing:border-box;box-sizing:border-box}.timeline-container{position:relative;display:block;visibility:hidden;margin:15px;font-size:1rem;line-height:1.5}.timeline-header{text-align:left}.timeline-headline{margin-top:0;margin-bottom:.5rem;font-family:inherit;font-size:1.3rem;font-weight:500;line-height:1.1;color:inherit}.timeline-from-date,.timeline-to-date{margin-right:.3rem}.timeline-from-date:before{content:"\ea60";font-family:jQueryTimeline!important;margin-right:.3rem;color:#7f7f7f;font-weight:400}.timeline-to-date:before{content:"\301C";margin-right:.3rem;color:#7f7f7f;font-weight:400}.timeline-body{position:relative;display:block;margin:0 auto;width:inherit;overflow-x:auto;overflow-y:hidden;text-align:center;z-index:1}.timeline-wrapper{position:relative;display:inline-block;margin:0 1px;width:auto;height:259px}.timeline-wrapper:after,.timeline-wrapper:before{content:"";position:absolute;top:0;width:1px;height:100%}.timeline-wrapper:before{left:0;border-left:1px solid #ddd}.timeline-wrapper:after{right:0;border-right:1px solid #ddd}.timeline-timetable{display:table;position:relative;border-collapse:collapse;border-spacing:0;border-color:#ddd;border-top:1px solid #ddd;border-right:0;border-bottom:1px solid #ddd;border-left:0}.timeline-timetable>thead>tr>th{border:0}.timeline-timetable>thead>tr>th.scale-major{padding-top:4px;padding-bottom:4px;font-size:100%;color:#555;text-align:center;border-top:0;border-right:1px solid #ddd;border-bottom:0;border-left:0}.timeline-timetable>thead>tr>th.scale-medium{padding-top:0;padding-bottom:4px;font-size:85%;color:#777;text-align:center;border-top:0;border-right:1px solid #ddd;border-bottom:0;border-left:0}.timeline-timetable>thead>tr>th.scale-major:last-child,.timeline-timetable>thead>tr>th.scale-medium:last-child{border-right:0}.timeline-timetable>thead>tr>th.scale-small{padding:0;border-top:0;border-right:1px solid #ddd;border-bottom:1px solid #ddd;border-left:0}.timeline-timetable>thead>tr>th.scale-small:last-child{border-right:0}.timeline-to-prev{position:absolute;top:-2rem;left:15px;z-index:9}.timeline-to-next{position:absolute;top:-2rem;right:15px;z-index:9}.spacer-cell{display:block;width:29px;min-height:5px}.timeline-events{position:absolute;display:block;left:0;width:100%;height:200px;z-index:9}.timeline-node{position:absolute;display:block;margin:6px 0;padding:4px 25px 4px 10px;height:auto;line-height:20px;vertical-align:middle;text-align:left;background-color:#e3d7a3;color:#777e41;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:4px;cursor:pointer;z-index:8;-webkit-transition:all 1s ease 0;transition:all 1s ease 0}.timeline-event-pointer{margin:0;padding:0;line-height:1;text-align:center;background-color:#f0f0f0;border-radius:100%;border:solid 4px #4496d3;background-image:none;background-size:cover;background-repeat:no-repeat;background-position:center center}.timeline-node.timeline-event-pointer.hovered{z-index:99}.timeline-node.timeline-event-pointer.active{-webkit-box-shadow:0 10px 6px -6px rgba(51,51,51,.25);box-shadow:0 10px 6px -6px rgba(51,51,51,.25);z-index:99}.timeline-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.timeline-node.timeline-text-truncate.active{margin:2px 0 4px;border:solid 1px rgba(61,61,61,.25);-webkit-box-shadow:0 10px 6px -6px rgba(51,51,51,.25);box-shadow:0 10px 6px -6px rgba(51,51,51,.25);z-index:99}.timeline-node.timeline-text-truncate:after{content:"\ec5c";font-family:jQueryTimeline!important;font-size:14px;position:absolute;right:5px}.timeline-loader{position:absolute;display:inline-block;width:48px;height:48px;margin:0;padding:0;top:50%;left:50%;opacity:.3;-webkit-animation:spin 2.1s linear infinite;animation:spin 2.1s linear infinite}.timeline-loader i{position:absolute;top:0;left:0;font-size:48px}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.timeline-line-canvas{position:absolute;display:block;left:0;bottom:0;width:100%;height:200px;z-index:6}.timeline-grids{position:absolute;left:0;height:200px;border-top:1px solid #ddd;z-index:0}.timeline-grids>tbody>tr>td{padding:0;border-top:0;border-right:1px dotted #ddd;border-bottom:0;border-left:0;vertical-align:bottom}.timeline-grids>tbody>tr>td:first-child{border-left:0}.timeline-grids>tbody>tr>td:last{border-right:0}.timeline-needle-pointer{position:absolute;display:block;top:56px;width:1px;height:calc(100% - 56px);border-left:2px dotted #e8383d;z-index:19}.timeline-needle-pointer:before{content:"\ea37";font-family:jQueryTimeline!important;position:absolute;top:-8px;left:-7.5px;font-size:13px;color:#e8383d}.timeline-footer{position:relative;top:50%;width:100%;z-index:5}.timeline-nav{width:inherit}.timeline-to-next-default,.timeline-to-prev-default{width:2rem;height:2rem;line-height:2rem;font-size:2rem;color:rgba(71,71,71,.325);text-decoration:none}.timeline-to-next-default:active,.timeline-to-next-default:focus,.timeline-to-next-default:hover,.timeline-to-prev-default:active,.timeline-to-prev-default:focus,.timeline-to-prev-default:hover{color:rgba(71,71,71,.75);text-decoration:none}.timeline-to-next-custom,.timeline-to-prev-custom{width:2rem;height:2rem;line-height:2rem;vertical-align:middle;text-align:center;border-radius:50%;background-color:rgba(51,51,51,.2);color:#fff;text-decoration:none}.timeline-to-next-custom:active,.timeline-to-next-custom:focus,.timeline-to-next-custom:hover,.timeline-to-prev-custom:active,.timeline-to-prev-custom:focus,.timeline-to-prev-custom:hover{background-color:rgba(51,51,51,.3);color:rgba(255,255,255,.75);text-decoration:none}.timeline-event-view{display:block;margin:0 1em}.timeline-event-header{margin-top:0;margin-bottom:1rem;border-bottom:dotted 1px #a8a8a8}.timeline-event-label{font-family:inherit;font-size:1.75rem;font-weight:500;line-height:1.1;color:inherit}.timeline-event-meta{margin-top:0;margin-bottom:.5rem;font-size:1rem;font-weight:300}.timeline-event-meta:before{content:"\ea60";font-family:jQueryTimeline!important;color:#999;margin-right:.5rem}.timeline-event-date-separator{display:inline-block}.timeline-event-date-separator:after{content:"\301c";color:#777;font-weight:400;margin-left:.5rem;margin-right:.5rem}.timeline-event-body{margin-top:0;margin-bottom:1rem}.timeline-event-footer{margin-top:0;margin-bottom:1rem}
\ No newline at end of file
diff --git a/dist/timeline.min.js b/dist/timeline.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..12add434b5c6201e6d8fce8ac0e5d14aeaca1f6a
--- /dev/null
+++ b/dist/timeline.min.js
@@ -0,0 +1 @@
+!function(e){function t(t){var i,n,r,l=e(t),s=l.data("timeline");console.info(s.timeline[0].attributes),r=/-|\/|\s|\:/,n=s.timeline.attr("actual-start-datetime").split(r);var c=new Date(Number(n[0]),Number(n[1])-1,Number(n[2]),Number(n[3]),Number(n[4]),Number(n[5]));Number(n[0])<100&&c.setFullYear(Number(n[0]));var h=e("<div />",{addClass:"timeline-header"}),u=e("<div />",{addClass:"timeline-body"}),p=e("<div />",{addClass:"timeline-footer"}),g=e("<div />",{addClass:"timeline-wrapper"}),y=e("<table />",{addClass:"timeline-timetable timeline-scale"}),v=e("<div />",{addClass:"timeline-events"}),b=e("<table />",{addClass:"timeline-timetable timeline-grids"}),w=e("<div />",{addClass:"timeline-needle-pointer"}),x=e("<div />",{addClass:"timeline-events default-events"}),M=new Date(c),D={years:{medium_scale:"months",medium_cols:12,small_scale:"days",small_cols:Number(s.timeline.attr("min-grid-per"))},months:{medium_scale:"days",medium_cols:new Date(c.getFullYear(),c.getMonth()+1,0).getDate(),small_scale:"hours",small_cols:Number(s.timeline.attr("min-grid-per"))},days:{medium_scale:"hours",medium_cols:24,small_scale:"minutes",small_cols:Number(s.timeline.attr("min-grid-per"))}},k=s.timeline.attr("scale"),N=D[k].medium_scale,F=D[k].small_scale,Y=Number(s.timeline.attr("min-grid-per"))*Number(s.timeline.attr("min-grid-size")),C=[D[k].medium_cols];if(l.hasClass("timeline-container")||l.addClass("timeline-container"),l.find(".timeline-events").length>0&&(l.find(".timeline-events").clone().appendTo(x),a(x,s)),"point"===s.timeline.attr("type")||"mixed"===s.timeline.attr("type"))var L=e("<canvas />",{addClass:"timeline-line-canvas"});if(l.empty(),M="years"===s.timeline.attr("scale")?new Date(M.setFullYear(M.getFullYear()+Number(s.timeline.attr("range"))-1)):"months"===s.timeline.attr("scale")?new Date(M.setMonth(M.getMonth()+Number(s.timeline.attr("range"))-1)):new Date(M.setDate(M.getDate()+Number(s.timeline.attr("range"))-1)),"days"===N&&Number(s.timeline.attr("range"))>1)for(i=1;i<Number(s.timeline.attr("range"));i++)C.push(new Date(c.getFullYear(),c.getMonth()+1+i,0).getDate());else for(i=1;i<Number(s.timeline.attr("range"));i++)C.push(D[k].medium_cols);if(s.timeline.attr("show-headline")){var z,H,T,I,S;switch(s.timeline.attr("scale")){case"years":T=I="",1==s.timeline.attr("zerofill-year")&&(c.getFullYear()<100?T="00":c.getFullYear()<1e3&&(T="0"),M.getFullYear()<100?I="00":M.getFullYear()<1e3&&(I="0")),z=s.timeline.attr("datetime-prefix")+T+f(s.timeline.attr("datetime-format-year"),c),H=s.timeline.attr("datetime-prefix")+I+f(s.timeline.attr("datetime-format-year"),M);break;case"months":z=s.timeline.attr("datetime-prefix")+f(s.timeline.attr("datetime-format-year")+s.timeline.attr("datetime-format-month"),c),H=s.timeline.attr("datetime-prefix")+f(s.timeline.attr("datetime-format-year")+s.timeline.attr("datetime-format-month"),M);break;case"days":z=s.timeline.attr("datetime-prefix")+f(s.timeline.attr("datetime-format-full"),c),H=s.timeline.attr("datetime-prefix")+f(s.timeline.attr("datetime-format-full"),M)}S='<span class="timeline-from-date">'+z+'</span><span class="timeline-to-date">'+H+"</span>",h.append('<h3 class="timeline-headline">'+S+"</h3>")}var j,P,A,E=mediumLevelRow=smallLevelRow="<tr>",_=d(C)*D[k].small_cols;for(s.timeline.attr("total-cols",_),i=0;i<Number(s.timeline.attr("range"));i++){switch(E+='<th colspan="'+C[i]*D[k].small_cols+'" class="scale-major scale-'+k+'">',j=new Date(c),k){case"years":j.setFullYear(j.getFullYear()+i),A=f(s.timeline.attr("datetime-format-year"),j);break;case"months":j.setMonth(j.getMonth()+i),A=f(s.timeline.attr("datetime-format-month"),j);break;case"days":j.setDate(j.getDate()+i),A=f(s.timeline.attr("datetime-format-day"),j)}E+=A+"</th>"}for(E+="</tr>",i=0;i<d(C);i++){switch(mediumLevelRow+='<th colspan="'+D[k].small_cols+'" class="scale-medium scale-'+N+'">',j=new Date(c),N){case"months":P=i%D[k].medium_cols,A=Y<18?"":P+1;break;case"days":j.setDate(j.getDate()+i),A=Y<20?"":j.getDate();break;case"hours":P=i%D[k].medium_cols,A=Y<40?"":P+":00"}mediumLevelRow+=A+"</th>"}for(mediumLevelRow+="</tr>",i=0;i<_;i++)smallLevelRow+='<th class="scale-small scale-'+F+'"><span class="spacer-cell"></span></th>';var O="<tr>";for(i=0;i<_;i++)O+='<td class="scale-small"><span class="spacer-cell"></span></td>';if(O+="</tr>",0==s.timeline.attr("show-pointer"))w.css("display","none");else{var W=m(o(!0),s);W>-1?w.css("left",W+"px"):w.css("display","none")}var G=e("<div />",{addClass:"timeline-loader",css:{display:"block"}});G.append('<i class="jqtl-spinner"></i><span class="sr-only">Loading...</span>');var J='<div class="timeline-nav">',X=""===s.timeline.attr("navi-icon-left")?"jqtl-circle-left":s.timeline.attr("navi-icon-left"),R=""===s.timeline.attr("navi-icon-right")?"jqtl-circle-right":s.timeline.attr("navi-icon-right");return J+='<a href="javascript:void(0);" class="timeline-to-prev '+(/^jqtl-circle-.*$/.test(X)?"timeline-to-prev-default":"timeline-to-prev-custom")+'"><i class="'+X+'"></i></a>',J+='<a href="javascript:void(0);" class="timeline-to-next '+(/^jqtl-circle-.*$/.test(R)?"timeline-to-next-default":"timeline-to-next-custom")+'"><i class="'+R+'"></i></a>',J+="</div>",y.append("<thead>"+E+mediumLevelRow+smallLevelRow+"</thead>"),b.append("<tbody>"+O+"</tbody>"),"point"===s.timeline.attr("type")||"mixed"===s.timeline.attr("type")?g.append(y.prop("outerHTML")+v.prop("outerHTML")+L.prop("outerHTML")+b.prop("outerHTML")+w.prop("outerHTML")):g.append(y.prop("outerHTML")+v.prop("outerHTML")+b.prop("outerHTML")+w.prop("outerHTML")),u.append(g),p.append(J),l.append(h),l.append(u),l.append(p),l.append(G.prop("outerHTML")),l}function i(t){var i=e(t),a=i.data("timeline");y="auto"===a.timeline.attr("timeline-height")||"number"!=typeof a.timeline.attr("timeline-height")?Number(a.timeline.attr("rows"))*p:Number(a.timeline.attr("timeline-height"));var n={width:i.find(".timeline-timetable.timeline-scale").outerWidth(),height:63};i.find(".timeline-wrapper")[0].offsetHeight!=n.height+y&&(i.find(".timeline-wrapper").css("height",n.height+y+"px"),i.find(".timeline-events").css("height",y+"px"),i.find(".timeline-line-canvas").css("height",y+"px").attr("width",n.width).attr("height",y),i.find(".timeline-grids").css("height",y+"px")),a.timeline.attr("min-grid-size",Number(a.timeline.attr("min-grid-size"))<5?30:Number(a.timeline.attr("min-grid-size"))),i.find(".spacer-cell").width()!=a.timeline.attr("min-grid-size")-1&&i.find(".spacer-cell").css("width",a.timeline.attr("min-grid-size")-1+"px");var r=-1*((i.find(".timeline-body").outerHeight()-i.find(".timeline-scale").outerHeight())/2+i.find(".timeline-to-prev").outerHeight());return i.find(".timeline-to-prev").css("top",r+"px"),i.find(".timeline-to-next").css("top",r+"px"),i.find(".timeline-body").scroll(function(){var t=e(this).scrollLeft();t<1?i.find(".timeline-to-prev").hide():t>=n.width-e(this).outerWidth()-2?i.find(".timeline-to-next").hide():(i.find(".timeline-to-prev").show(),i.find(".timeline-to-next").show())}),i}function a(t,i){if(e(t).find(".timeline-events").children().length>0){var a=[],n=[],r=0;e(t).find(".timeline-events").children().each(function(){if(e(this).data("timelineNode")){var t=new Function("return "+e(this).data("timelineNode"))();t.label=e(this).text(),t.eventId&&n.push(Number(t.eventId)),a.push(t)}}),a.length>0&&(r=n.length>0?Math.max.apply(null,n)+1:r,a.forEach(function(e,t,i){e.eventId||(i[t].eventId=r,r++)}),i.timeline.text(JSON.stringify(a)))}}function n(t){var i=e(t),a=i.data("timeline"),n=new Function("return "+a.timeline.text())(),l=new Date(a.timeline.attr("actual-start-datetime")),o=new Date(l),m=a.timeline.attr("type"),d=a.timeline.attr("scale"),c=Number(a.timeline.attr("range")),h=(Number(a.timeline.attr("rows")),Number(a.timeline.attr("total-cols"))),u=Number(a.timeline.attr("min-grid-per")),f=Number(a.timeline.attr("min-grid-size")),y={x:0,y:0,w:0},v=f*h-1;switch(i.find(".timeline-loader").css("display","block"),d){case"years":o.setYear(o.getFullYear()+c);break;case"months":o.setMonth(o.getMonth()+c-1);break;case"days":o.setDate(o.getDate()+c)}console.info(["placeEvents",a.timeline,n,l,o,h,v]),i.find(".timeline-events").empty(),n.forEach(function(t,a){if(t.start){var n,r=new Date(t.start),c=void 0==t.end?new Date(t.start):new Date(t.end),h=u*f;if(s(r,l,o)){switch(d){case"years":y.x=Math.round((r-l)*v/(o-l));break;case"months":y.x=Math.floor((r-l)/864e5*h);break;case"days":y.x=Math.floor((r-l)/36e5*h)}if(y.y=void 0!==t.row?(t.row-1)*p:0,s(c,l,o)){switch(d){case"years":y.w=Math.floor((c-l)/2592e6*h-y.x);break;case"months":y.w=Math.floor((c-l)/864e5*h-y.x);break;case"days":y.w=Math.floor((c-l)/36e5*h-y.x)}0==y.w&&(y.w=1)}else switch(d){case"years":y.w=Math.floor((o-l)/2592e6*h-y.x);break;case"months":y.w=Math.floor((o-l)/864e5*h-y.x);break;case"days":y.w=Math.floor((o-l)/36e5*h-y.x)}}else if(s(c,l,o))switch(y.x=0,y.y=void 0!==t.row?(t.row-1)*p:0,d){case"years":y.w=Math.floor((c-l)/2592e6*h);break;case"months":y.w=Math.floor((c-l)/864e5*h);break;case"days":y.w=Math.floor((c-l)/36e5*h)}else if(s(l,r,c)&&s(o,r,c))switch(y.x=0,y.y=void 0!==t.row?(t.row-1)*p:0,d){case"years":y.w=Math.floor((o-l)/2592e6*h);break;case"months":y.w=Math.floor((o-l)/864e5*h);break;case"days":y.w=Math.floor((o-l)/36e5*h)}else y.w=0;if(console.info([y.x,y.y,y.w,r,c,t.eventId]),y.w>0){if("point"===m){var b=t.margin?Number(t.margin):g;b=(b=b<0?0:b)>p/2?p/2-1:b,n=e("<div />",{addClass:"timeline-node timeline-event-pointer",id:"evt-"+t.eventId,css:{left:y.x-Math.floor(p/2)+b+"px",top:y.y+b+"px",width:p-2*b+"px",height:p-2*b+"px"},title:t.label}),t.bdColor?n.css("border-color",t.bdColor):t.bgColor&&n.css("border-color",t.bgColor),t.image&&n.css("background-image","url("+t.image+")"),t.relation&&e.each(t.relation,function(t,i){-1==e.inArray(t,["before","after","size"])||isNaN(i)?"curve"===t?-1!=e.inArray(i,["lt","rt","lb","rb"])&&n.attr("data-relay-curve",i):n.attr("data-relay-"+t,i):n.attr("data-relay-"+t,Number(i))})}else n=e("<div />",{addClass:"timeline-node timeline-text-truncate",id:"evt-"+t.eventId,css:{left:y.x+"px",top:y.y+"px",width:y.w+"px"},text:t.label}),t.color&&n.css("color",t.color),y.w<f&&n.css("padding-left","1.5rem").css("padding-right","0").css("text-overflow","clip");t.bgColor&&n.css("background-color",t.bgColor),t.extend&&e.each(t.extend,function(e,t){n.attr("data-"+e,t)}),i.find(".timeline-events").append(n.prop("outerHTML"))}}}),i.find(".timeline-loader").css("display","none"),"point"!==m&&"mixed"!==m||(r(i),i.find(".timeline-event-pointer").hover(function(t){var i;"mouseenter"===t.type?(i={left:parseInt(e(this).css("left")),top:parseInt(e(this).css("top")),width:parseInt(e(this).css("width")),height:parseInt(e(this).css("height"))},e(this).attr("data-default-axis",JSON.stringify(i)),e(this).hasClass("hovered")||e(this).addClass("hovered").animate({left:i.left-p/10,top:i.top-p/10,width:i.width+p/10*2,height:i.height+p/10*2},0)):"mouseleave"===t.type&&(i=e(this).data("defaultAxis"),e(this).css("left",i.left+"px").css("top",i.top+"px").css("width",i.width+"px").css("height",i.height+"px"),e(this).removeAttr("data-default-axis"),e(this).hasClass("hovered")&&e(this).removeClass("hovered"))}))}function r(t){function i(e,t,i){if("object"==typeof e&&"object"==typeof t){i=i||!1;var n={x:Math.abs((e.x-t.x)/p),y:Math.abs((e.y-t.y)/p)};if(a.beginPath(),a.moveTo(e.x,e.y),!1!==i){switch(i){case"lt":controlPoint={relayStartX:e.x,relayStartY:t.y+p,cpx:e.x,cpy:t.y,relayEndX:e.x+p,relayEndY:t.y};break;case"rt":controlPoint={relayStartX:t.x-p,relayStartY:e.y,cpx:t.x,cpy:e.y,relayEndX:t.x,relayEndY:e.y+p};break;case"lb":controlPoint={relayStartX:e.x,relayStartY:t.y-p,cpx:e.x,cpy:t.y,relayEndX:e.x+p,relayEndY:t.y};break;case"rb":controlPoint={relayStartX:t.x-p,relayStartY:e.y,cpx:t.x,cpy:e.y,relayEndX:t.x,relayEndY:e.y-p}}(n.x>1||n.y>1)&&a.lineTo(controlPoint.relayStartX,controlPoint.relayStartY),a.quadraticCurveTo(controlPoint.cpx,controlPoint.cpy,controlPoint.relayEndX,controlPoint.relayEndY)}a.lineTo(t.x,t.y),a.stroke()}}var a,n=t.find(".timeline-node.timeline-event-pointer"),r=t.find(".timeline-line-canvas")[0];r.getContext&&(a=r.getContext("2d"),n.each(function(){var t,n,l,o,s,m=void 0==e(this).data("relayLinecolor")?e(this).css("border-left-color"):e(this).data("relayLinecolor"),d=void 0==e(this).data("relayLinesize")?Math.round(p/10):e(this).data("relayLinesize");a.strokeStyle=m,a.lineWidth=d,a.lineJoin="round",a.lineCap="round",o={x:(p-a.lineWidth)/2,y:p/2},t={x:e(this)[0].offsetLeft+o.x,y:Math.floor(e(this)[0].offsetTop/p)*p+o.y},void 0!=e(this).data("relayBefore")&&(s=((n=e(this).data("relayBefore")>0?{x:e("#evt-"+e(this).data("relayBefore"))[0].offsetLeft+o.x,y:Math.floor(e("#evt-"+e(this).data("relayBefore"))[0].offsetTop/p)*p+o.y}:{x:0,y:t.y}).y-t.y)/p,Math.abs(s)>0&&void 0!=e(this).data("relayCurve")&&-1!=e.inArray(e(this).data("relayCurve"),["lt","rt","lb","rb"])?i(n,t,e(this).data("relayCurve")):i(n,t)),void 0!=e(this).data("relayAfter")&&(l=e(this).data("relayAfter")>0?{x:e("#evt-"+e(this).data("relayAfter"))[0].offsetLeft+o.x,y:Math.floor(e("#evt-"+e(this).data("relayAfter"))[0].offsetTop/p)*p+o.y}:{x:r.width,y:t.y},s=(t.y-l.y)/p,Math.abs(s)>0&&void 0!=e(this).data("relayCurve")&&-1!=e.inArray(e(this).data("relayCurve"),["lt","rt","lb","rb"])?i(t,l,e(this).data("relayCurve")):i(t,l))}))}function l(t){if(0==e(".timeline-event-view").length)return!0;console.info(t),e(".timeline-event-view").empty();var i,a=e("<div />",{addClass:"timeline-event-header"}),n=e("<h3 />",{addClass:"timeline-event-label"}),r=e("<div />",{addClass:"timeline-event-meta"}),l=e("<div />",{addClass:"timeline-event-body"}),o=e("<div />",{addClass:"timeline-event-footer"});return n.text(t.label),i='<span class="timeline-event-start-date">'+f("Y/m/d H:i",t.start)+"</span>",t.end&&(i+='<span class="timeline-event-date-separator"></span>',i+='<span class="timeline-event-end-date">'+f("Y/m/d H:i",t.end)+"</span>"),a.append(n.prop("outerHTML")+r.append(i).prop("outerHTML")),t.content&&l.html(t.content),e(".timeline-event-view").append(a.prop("outerHTML")+l.prop("outerHTML")+o.prop("outerHTML")),!0}function o(t){var i=new Date;return t&&b().then(function(){i=e("body").data("serverDate"),e.removeData("body","serverDate")},function(){i=new Date}),i}function s(e,t,i){var a=new Date(e).getTime(),n=new Date(t).getTime(),r=new Date(i).getTime();return a-n>=0&&r-a>=0}function m(e,t){var i,e="[object Date]"===Object.prototype.toString.call(e)?e:new Date(e),a=t.timeline,n=new Date(a.attr("actual-start-datetime")),r=new Date(n),l=a.attr("scale"),o=Number(a.attr("range")),m=Number(a.attr("total-cols")),d=Number(a.attr("min-grid-per")),c=Number(a.attr("min-grid-size")),h=c*m-1,u=d*c;switch(l){case"years":r=new Date(r.setFullYear(r.getFullYear()+o-1));break;case"months":r=new Date(r.setMonth(r.getMonth()+o-1));break;case"days":r=new Date(r.setDate(r.getDate()+o-1))}if(s(e,n,r)){switch(l){case"years":i=Math.round((e-n)*h/(r-n));break;case"months":i=Math.floor((e-n)/864e5*u);break;case"days":i=Math.floor((e-n)/36e5*u)}return i}return!1}function d(e){return e.reduce(function(e,t,i,a){return e+t})}function c(e){var t=[];for(var i in e)e.hasOwnProperty(i)&&t.push(e[i]);return t}function h(e){var t=[];for(var i in e)e.hasOwnProperty(i)&&t.push(i);return t}function u(e,t){var i=function(e,t){return Array(e+1).join(t)}(t-1,"0");return String(e).length==t?e:(i+e).substr(-1*e)}function f(t,i){var a="[object Date]"===Object.prototype.toString.call(i)?i:new Date(i),n={Jan:"January",Feb:"February",Mar:"March",Apr:"April",May:"May",Jun:"June",Jul:"July",Aug:"August",Sep:"September",Oct:"October",Nov:"November",Dec:"December"},r={Sun:"Sunday",Mon:"Monday",Tue:"Tuesday",Wed:"Wednesday",Thu:"Thurseday",Fri:"Friday",Sat:"Saturday"},l=["am","pm"],o=t.split(""),s="",m=!1,d=function(e){var t=new Date(e.getFullYear(),e.getMonth()+1,1);return t.setTime(t.getTime()-1),t.getDate()},f=function(e){var t,i=new Date(e.getFullYear(),0,1),a=0;for(t=0;t<12;t++)i.setMonth(t),a+=d(i);return 365===a?0:1},p=function(e){var t,i=new Date(e.getFullYear(),0,1),a=0;for(t=0;t<e.getMonth();t++)i.setMonth(t),a+=d(i);return a+e.getDate()},g=function(e){var t=e.getHours();return t>12?t-12:t},y=function(e){return e.getHours()>12?l[1]:l[0]};return""===t?a:("object"==typeof e.timeline.global&&(n="object"==typeof e.timeline.global.month?e.timeline.global.month:n,r="object"==typeof e.timeline.global.day?e.timeline.global.day:r,l="object"==typeof e.timeline.global.ma?e.timeline.global.ma:l),o.forEach(function(e,t){var i,l,v;if(!1!==m)return m=!1,!0;switch(e){case"Y":case"o":i=a.getFullYear();break;case"y":i=(""+a.getFullYear()).slice(-2);break;case"m":i=("0"+(a.getMonth()+1)).slice(-2);break;case"n":i=a.getMonth()+1;break;case"F":i=c(n)[a.getMonth()];break;case"M":i=h(n)[a.getMonth()];break;case"d":i=("0"+a.getDate()).slice(-2);break;case"j":i=a.getDate();break;case"S":i=["st","nd","rd","th"][function(){var e=a.getDate();return 1==e||2==e||3==e||21==e||22==e||23==e||31==e?Number((""+e).slice(-1)-1):3}()];break;case"w":case"W":i=a.getDay();break;case"l":i=c(r)[a.getDay()];break;case"D":i=h(r)[a.getDay()];break;case"N":i=0===a.getDay()?7:a.getDay();break;case"a":i=y(a);break;case"A":i=y(a).toUpperCase();break;case"g":i=g(a);break;case"h":i=("0"+g(a)).slice(-2);break;case"G":i=a.getHours();break;case"H":i=("0"+a.getHours()).slice(-2);break;case"i":i=("0"+a.getMinutes()).slice(-2);break;case"s":i=("0"+a.getSeconds()).slice(-2);break;case"z":i=p(a);break;case"t":i=d(a);break;case"L":i=f(a);break;case"c":l=a.getTimezoneOffset(),tzo=[Math.floor(Math.abs(l)/60),Math.abs(l)%60],v=l<0?"+":"-",i=a.getFullYear()+"-"+u(a.getMonth()+1,2)+"-"+u(a.getDate(),2)+"T",i+=u(a.getHours(),2)+":"+u(a.getMinutes(),2)+":"+u(a.getSeconds(),2),i+=v+u(tzo[0],2)+":"+u(tzo[1],2);break;case"r":l=a.getTimezoneOffset(),tzo=[Math.floor(Math.abs(l)/60),Math.abs(l)%60],v=l<0?"+":"-",i=h(r)[a.getDay()]+", "+a.getDate()+" "+h(n)[a.getMonth()]+" "+a.getFullYear()+" ",i+=u(a.getHours(),2)+":"+u(a.getMinutes(),2)+":"+u(a.getSeconds(),2)+" ",i+=v+u(tzo[0],2)+u(tzo[1],2);break;case"u":i=a.getTime();break;case"U":i=Date.parse(a)/1e3;break;case"\\":m=!0,i=o[t+1];break;default:i=e}s+=i}),s)}var p=40,g=2,y=0;"global"in e.timeline&&"object"==typeof e.timeline.global&&void 0!==e.timeline.global.rowH&&(p=Number(e.timeline.global.rowH));var v={init:function(a){var r=e.extend({type:"bar",scale:"days",startDatetime:"currently",datetimePrefix:"",showHeadline:!0,datetimeFormat:{full:"Y/m/d",year:"Y",month:"n",day:"n/j"},minuteInterval:30,zerofillYear:!1,range:3,rows:5,height:"auto",minGridPer:2,minGridSize:30,rangeAlign:"current",naviIcon:{left:"jqtl-circle-left",right:"jqtl-circle-right"},showPointer:!0},a);return this.each(function(){var a=e(this),l=a.data("timeline"),s=e("<div />",{title:a.find(".timeline-headline").text(),type:r.type,scale:r.scale,"start-datetime":r.startDatetime,"datetime-prefix":r.datetimePrefix,"show-headline":r.showHeadline?1:0,"datetime-format-full":r.datetimeFormat.full,"datetime-format-year":r.datetimeFormat.year,"datetime-format-month":r.datetimeFormat.month,"datetime-format-day":r.datetimeFormat.day,"minute-interval":r.minuteInterval,"zerofill-year":r.zerofillYear?1:0,range:r.range,rows:r.rows,"timeline-height":r.height,"min-grid-per":r.minGridPer,"min-grid-size":r.minGridSize,"range-align":r.rangeAlign,"navi-icon-left":r.naviIcon.left,"navi-icon-right":r.naviIcon.right,"show-pointer":r.showPointer?1:0,text:""});if(a.on("click.timeline",".timeline-to-prev",v.dateback),a.on("click.timeline",".timeline-to-next",v.dateforth),a.on("click.timeline",".timeline-node",v.openEvent),a.on("align.timeline",v.alignment),!l){a.data("timeline",{target:a,timeline:s});var m,d,c,h;switch("currently"===r.startDatetime?m=o(!0):(m=new Date(r.startDatetime),h=/-|\//,c=r.startDatetime.split(h),Number(c[0])<100&&m.setFullYear(Number(c[0]))),r.scale){case"years":d=m.getFullYear()+"-01-01 00:00:00";break;case"months":d=m.getFullYear()+"-"+(m.getMonth()+1)+"-01 00:00:00";break;case"days":d=m.getFullYear()+"-"+(m.getMonth()+1)+"-"+m.getDate()+" 00:00:00";break;default:d=m.getFullYear()+"-"+(m.getMonth()+1)+"-"+m.getDate()+" "+d.getHours()+":00:00"}console.info(m,d),a.data("timeline").timeline.attr("actual-start-datetime",d),t(a),i(a),a.trigger("align.timeline",[r.rangeAlign]),a.css("visibility","visible")}var u=0,f=setInterval(function(){1==++u&&(n(a),clearInterval(f))},300)})},destroy:function(){return this.each(function(){var t=e(this),i=t.data("timeline");e(window).off(".timeline"),i&&(i.timeline.remove(),t.removeData("timeline"))})},render:function(a){return this.each(function(){var r=e(this),l=r.data("timeline");"type"in a&&l.timeline.attr("type",a.type),"scale"in a&&l.timeline.attr("scale",a.scale),"startDatetime"in a&&l.timeline.attr("start-datetime",a.startDatetime),"datetimePrefix"in a&&l.timeline.attr("datetime-prefix",a.datetimePrefix),"showHeadline"in a&&l.timeline.attr("show-headline",a.showHeadline?1:0),"datetimeFormat"in a&&(void 0!=typeof a.datetimeFormat.full&&l.timeline.attr("datetime-format-full",a.datetimeFormat.full),void 0!=typeof a.datetimeFormat.year&&l.timeline.attr("datetime-format-year",a.datetimeFormat.year),void 0!=typeof a.datetimeFormat.day&&l.timeline.attr("datetime-format-day",a.datetimeFormat.day)),"minuteInterval"in a&&l.timeline.attr("minute-interval",a.minuteInterval),"zerofillYear"in a&&l.timeline.attr("zerofill-year",a.zerofillYear?1:0),"range"in a&&l.timeline.attr("range",a.range),"rows"in a&&l.timeline.attr("rows",a.rows),"height"in a&&l.timeline.attr("timeline-height",a.height),"minGridPer"in a&&l.timeline.attr("min-grid-per",a.minGridPer),"minGridSize"in a&&l.timeline.attr("min-grid-size",a.minGridSize),"rangeAlign"in a&&l.timeline.attr("range-align",a.rangeAlign),"naviIcon"in a&&(void 0!=typeof a.naviIcon.left&&l.timeline.attr("navi-icon-left",a.naviIcon.left),void 0!=typeof a.naviIcon.right&&l.timeline.attr("navi-icon-right",a.naviIcon.right)),"showPointer"in a&&l.timeline.attr("show-pointer",a.showPointer?1:0);var s,m,d,c;switch("currently"===l.timeline.attr("start-datetime")?s=o(!0):(s=new Date(l.timeline.attr("start-datetime")),c=/-|\//,d=l.timeline.attr("start-datetime").split(c),Number(d[0])<100&&s.setFullYear(Number(d[0]))),l.timeline.attr("scale")){case"years":m=s.getFullYear()+"-01-01 00:00:00";break;case"months":m=s.getFullYear()+"-"+(s.getMonth()+1)+"-01 00:00:00";break;case"days":m=s.getFullYear()+"-"+(s.getMonth()+1)+"-"+s.getDate()+" 00:00:00";break;default:m=s.getFullYear()+"-"+(s.getMonth()+1)+"-"+s.getDate()+" "+m.getHours()+":00:00"}l.timeline.attr("actual-start-datetime",m),console.info('Fired "render" method',a,l.timeline),r.find(".timeline-container").empty().removeClass("timeline-container"),t(r),i(r),n(r),r.trigger("align.timeline",[l.timeline.attr("range-align")])})},show:function(){return this.each(function(){e(this).css("display","block").css("visibility","visible")})},hide:function(){return this.each(function(){e(this).css("visibility","hidden").css("display","none")})},initialized:function(t){return this.each(function(){var i=e(this),a=i.data("timeline");a&&"function"==typeof t&&(console.info('Fired "initialized" method after initialize this plugin.'),t(i,a))})},dateback:function(t){t.preventDefault();var i=e(this).parents(".timeline-container"),a=i.data("timeline"),n=i.find(".timeline-body")[0].clientWidth,r=i.find(".timeline-wrapper")[0].scrollWidth,l=i.find(".timeline-body").scrollLeft(),o=0;return r>n&&(o=(o=l/n>1?l-n:l-(r-n)/Number(a.timeline.attr("range")))<0?0:o,i.find(".timeline-body").animate({scrollLeft:o},300)),this},dateforth:function(t){t.preventDefault();var i=e(this).parents(".timeline-container"),a=i.data("timeline"),n=i.find(".timeline-body")[0].clientWidth,r=i.find(".timeline-wrapper")[0].scrollWidth,l=i.find(".timeline-body").scrollLeft(),o=0;return r>n&&(o=(o=(r-l)/n>1?l+n:l+(r-n)/Number(a.timeline.attr("range")))>r-n+1?r-n+1:o,i.find(".timeline-body").animate({scrollLeft:o},300)),this},alignment:function(){var t=arguments.length>1?Array.prototype.slice.call(arguments,1):[arguments[0]],i=t[0].toLowerCase(),a=void 0!==t[1]?String(t[1]).toLowerCase():0,n=e(this).find(".timeline-body")[0].clientWidth,r=e(this).find(".timeline-wrapper")[0].scrollWidth,l=0;if(r>n){switch(i){case"left":l=0;break;case"right":l=r-n+1;break;case"center":l=(r-n)/2;break;case"current":l=(h=m(o(!0),u=e(this).data("timeline")))>-1?h-n/2>r-n+1?r-n+1:h-n/2:r-n+1;break;case"latest":var s,d,c,h,u=e(this).data("timeline"),p=new Function("return "+u.timeline.text())();e.each(p,function(e,t){d=f("U",t.start),0==e?(s=d,c=e):d>=s&&(s=d,c=e)}),l=(h=m(new Date(p[c].start),u))>-1?h-n/2>r-n+1?r-n+1:h-n/2:r-n+1;break;default:l=0;var g="#"+i;e(g).length&&(l=(h=e(g).position().left)-n/2>r-n+1?r-n+1:h-n/2)}-1!=e.inArray(a,["slow","normal","fast"])||Number(a)>0?e(this).find(".timeline-body").animate({scrollLeft:l},a):e(this).find(".timeline-body").scrollLeft(l)}return this},getOptions:function(){var t=e(this).data("timeline");return{title:t.timeline.attr("title"),type:t.timeline.attr("type"),scale:t.timeline.attr("scale"),startDatetime:t.timeline.attr("start-datetime"),datetimePrefix:t.timeline.attr("datetime-prefix"),showHeadline:1==Number(t.timeline.attr("show-headline")),datetimeFormat:{full:t.timeline.attr("datetime-format-full"),year:t.timeline.attr("datetime-format-year"),month:t.timeline.attr("datetime-format-month"),day:t.timeline.attr("datetime-format-day")},minuteInterval:Number(t.timeline.attr("minute-interval")),zerofillYear:1==Number(t.timeline.attr("zerofill-year")),range:Number(t.timeline.attr("range")),rows:Number(t.timeline.attr("rows")),height:"auto"===t.timeline.attr("timeline-height")?"auto":Number(t.timeline.attr("timeline-height")),minGridPer:Number(t.timeline.attr("min-grid-per")),minGridSize:Number(t.timeline.attr("min-grid-size")),rangeAlign:t.timeline.attr("range-align"),naviIcon:{left:t.timeline.attr("navi-icon-left"),right:t.timeline.attr("navi-icon-right")},showPointer:t.timeline.attr("show-pointer"),events:new Function("return "+t.timeline.text())()}},addEvent:function(t,i){return this.each(function(){var a=e(this),r=a.data("timeline"),l=new Function("return "+r.timeline.text())(),o=1,s=[o];t.length>0&&(e.each(l,function(e,t){s.push(Number(t.eventId))}),o=Math.max.apply(null,s)+1,e.each(t,function(e,t){t.eventId=o,o++,l.push(t)}),r.timeline.text(JSON.stringify(l))),n(a),e(this).trigger("align.timeline",["evt-"+(o-1),"fast"]),r&&"function"==typeof i&&(console.info('Fired "addEvent" method after events addition.'),i(a,r))})},removeEvent:function(){var t,i;return 0==arguments.length?(t="all",i=null):1==arguments.length?"function"==typeof arguments[0]?(t="all",i=arguments[0]):(t=arguments[0],i=null):(t=arguments[0],i=arguments[1]),this.each(function(){var a=e(this),r=a.data("timeline"),l=new Function("return "+r.timeline.text())();if("all"===t)l=[];else{var o=[];e.each(l,function(i,a){-1==e.inArray(a.eventId,t)&&o.push(a)}),l=o}r.timeline.text(JSON.stringify(l)),n(a),r&&"function"==typeof i&&(console.info('Fired "removeEvent" method after events removing.'),i(a,r))})},updateEvent:function(t,i){return void 0!==t&&this.each(function(){var a,r=e(this),l=r.data("timeline"),o=new Function("return "+l.timeline.text())(),s=[];t.length>0&&e.each(t,function(e,t){s.push(t.eventId)}),o.length>0&&s.length>0&&(e.each(o,function(i,n){if(-1!=e.inArray(n.eventId,s)){var r;e.each(t,function(e,t){if(t.eventId==n.eventId)return r=t,a=t.eventId,!1}),o[i]=r}}),l.timeline.text(JSON.stringify(o))),n(r),e(this).trigger("align.timeline",["evt-"+a,"fast"]),l&&"function"==typeof i&&(console.info('Fired "updateEvent" method after events updating.'),i(r,l))})},openEvent:function(t){var i=Number(e(t.target).attr("id").replace("evt-","")),a=t.delegateTarget;return""!==i&&0!=i&&e(a).each(function(){var t,a=e(this).data("timeline"),n=new Function("return "+a.timeline.text())();e.each(n,function(e,a){if(a.eventId==i)return t=a,!1}),e(this).find(".timeline-node").each(function(){e(this).attr("id")==="evt-"+i?e(this).addClass("active"):e(this).removeClass("active")}),e(this).trigger("align.timeline",["evt-"+i,"fast"]),l(t)&&t.callback&&(console.info('Fired "openEvent" method after event shown.'),Function.call(null,"return "+t.callback)())})}};e.fn.timeline=function(t){return v[t]?v[t].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof t&&t?void e.error("Method "+t+" does not exist on jQuery.timeline."):v.init.apply(this,arguments)};var b=function(){return e.ajax({type:"GET"}).done(function(t,i,a){e("body").data("serverDate",new Date(a.getResponseHeader("Date")))}).promise()}}(jQuery);
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000000000000000000000000000000000000..29d90419e620cc393c51e0922ca8743640af4187
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,52 @@
+var gulp = require('gulp');
+var sass = require('gulp-sass');
+var autoprefixer = require('gulp-autoprefixer');
+var cleanCSS = require('gulp-clean-css');
+var eslint = require('gulp-eslint');
+var uglify = require('gulp-uglify');
+var rename = require('gulp-rename');
+var gutil = require('gulp-util');
+var browserSync = require('browser-sync').create();
+
+gulp.task('browser-sync', function() {
+  browserSync.init({
+    server: './'
+  });
+});
+
+gulp.task('styles', function() {
+  return gulp.src('src/**/*.scss')
+    .pipe(sass())
+    .pipe(autoprefixer())
+    .pipe(cleanCSS({compatibility: 'ie8'}))
+    .pipe(rename({extname: '.min.css'}))
+    .pipe(gulp.dest('./dist'))
+    .pipe(browserSync.stream());
+});
+
+gulp.task('scripts', function() {
+  return gulp.src('src/timeline.js')
+    .pipe(uglify())
+    .on('error', function (err) { gutil.log(gutil.colors.red('[Error]'), err.toString()); })
+    .pipe(rename({extname: '.min.js'}))
+    .pipe(gulp.dest('./dist'))
+    .pipe(browserSync.stream());
+});
+
+gulp.task('eslint', function() {
+  return gulp.src('src/timeline.js')
+    .pipe(eslint({useEslintrc: true}))
+    .pipe(eslint.format())
+    .pipe(eslint.failAfterError());
+    //.pipe(gulp.dest('./dist'))
+    //.pipe(browserSync.stream());
+});
+
+gulp.task('default', function() {
+  browserSync.init({
+    server: './'
+  });
+  gulp.watch('src/timeline.js',['eslint','scripts']);
+  gulp.watch('src/**/*.scss',['styles']);
+});
+
diff --git a/index.html b/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..ea1b276a5f996bcae130f319a61e39ac1c88f7fc
--- /dev/null
+++ b/index.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <title>TimeLine</title>
+  <!-- Tell the browser to be responsive to screen width -->
+  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
+  <!-- Bootstrap 4.0.0-alpha.6 -->
+  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
+  <!-- Ionicons 2.0.1 -->
+  <link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
+  <!-- Font Awesome latest -->
+  <script src="http://email.tl.fortawesome.com/c/eJxNjUEOwiAQRU9TlmQYaIcuWKhJ70E7g1XbYgrG68vS5Oct3uJ9DiwDC6lHQDAEiGQsut5qgw5Grw0QeX2d7NSPdOsc1E2nfNb4lZJ30Uve1RokQYQEJrJ1kmZKHJ3zwzAubkHPRm1hrfVdOnvpcGr7FGmZ4z_T7OwZPfJsUD-LOsMrYnts1Pm8_wAiUTJN"></script>
+  <!-- Timeline style -->
+  <link rel="stylesheet" href="./dist/timeline.min.css?">
+
+  <!-- HTML5 ShimとRespond.js IE8のHTML5要素とメディアクエリのサポート -->
+  <!-- 警告:Respond.jsは、file:// 経由でページを表示しても機能しません -->
+  <!--[if lt IE 9]>
+  <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
+  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+  <![endif]-->
+</head>
+<body>
+<div class="wrapper">
+
+  <!-- コンテンツ・ラッパー。ページコンテンツを含む -->
+  <div class="content-wrapper">
+    <!-- コンテンツ・ヘッダ (ページ・ヘッダ) -->
+    <section class="content-header">
+      <h1>
+        404 Not Found
+        <small>ページが見つかりません</small>
+      </h1>
+      <ol class="breadcrumb">
+        <li><a href="#"><i class="fa fa-dashboard"></i> 管理TOP</a></li>
+        <li class="active">404</li>
+      </ol>
+    </section>
+
+    <!-- メイン・コンテンツ -->
+    <section class="content">
+
+      <!-- Your Page Content Here -->
+
+    </section>
+    <!-- /.content -->
+  </div>
+  <!-- /.content-wrapper -->
+
+
+</div>
+<!-- ./wrapper -->
+
+<!-- REQUIRED JS SCRIPTS -->
+
+<!-- jQuery 3.1.1 -->
+<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+<!-- tether 1.4.0 -->
+<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" crossorigin="anonymous"></script>
+<!-- Bootstrap 4.0.0-alpha.6 -->
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
+<!-- Main script -->
+<script src="./dist/timeline.min.js?"></script>
+</body>
+</html>
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d484b5604d8133dbc2daf72433a9da49f61700b1
--- /dev/null
+++ b/package.json
@@ -0,0 +1,38 @@
+{
+  "name": "jquery.timeline",
+  "version": "1.0.0",
+  "description": "Horizontal Timeline plugin for jQuery",
+  "main": "gulpfile.js",
+  "dependencies": {
+    "gulp-sass": "^3.1.0"
+  },
+  "devDependencies": {
+    "browser-sync": "^2.18.12",
+    "gulp": "^3.9.1",
+    "gulp-autoprefixer": "^4.0.0",
+    "gulp-clean-css": "^3.4.0",
+    "gulp-eslint": "^3.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-sass": "^3.1.0",
+    "gulp-uglify": "^3.0.0",
+    "gulp-util": "^3.0.8"
+  },
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/ka215/jquery.timeline.git"
+  },
+  "keywords": [
+    "jquery",
+    "timeline",
+    "plugin"
+  ],
+  "author": "ka2",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/ka215/jquery.timeline/issues"
+  },
+  "homepage": "https://github.com/ka215/jquery.timeline#readme"
+}
diff --git a/src/timeline.js b/src/timeline.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad0994acfb8458217f00321a804ba2e26132ccef
--- /dev/null
+++ b/src/timeline.js
@@ -0,0 +1,1660 @@
+/*!
+ * JQuery Timeline Plugin Scripts
+ * ------------------------
+ * Version: 1.0.0
+ * Coded by: Ka2 (https://ka2.org/)
+ * Lisenced: MIT
+ */
+(function( $ ) {
+
+  // Constant values
+  var pluginName   = 'jQuery.Timeline',
+      rowH         = 40,
+      pointMargin  = 2,
+      tlEventAreaH = 0;
+
+  if ( 'global' in $.timeline && typeof $.timeline.global === 'object' && $.timeline.global.rowH !== undefined ) {
+    rowH = Number( $.timeline.global.rowH );
+  }
+
+  var methods = {
+    init : function( options ) {
+      
+      // Default settings
+      var settings = $.extend( {
+        type            : "bar", // View type of timeline event is either "bar" or "point"
+        scale           : "days", // Timetable's top level scale is either "years" or "months" or "days"
+        startDatetime   : "currently", // Default set datetime as viewing timetable; format is ( "^[-+]d{4}(/|-)d{2}(/|-)d{2}\sd{2}:d{2}:d{2}$" ) or "currently"
+//        timelineRange   : { // Begin Datetime and Final Datetime; format is ( "^[-+]d{4}(/|-)d{2}(/|-)d{2}\sd{2}:d{2}:d{2}$" )
+//          from          : "1-01-01 00:00:00",
+//          to            : "9999-12-31 23:59:59"
+//        },
+        datetimePrefix  : "", // The prefix of the date and time notation displayed in the headline
+        showHeadline    : true, // Whether to display headline
+        datetimeFormat  : {
+          full          : "Y/m/d",
+          year          : "Y",
+          month         : "n", // or "F" etc.
+          day           : "n/j" // or "j" etc.
+        },
+        minuteInterval  : 30, // Recommend more than 5 minutes; only if top scale is "days" ; Deprecated
+        zerofillYear    : false, // It's outputted at the "0099" if true, the "99" if false
+        range           : 3, // The default view range of the timetable starting from the `startDatetime`
+        rows            : 5, // Rows of timeline event area
+        height          : "auto", // Fixed height (pixel) of timeline event area; default "auto" is (rows * 40)px
+        minGridPer      : 2, // Minimum grid per
+        minGridSize     : 30, // Minimum size (pixel) of timeline grid; It needs 5 pixels or more
+        rangeAlign      : "current", // Possible values are "left", "center", "right", "current", "latest" and specific event id
+        naviIcon        : { // Define class name
+          left          : "jqtl-circle-left",
+          right         : "jqtl-circle-right"
+        },
+        showPointer     : true
+      }, options);
+      
+      // initialize plugin
+      return this.each(function(){
+        
+        var $this = $(this),
+            data = $this.data('timeline'),
+            timeline = $('<div />', {
+              "title"                 : $this.find('.timeline-headline').text(),
+              "type"                  : settings.type,
+              "scale"                 : settings.scale,
+              "start-datetime"        : settings.startDatetime,
+//              "timeline-range-from"   : settings.timelineRange.from,
+//              "timeline-range-to"     : settings.timelineRange.to,
+              "datetime-prefix"       : settings.datetimePrefix,
+              "show-headline"         : settings.showHeadline ? 1 : 0,
+              "datetime-format-full"  : settings.datetimeFormat.full,
+              "datetime-format-year"  : settings.datetimeFormat.year,
+              "datetime-format-month" : settings.datetimeFormat.month,
+              "datetime-format-day"   : settings.datetimeFormat.day,
+              "minute-interval"       : settings.minuteInterval,
+              "zerofill-year"         : settings.zerofillYear ? 1 : 0,
+              "range"                 : settings.range,
+              "rows"                  : settings.rows,
+              "timeline-height"       : settings.height,
+              "min-grid-per"          : settings.minGridPer,
+              "min-grid-size"         : settings.minGridSize,
+              "range-align"           : settings.rangeAlign,
+              "navi-icon-left"        : settings.naviIcon.left,
+              "navi-icon-right"       : settings.naviIcon.right,
+              "show-pointer"          : settings.showPointer ? 1 : 0,
+              "text"                  : ""
+          });
+        
+        // Set Events
+        //$(window).on( 'resize.timeline', methods.render );
+        $this.on( 'click.timeline', '.timeline-to-prev', methods.dateback );
+        $this.on( 'click.timeline', '.timeline-to-next', methods.dateforth );
+        $this.on( 'click.timeline', '.timeline-node', methods.openEvent );
+        $this.on( 'align.timeline', methods.alignment );
+        
+        // If uninitialized yet
+        if ( ! data ) {
+          
+          $this.data('timeline', {
+            target: $this,
+            timeline : timeline
+          });
+          
+          // Retrive Current Date
+          var currentDt, currentDate, _tmp, _regx;
+          if ( settings.startDatetime === 'currently' ) {
+            currentDt = setCurrentDate( true );
+          } else {
+            currentDt = new Date( settings.startDatetime );
+            _regx = /-|\//;
+            _tmp = settings.startDatetime.split( _regx );
+            if ( Number( _tmp[0] ) < 100 ) {
+              // for 0 - 99 years map
+              currentDt.setFullYear( Number( _tmp[0] ) );
+            }
+          }
+          switch( settings.scale ) {
+            case 'years':
+              currentDate = currentDt.getFullYear() +'-01-01 00:00:00';
+              break;
+            case 'months':
+              currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-01 00:00:00';
+              break;
+            case 'days':
+              currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' 00:00:00';
+              break;
+            default:
+              currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' '+ currentDate.getHours() +':00:00';
+          }
+console.info( currentDt, currentDate );
+          $this.data('timeline').timeline.attr( 'actual-start-datetime', currentDate );
+        
+          renderTimeline( $this );
+          
+          // timeline container sizing
+          resizeTimeline( $this );
+          
+          // do methods.alignment
+          $this.trigger( 'align.timeline', [ settings.rangeAlign ] );
+          
+          $this.css('visibility','visible');
+          
+        }
+        
+// for debug
+        var wait = 0,
+            sleep = setInterval(function() {
+              wait++;
+              if ( wait == 1 ) {
+                placeEvents( $this );
+                clearInterval( sleep );
+              }
+            }, 300);
+        //placeEvents( $this );
+        
+      });
+      
+    },
+    destroy : function( ) {
+      // destroy object
+      return this.each(function(){
+        var $this = $(this),
+          data = $this.data('timeline');
+        
+        $(window).off('.timeline');
+        if ( data ) {
+          data.timeline.remove();
+          $this.removeData('timeline');
+        }
+        
+      });
+    },
+    render : function( options ) {
+      // render timeline object
+      return this.each(function(){
+        var $this = $(this),
+            data = $this.data('timeline');
+        
+        // update options
+        if ( 'type' in options ) {
+          data.timeline.attr( 'type', options.type );
+        }
+        if ( 'scale' in options ) {
+          data.timeline.attr( 'scale', options.scale );
+        }
+        if ( 'startDatetime' in options ) {
+          data.timeline.attr( 'start-datetime', options.startDatetime );
+        }
+/*
+        if ( 'timelineRange' in options ) {
+          if ( typeof options.timelineRange.from != undefined ) {
+            data.timeline.attr( 'timeline-range-from', options.timelineRange.from );
+          }
+          if ( typeof options.timelineRange.to != undefined ) {
+            data.timeline.attr( 'timeline-range-to', options.timelineRange.to );
+          }
+        }
+*/
+        if ( 'datetimePrefix' in options ) {
+          data.timeline.attr( 'datetime-prefix', options.datetimePrefix );
+        }
+        if ( 'showHeadline' in options ) {
+          data.timeline.attr( 'show-headline', options.showHeadline ? 1 : 0 );
+        }
+        if ( 'datetimeFormat' in options ) {
+          if ( typeof options.datetimeFormat.full != undefined ) {
+            data.timeline.attr( 'datetime-format-full', options.datetimeFormat.full );
+          }
+          if ( typeof options.datetimeFormat.year != undefined ) {
+            data.timeline.attr( 'datetime-format-year', options.datetimeFormat.year );
+          }
+          if ( typeof options.datetimeFormat.day != undefined ) {
+            data.timeline.attr( 'datetime-format-day', options.datetimeFormat.day );
+          }
+        }
+        if ( 'minuteInterval' in options ) {
+          data.timeline.attr( 'minute-interval', options.minuteInterval );
+        }
+        if ( 'zerofillYear' in options ) {
+          data.timeline.attr( 'zerofill-year', options.zerofillYear ? 1 : 0 );
+        }
+        if ( 'range' in options ) {
+          data.timeline.attr( 'range', options.range );
+        }
+        if ( 'rows' in options ) {
+          data.timeline.attr( 'rows', options.rows );
+        }
+        if ( 'height' in options ) {
+          data.timeline.attr( 'timeline-height', options.height );
+        }
+        if ( 'minGridPer' in options ) {
+          data.timeline.attr( 'min-grid-per', options.minGridPer );
+        }
+        if ( 'minGridSize' in options ) {
+          data.timeline.attr( 'min-grid-size', options.minGridSize );
+        }
+        if ( 'rangeAlign' in options ) {
+          data.timeline.attr( 'range-align', options.rangeAlign );
+        }
+        if ( 'naviIcon' in options ) {
+          if ( typeof options.naviIcon.left != undefined ) {
+            data.timeline.attr( 'navi-icon-left', options.naviIcon.left );
+          }
+          if ( typeof options.naviIcon.right != undefined ) {
+            data.timeline.attr( 'navi-icon-right', options.naviIcon.right );
+          }
+        }
+        if ( 'showPointer' in options ) {
+          data.timeline.attr( 'show-pointer', options.showPointer ? 1 : 0 );
+        }
+
+        // Retrive current Date
+        var currentDt, currentDate, _tmp, _regx;
+        if ( data.timeline.attr('start-datetime') === 'currently' ) {
+          currentDt = setCurrentDate( true );
+        } else {
+          currentDt = new Date( data.timeline.attr('start-datetime') );
+          _regx = /-|\//;
+          _tmp = data.timeline.attr('start-datetime').split( _regx );
+          if ( Number( _tmp[0] ) < 100 ) {
+            // for 0 - 99 years map
+            currentDt.setFullYear( Number( _tmp[0] ) );
+          }
+        }
+        switch( data.timeline.attr('scale') ) {
+          case 'years':
+            currentDate = currentDt.getFullYear() +'-01-01 00:00:00';
+            break;
+          case 'months':
+            currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-01 00:00:00';
+            break;
+          case 'days':
+            currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' 00:00:00';
+            break;
+          default:
+            currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' '+ currentDate.getHours() +':00:00';
+        }
+        data.timeline.attr( 'actual-start-datetime', currentDate );
+
+console.info( 'Fired "render" method', options, data.timeline );
+        $this.find('.timeline-container').empty().removeClass('timeline-container');
+        renderTimeline( $this );
+        resizeTimeline( $this );
+        placeEvents( $this );
+        
+        // do methods.alignment
+        $this.trigger( 'align.timeline', [ data.timeline.attr('range-align') ] );
+      });
+    },
+    show : function( ) {
+      return this.each(function(){
+        $(this).css('display', 'block').css('visibility', 'visible');
+      });
+    },
+    hide : function( ) {
+      return this.each(function(){
+        $(this).css('visibility', 'hidden').css('display', 'none');
+      });
+    },
+    initialized : function( callback ) {
+      return this.each(function(){
+        var $this = $(this),
+          data = $this.data('timeline');
+        
+        if ( data && typeof callback === 'function' ) {
+          console.info( 'Fired "initialized" method after initialize this plugin.' );
+          callback( $this, data );
+        }
+      });
+    },
+    dateback  : function( evt ) {
+//console.info([ 'Fired "dateback" method', this, evt ]);
+      evt.preventDefault();
+      var $root = $(this).parents('.timeline-container'),
+          data = $root.data('timeline'),
+          visibleTimelineWidth = $root.find('.timeline-body')[0].clientWidth,
+          fullTimelineWidth = $root.find('.timeline-wrapper')[0].scrollWidth,
+          currentTimelinePos = $root.find('.timeline-body').scrollLeft(),
+          mov = 0;
+      if ( fullTimelineWidth > visibleTimelineWidth ) {
+//console.info([ fullTimelineWidth / visibleTimelineWidth, currentTimelinePos, fullTimelineWidth - currentTimelinePos, (currentTimelinePos / visibleTimelineWidth) ]);
+        if ( (currentTimelinePos / visibleTimelineWidth) > 1 ) {
+          mov = currentTimelinePos - visibleTimelineWidth;
+        } else {
+          mov = currentTimelinePos - ((fullTimelineWidth - visibleTimelineWidth) / Number( data.timeline.attr('range') ));
+        }
+        mov = mov < 0 ? 0 : mov;
+        $root.find('.timeline-body').animate( { scrollLeft: mov }, 300 );
+      }
+      return this;
+    },
+    dateforth : function( evt ) {
+//console.info([ 'Fired "dateforth" method', this, evt ]);
+      evt.preventDefault();
+      var $root = $(this).parents('.timeline-container'),
+          data = $root.data('timeline'),
+          visibleTimelineWidth = $root.find('.timeline-body')[0].clientWidth,
+          fullTimelineWidth = $root.find('.timeline-wrapper')[0].scrollWidth,
+          currentTimelinePos = $root.find('.timeline-body').scrollLeft(),
+          mov = 0;
+      if ( fullTimelineWidth > visibleTimelineWidth ) {
+        if ( (fullTimelineWidth - currentTimelinePos) / visibleTimelineWidth > 1 ) {
+          mov = currentTimelinePos + visibleTimelineWidth;
+        } else {
+          mov = currentTimelinePos + ((fullTimelineWidth - visibleTimelineWidth) / Number( data.timeline.attr('range') ));
+        }
+        mov = mov > (fullTimelineWidth - visibleTimelineWidth + 1) ? fullTimelineWidth - visibleTimelineWidth + 1 : mov;
+        $root.find('.timeline-body').animate( { scrollLeft: mov }, 300 );
+      }
+      return this;
+    },
+    alignment : function( ) {
+      var args = arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [ arguments[0] ],
+          control = args[0].toLowerCase(),
+          animateSpeed = typeof args[1] !== 'undefined' ? String( args[1] ).toLowerCase() : 0;
+//console.info([ 'Fired "alignment" method', this, control, animateSpeed ]);
+      var visibleTimelineWidth = $(this).find('.timeline-body')[0].clientWidth, // 表示域
+          fullTimelineWidth = $(this).find('.timeline-wrapper')[0].scrollWidth, // 全長
+          mov = 0; // 初期位置(= left)
+      if ( fullTimelineWidth > visibleTimelineWidth ) { // 表示域より全長が大きい場合(横スクロールが発生する場合)
+        switch ( control ) {
+          case "left":
+            // Move to beginning of timetable range
+            mov = 0;
+            break;
+          case "right":
+            // Move to last of timetable range
+            mov = fullTimelineWidth - visibleTimelineWidth + 1;
+            break;
+          case "center":
+            // Move to central of timetable range
+            mov = (fullTimelineWidth - visibleTimelineWidth) / 2;
+            break;
+          case "current":
+            // Move to nearest current time on timetable (default)
+            var currentDt = setCurrentDate( true ),
+                data      = $(this).data('timeline'),
+                posX      = getAbscissa( currentDt, data );
+            if ( posX > -1 ) {
+              if ( (posX - visibleTimelineWidth / 2) > (fullTimelineWidth - visibleTimelineWidth + 1) ) {
+                mov = fullTimelineWidth - visibleTimelineWidth + 1;
+              } else {
+                mov = posX - visibleTimelineWidth / 2;
+              }
+            } else {
+              mov = fullTimelineWidth - visibleTimelineWidth + 1;
+            }
+            break;
+          case "latest":
+            // Move to latest event on the timetable
+            var data        = $(this).data('timeline'),
+                eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+                diffDt, cur, latestKey, latestDt, posX;
+            $.each( eventNodes, function( i, evt ) {
+              cur = formatDate( 'U', evt.start );
+              if ( i == 0 ) {
+                diffDt = cur;
+                latestKey = i;
+              } else {
+                if ( cur >= diffDt ) {
+                  diffDt = cur;
+                  latestKey = i;
+                }
+              }
+            });
+//console.info([ latestKey, eventNodes[latestKey] ]);
+            latestDt = new Date( eventNodes[latestKey].start ),
+            posX     = getAbscissa( latestDt, data );
+            if ( posX > -1 ) {
+              if ( (posX - visibleTimelineWidth / 2) > (fullTimelineWidth - visibleTimelineWidth + 1) ) {
+                mov = fullTimelineWidth - visibleTimelineWidth + 1;
+              } else {
+                mov = posX - visibleTimelineWidth / 2;
+              }
+            } else {
+              mov = fullTimelineWidth - visibleTimelineWidth + 1;
+            }
+            break;
+          default:
+            // Move to specific event that has targeted id
+            mov = 0;
+            var targetId = '#' + control;
+            if ( $(targetId).length ) {
+              var posX = $(targetId).position().left;
+              if ( (posX - visibleTimelineWidth / 2) > (fullTimelineWidth - visibleTimelineWidth + 1) ) {
+                mov = fullTimelineWidth - visibleTimelineWidth + 1;
+              } else {
+                mov = posX - visibleTimelineWidth / 2;
+              }
+            }
+            break;
+        }
+        if ( $.inArray( animateSpeed, [ "slow", 'normal', 'fast' ] ) != -1 || Number( animateSpeed ) > 0 ) {
+          $(this).find('.timeline-body').animate({ scrollLeft: mov }, animateSpeed);
+        } else {
+          $(this).find('.timeline-body').scrollLeft( mov );
+        }
+      }
+      return this;
+    },
+    getOptions : function( ) {
+      var $this = $(this),
+          data  = $this.data('timeline');
+      return {
+        title          : data.timeline.attr('title'),
+        type           : data.timeline.attr('type'),
+        scale          : data.timeline.attr('scale'),
+        startDatetime  : data.timeline.attr('start-datetime'),
+/*
+        timelineRange  : {
+          from         : data.timeline.attr('timeline-range-from'),
+          to           : data.timeline.attr('timeline-range-to'),
+        },
+*/
+        datetimePrefix : data.timeline.attr('datetime-prefix'),
+        showHeadline   : Number( data.timeline.attr('show-headline') ) == 1 ? true : false,
+        datetimeFormat : {
+          full         : data.timeline.attr('datetime-format-full'),
+          year         : data.timeline.attr('datetime-format-year'),
+          month        : data.timeline.attr('datetime-format-month'),
+          day          : data.timeline.attr('datetime-format-day'),
+        },
+        minuteInterval : Number( data.timeline.attr('minute-interval') ),
+        zerofillYear   : Number( data.timeline.attr('zerofill-year') ) == 1 ? true : false,
+        range          : Number( data.timeline.attr('range') ),
+        rows           : Number( data.timeline.attr('rows') ),
+        height         : data.timeline.attr('timeline-height') === 'auto' ? 'auto' : Number( data.timeline.attr('timeline-height') ),
+        minGridPer     : Number( data.timeline.attr('min-grid-per') ),
+        minGridSize    : Number( data.timeline.attr('min-grid-size') ),
+        rangeAlign     : data.timeline.attr('range-align'),
+        naviIcon       : {
+          left         : data.timeline.attr('navi-icon-left'),
+          right        : data.timeline.attr('navi-icon-right'),
+        },
+        showPointer    : data.timeline.attr('show-pointer'),
+        events         : ( new Function( 'return ' + data.timeline.text() ) )()
+      };
+    },
+    addEvent : function( events, callback ) {
+      return this.each(function(){
+        var $this       = $(this),
+            data        = $this.data('timeline'),
+            eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+            incrementId = 1,
+            _ids        = [ incrementId ];
+        // add events
+        if ( events.length > 0 ) {
+          $.each(eventNodes, function( i, evt ) {
+            _ids.push( Number( evt.eventId ) );
+          });
+          incrementId = Math.max.apply( null, _ids ) + 1;
+          $.each(events, function( i, evt ) {
+            evt['eventId'] = incrementId;
+            incrementId++;
+            eventNodes.push(evt);
+          });
+          data.timeline.text( JSON.stringify( eventNodes ) );
+        }
+        
+        placeEvents( $this );
+        
+        // Alignment to current node
+        $(this).trigger( 'align.timeline', [ 'evt-' + (incrementId - 1), 'fast' ] );
+        
+        if ( data && typeof callback === 'function' ) {
+          console.info( 'Fired "addEvent" method after events addition.' );
+          callback( $this, data );
+        }
+      });
+    },
+    removeEvent : function( ) { // arguments is optional
+      var eventIds, callback;
+      if ( arguments.length == 0 ) {
+        eventIds = 'all';
+        callback = null;
+      } else
+      if ( arguments.length == 1 ) {
+        if ( typeof arguments[0] === 'function' ) {
+          eventIds = 'all';
+          callback = arguments[0];
+        } else {
+          eventIds = arguments[0];
+          callback = null;
+        }
+      } else {
+        eventIds = arguments[0];
+        callback = arguments[1];
+      }
+      return this.each(function(){
+        var $this       = $(this),
+            data        = $this.data('timeline'),
+            eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )();
+        
+        // remove events
+        if ( eventIds === 'all' ) {
+          eventNodes = [];
+        } else {
+          var newEventNodes = [];
+          $.each(eventNodes, function( i, evt ) {
+            if ( $.inArray( evt.eventId, eventIds ) == -1 ) {
+              newEventNodes.push(evt);
+            }
+          });
+          eventNodes = newEventNodes;
+        }
+        data.timeline.text( JSON.stringify( eventNodes ) );
+        
+        placeEvents( $this );
+        
+        if ( data && typeof callback === 'function' ) {
+          console.info( 'Fired "removeEvent" method after events removing.' );
+          callback( $this, data );
+        }
+      });
+    },
+    updateEvent : function( events, callback ) {
+      if ( typeof events === 'undefined' ) {
+        return false;
+      }
+      return this.each(function(){
+        var $this       = $(this),
+            data        = $this.data('timeline'),
+            eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+            _ids        = [],
+            lastUpdated;
+        // update events
+        if ( events.length > 0 ) {
+          $.each( events, function( i, newEvt ) {
+            _ids.push(newEvt.eventId);
+          });
+        }
+        
+        if ( eventNodes.length > 0 && _ids.length > 0 ) {
+          $.each( eventNodes, function( i, evt ) {
+            if ( $.inArray( evt.eventId, _ids ) != -1 ) {
+              var newEvent;
+              $.each( events, function( j, newEvt ) {
+                if ( newEvt.eventId == evt.eventId ) {
+                  newEvent = newEvt;
+                  lastUpdated = newEvt.eventId;
+                  return false;
+                }
+              });
+              eventNodes[i] = newEvent;
+            }
+          });
+          data.timeline.text( JSON.stringify( eventNodes ) );
+        }
+        
+        placeEvents( $this );
+        
+        // Alignment to current node
+        $(this).trigger( 'align.timeline', [ 'evt-' + lastUpdated, 'fast' ] );
+        
+        if ( data && typeof callback === 'function' ) {
+console.info( 'Fired "updateEvent" method after events updating.' );
+          callback( $this, data );
+        }
+      });
+    },
+    openEvent : function( event ) {
+      var eventId         = Number( $(event.target).attr('id').replace('evt-', '') ),
+          currentTimeline = event.delegateTarget;
+      if ( eventId === '' || eventId == 0 ) {
+        return false;
+      }
+      return $(currentTimeline).each(function(){
+        var data       = $(this).data('timeline'),
+            eventNodes = ( new Function( 'return ' + data.timeline.text() ) )(), eventData;
+        $.each( eventNodes, function( i, evt ) {
+          if ( evt.eventId == eventId ) {
+            eventData = evt;
+            return false;
+          }
+        });
+        
+        // Activate focused event
+        $(this).find('.timeline-node').each(function(){
+          if ( $(this).attr('id') === 'evt-' + eventId ) {
+            $(this).addClass('active');
+          } else {
+            $(this).removeClass('active');
+          }
+        });
+        
+        // Alignment to current node
+        $(this).trigger( 'align.timeline', [ 'evt-' + eventId, 'fast' ] );
+        
+        if ( showEvent( eventData ) && eventData.callback ) {
+console.info( 'Fired "openEvent" method after event shown.' );
+          Function.call( null, 'return ' + eventData.callback )();
+          //var callback = Function.call( null, 'return ' + eventData.callback )();
+          //callback.call( eventData );
+        }
+      });
+    }
+  };
+
+  $.fn.timeline = function( method ) {
+    // Dispatcher of Plugin
+    if ( methods[method] ) {
+      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+    } else 
+    if ( typeof method === 'object' || ! method ) {
+      return methods.init.apply( this, arguments );
+    } else {
+      $.error( 'Method ' + method + ' does not exist on jQuery.timeline.' );
+    }
+    
+  };
+
+  function renderTimeline( obj ) {
+    // Rendering timeline view
+    var $this = $(obj), i, _tmp, _regx, 
+        data = $this.data('timeline');
+//console.info([ 'Called "renderTimeline" function', $this, data.timeline ]);
+console.info( data.timeline[0].attributes );
+    
+    _regx = /-|\/|\s|\:/;
+    _tmp = data.timeline.attr('actual-start-datetime').split( _regx );
+    var startDt = new Date( Number( _tmp[0] ), Number( _tmp[1] ) - 1, Number( _tmp[2] ), Number( _tmp[3] ), Number( _tmp[4] ), Number( _tmp[5] ) );
+    if ( Number( _tmp[0] ) < 100 ) {
+      // for 0 - 99 years map
+      startDt.setFullYear( Number( _tmp[0] ) );
+    }
+    
+    var tlHeader = $('<div />', { addClass: "timeline-header" }),
+        tlBody   = $('<div />', { addClass: "timeline-body" }),
+        tlFooter = $('<div />', { addClass: "timeline-footer" }),
+        tlWrapper= $('<div />', { addClass: "timeline-wrapper" }),
+        tlScale  = $('<table />', { addClass: "timeline-timetable timeline-scale" }),
+        tlEvents = $('<div />', { addClass: "timeline-events" }),
+        tlGrids  = $('<table />', { addClass: "timeline-timetable timeline-grids" }),
+        tlPointer= $('<div />', { addClass: "timeline-needle-pointer" }),
+        dfEvents = $('<div />', { addClass: "timeline-events default-events" }),
+        endDt    = new Date( startDt ),
+        scaleSet = {
+          years  : {
+            "medium_scale": "months",
+            "medium_cols": 12,
+            "small_scale": "days",
+            "small_cols": Number( data.timeline.attr('min-grid-per') )
+          },
+          months : {
+            "medium_scale": "days",
+            "medium_cols": new Date( startDt.getFullYear(), startDt.getMonth() + 1, 0 ).getDate(),
+            "small_scale": "hours",
+            "small_cols": Number( data.timeline.attr('min-grid-per') )
+          },
+          days   : {
+            "medium_scale": "hours",
+            "medium_cols": 24,
+            "small_scale": "minutes",
+            "small_cols": Number( data.timeline.attr('min-grid-per') ) // retriveDaysGrid( data.timeline.attr('minute-interval'), data.timeline.attr('min-grid-per') )
+          }
+        },
+        topScale = data.timeline.attr('scale'),
+        midScale = scaleSet[topScale]['medium_scale'],
+        smlScale = scaleSet[topScale]['small_scale'],
+        mediumCellSize = Number( data.timeline.attr( 'min-grid-per' ) ) * Number( data.timeline.attr( 'min-grid-size' ) ),
+        scaleMediumCols = [ scaleSet[topScale]['medium_cols'] ],
+        scaleSmallCols;
+    
+//console.info([ scaleSet.years['small_cols'], scaleSet.months['small_cols'], scaleSet.days['small_cols'] ]);
+    // initialize element
+    if ( ! $this.hasClass('timeline-container') ) {
+      $this.addClass('timeline-container');
+    }
+    if ( $this.find('.timeline-events').length > 0 ) {
+      $this.find('.timeline-events').clone().appendTo( dfEvents );
+      defaultEvents( dfEvents, data );
+    }
+    if ( data.timeline.attr( 'type' ) === 'point' || data.timeline.attr( 'type' ) === 'mixed' ) {
+      var tlLineCanvas = $('<canvas />', { addClass: "timeline-line-canvas" });
+    }
+    $this.empty();
+    
+    // Set endDate
+    if ( data.timeline.attr('scale') === 'years' ) {
+      endDt = new Date( endDt.setFullYear( endDt.getFullYear() + Number( data.timeline.attr('range') ) - 1 ) );
+    } else
+    if ( data.timeline.attr('scale') === 'months' ) {
+      endDt = new Date( endDt.setMonth( endDt.getMonth() + Number( data.timeline.attr('range') ) - 1 ) );
+    } else {
+      endDt = new Date( endDt.setDate( endDt.getDate() + Number( data.timeline.attr('range') ) - 1 ) );
+    }
+//console.info([ startDt, endDt ]);
+    
+    // Set scaleMediumCols
+    if ( midScale === 'days' && Number( data.timeline.attr('range') ) > 1 ) {
+      for ( i = 1; i < Number( data.timeline.attr('range') ); i++ ) {
+         scaleMediumCols.push( new Date( startDt.getFullYear(), startDt.getMonth() + 1 + i, 0 ).getDate() );
+      }
+    } else {
+      for ( i = 1; i < Number( data.timeline.attr('range') ); i++ ) {
+        scaleMediumCols.push( scaleSet[topScale]['medium_cols'] );
+      }
+    }
+    
+    // Create header
+    if ( data.timeline.attr('show-headline') ) {
+      var fromDate, toDate, zf, zt, tlTitle;
+      switch( data.timeline.attr('scale') ) {
+        case "years":
+          zf = zt = '';
+          if ( data.timeline.attr('zerofill-year') == 1 ) {
+            if ( startDt.getFullYear() < 100 ) {
+              zf = '00';
+            } else
+            if ( startDt.getFullYear() < 1000 ) {
+              zf = '0';
+            }
+            if ( endDt.getFullYear() < 100 ) {
+              zt = '00';
+            } else
+            if ( endDt.getFullYear() < 1000 ) {
+              zt = '0';
+            }
+          }
+          fromDate = data.timeline.attr('datetime-prefix') + zf + formatDate( data.timeline.attr('datetime-format-year'), startDt );
+          toDate   = data.timeline.attr('datetime-prefix') + zt + formatDate( data.timeline.attr('datetime-format-year'), endDt );
+          break;
+        case "months":
+          fromDate = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-year') + data.timeline.attr('datetime-format-month'), startDt );
+          toDate   = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-year') + data.timeline.attr('datetime-format-month'), endDt );
+          break;
+        case "days":
+          fromDate = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-full'), startDt );
+          toDate   = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-full'), endDt );
+          break;
+      }
+      tlTitle = '<span class="timeline-from-date">' + fromDate + '</span><span class="timeline-to-date">' + toDate + '</span>';
+      tlHeader.append('<h3 class="timeline-headline">' + tlTitle + '</h3>');
+    }
+    
+    // Create Time Scale
+    var topLevelRow = mediumLevelRow = smallLevelRow = '<tr>',
+        scaleSmallCols = array_sum( scaleMediumCols ) * scaleSet[topScale]['small_cols'],
+        tmpDate, resMod, label;
+    
+    // Stored total cols
+    data.timeline.attr( 'total-cols', scaleSmallCols );
+    
+    // Row of top level time scale
+    for ( i = 0; i < Number( data.timeline.attr('range') ); i++ ) {
+      topLevelRow += '<th colspan="' + ( scaleMediumCols[i] * scaleSet[topScale]['small_cols'] ) + '" class="scale-major scale-' + topScale + '">';
+      tmpDate = new Date( startDt );
+      switch ( topScale ) {
+        case 'years':
+          tmpDate.setFullYear( tmpDate.getFullYear() + i );
+          label = formatDate( data.timeline.attr('datetime-format-year'), tmpDate ); // tmpDate.getFullYear()
+          break;
+        case 'months':
+          tmpDate.setMonth( tmpDate.getMonth() + i );
+          label = formatDate( data.timeline.attr('datetime-format-month'), tmpDate ); // tmpDate.getFullYear() + '/' + ( tmpDate.getMonth() + 1 );
+          break;
+        case 'days':
+          tmpDate.setDate( tmpDate.getDate() + i );
+          label = formatDate( data.timeline.attr('datetime-format-day'), tmpDate ); // ( tmpDate.getMonth() + 1 ) + '/' + tmpDate.getDate();
+          break;
+      }
+      topLevelRow += label + '</th>';
+    }
+    topLevelRow += '</tr>';
+    
+    // Row of medium level time scale
+    for ( i = 0; i < array_sum( scaleMediumCols ); i++ ) {
+      mediumLevelRow += '<th colspan="' + scaleSet[topScale]['small_cols'] + '" class="scale-medium scale-' + midScale + '">';
+      tmpDate = new Date( startDt );
+      switch ( midScale ) {
+        case 'months':
+          resMod = i % scaleSet[topScale]['medium_cols'];
+          label = mediumCellSize < 18 ? '' : resMod + 1;
+          break;
+        case 'days':
+          tmpDate.setDate( tmpDate.getDate() + i );
+          label = mediumCellSize < 20 ? '' : tmpDate.getDate();
+          break;
+        case 'hours':
+          resMod = i % scaleSet[topScale]['medium_cols'];
+          label = mediumCellSize < 40 ? '' : resMod + ':00';
+          break;
+      }
+      mediumLevelRow += label + '</th>';
+    }
+    mediumLevelRow += '</tr>';
+    
+    // Row of small level time scale
+    for ( i = 0; i < scaleSmallCols; i++ ) {
+      smallLevelRow += '<th class="scale-small scale-' + smlScale + '"><span class="spacer-cell"></span></th>';
+    }
+    
+    // Create Timeline grids
+    var tlGridsRow = '<tr>';
+    for ( i = 0; i < scaleSmallCols; i++ ) {
+      tlGridsRow += '<td class="scale-small"><span class="spacer-cell"></span></td>';
+    }
+    tlGridsRow += '</tr>';
+    
+    // Create Timeline needle pointer
+    if ( data.timeline.attr( 'show-pointer' ) == 0 ) {
+      tlPointer.css('display', 'none');
+    } else {
+    	var currentDt = setCurrentDate( true ),
+    	    posX = getAbscissa( currentDt, data );
+    	if ( posX > -1 ) {
+        tlPointer.css('left', posX + 'px');
+      } else {
+        tlPointer.css('display', 'none');
+      }
+    }
+    
+    // Create Timeline loader & Timeline Events
+    var tlLoader = $('<div />', { addClass: "timeline-loader", css: { display: 'block' } });
+    tlLoader.append( '<i class="jqtl-spinner"></i><span class="sr-only">Loading...</span>' );
+    //tlEvents.append( tlLoader.prop('outerHTML') ).css('display','block');
+    
+    // Create Timeline footer
+    var tlFooterNav    = '<div class="timeline-nav">',
+        tlNavLeft      = data.timeline.attr( 'navi-icon-left' ) === '' ? 'jqtl-circle-left' : data.timeline.attr( 'navi-icon-left' ),
+        tlNavRight     = data.timeline.attr( 'navi-icon-right' ) === '' ? 'jqtl-circle-right' : data.timeline.attr( 'navi-icon-right' ),
+        tlNavPrevClass = /^jqtl-circle-.*$/.test( tlNavLeft ) ? 'timeline-to-prev-default' : 'timeline-to-prev-custom',
+        tlNavNextClass = /^jqtl-circle-.*$/.test( tlNavRight ) ? 'timeline-to-next-default' : 'timeline-to-next-custom';
+//console.info([ tlNavLeft, tlNavRight ]);
+    tlFooterNav += '<a href="javascript:void(0);" class="timeline-to-prev ' + tlNavPrevClass + '"><i class="' + tlNavLeft + '"></i></a>';
+    tlFooterNav += '<a href="javascript:void(0);" class="timeline-to-next ' + tlNavNextClass + '"><i class="' + tlNavRight + '"></i></a>';
+    tlFooterNav += '</div>';
+    
+    // Build Elements
+    tlScale.append( '<thead>' + topLevelRow + mediumLevelRow + smallLevelRow + '</thead>' );
+    tlGrids.append( '<tbody>' + tlGridsRow + '</tbody>' );
+    if ( data.timeline.attr( 'type' ) === 'point' || data.timeline.attr( 'type' ) === 'mixed' ) {
+      tlWrapper.append( tlScale.prop('outerHTML') + tlEvents.prop('outerHTML') + tlLineCanvas.prop('outerHTML') + tlGrids.prop('outerHTML') + tlPointer.prop('outerHTML') );
+    } else {
+      tlWrapper.append( tlScale.prop('outerHTML') + tlEvents.prop('outerHTML') + tlGrids.prop('outerHTML') + tlPointer.prop('outerHTML') );
+    }
+    tlBody.append( tlWrapper );
+    tlFooter.append( tlFooterNav );
+    
+    $this.append( tlHeader );
+    $this.append( tlBody );
+    $this.append( tlFooter );
+    $this.append( tlLoader.prop('outerHTML') );
+    
+    return $this;
+  }
+
+  function resizeTimeline( obj ) {
+    // Resizing timeline view
+    var $this = $(obj), i,
+        data = $this.data('timeline');
+
+    if ( data.timeline.attr('timeline-height') === "auto" || typeof data.timeline.attr('timeline-height') !== "number" ) {
+      tlEventAreaH = Number( data.timeline.attr('rows') ) * rowH;
+    } else {
+      tlEventAreaH = Number( data.timeline.attr('timeline-height') );
+    }
+    var timetableSize = {
+      width : $this.find('.timeline-timetable.timeline-scale').outerWidth(),
+      height: 63 // $this.find('.timeline-timetable.timeline-scale').outerHeight() だと正確な値が取れない(bootstrap利用だとOK)(なぜだ!?)
+    };
+    //console.info([ document.getElementsByClassName( 'timeline-scale' )[0].clientHeight, $(document).find('.timeline-timetable:first-child').height(), $this.find('.timeline-timetable:first-child').height(),$this.find('.timeline-timetable:first-child').innerHeight(),$this.find('.timeline-timetable:first-child').outerHeight(),$this.find('.timeline-timetable:first-child').outerHeight(true) ]);
+    //console.info([ timetableSize, $(this).find('.timeline-wrapper').height(), $(this).find('.spacer-cell').width() ]);
+    if ( $this.find('.timeline-wrapper')[0].offsetHeight != timetableSize.height + tlEventAreaH ) {
+      $this.find('.timeline-wrapper').css('height', (timetableSize.height + tlEventAreaH) + 'px');
+      $this.find('.timeline-events').css('height', tlEventAreaH + 'px');
+      $this.find('.timeline-line-canvas').css('height', tlEventAreaH + 'px').attr('width', timetableSize.width).attr('height', tlEventAreaH);
+      $this.find('.timeline-grids').css('height', tlEventAreaH + 'px');
+    }
+    data.timeline.attr('min-grid-size', Number( data.timeline.attr('min-grid-size') ) < 5 ? 30 : Number( data.timeline.attr('min-grid-size') ) );
+    if ( $this.find('.spacer-cell').width() != data.timeline.attr('min-grid-size') - 1 ) {
+      $this.find('.spacer-cell').css('width', (data.timeline.attr('min-grid-size') - 1) + 'px');
+    }
+    
+    // Adjust position of navi icons
+    var basePos     = ( $this.find('.timeline-body').outerHeight() - $this.find('.timeline-scale').outerHeight() ) / 2,
+        navIconH    = $this.find('.timeline-to-prev').outerHeight(),
+        navPosition = -1 * ( basePos + navIconH );
+    $this.find('.timeline-to-prev').css('top', navPosition + 'px');
+    $this.find('.timeline-to-next').css('top', navPosition + 'px');
+    
+    // Set event of scrolling timeline
+    $this.find('.timeline-body').scroll(function(){
+      var currentScrollLeft = $(this).scrollLeft();
+      if ( currentScrollLeft < 1 ) {
+        // Terminated Left
+        $this.find('.timeline-to-prev').hide();
+      } else
+      if ( currentScrollLeft >= (timetableSize.width - $(this).outerWidth() - 2) ) {
+        // Terminated Right
+        $this.find('.timeline-to-next').hide();
+      } else {
+        $this.find('.timeline-to-prev').show();
+        $this.find('.timeline-to-next').show();
+      }
+    });
+    
+    return $this;
+  }
+
+  function defaultEvents( obj, data ) {
+    // Defining default events
+    if ( $(obj).find('.timeline-events').children().length > 0 ) {
+      var eventData = [],
+          eventIds = [],
+          startEventId = 0;
+      $(obj).find('.timeline-events').children().each(function(){
+        if ( $(this).data('timelineNode') ) {
+          var event = ( new Function( 'return ' + $(this).data('timelineNode') ) )();
+          event['label'] = $(this).text();
+          if ( event.eventId ) 
+            eventIds.push( Number( event.eventId ) );
+          eventData.push( event );
+        }
+      });
+      if ( eventData.length > 0 ) {
+        startEventId = eventIds.length > 0 ? Math.max.apply( null, eventIds ) + 1 : startEventId;
+        eventData.forEach(function( evt, i, ary ) {
+          if ( ! evt.eventId ) {
+            ary[i]['eventId'] = startEventId;
+            startEventId++;
+          }
+        });
+        data.timeline.text( JSON.stringify( eventData ) );
+      }
+    }
+    return;
+  }
+
+  function placeEvents( obj ) {
+    // Placing all events
+    var $this       = $(obj),
+        data        = $this.data('timeline'),
+        eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+        //tlStartDt   = new Date( data.timeline.attr('start-datetime') === 'currently' ? data.timeline.attr('actual-start-datetime') : data.timeline.attr('start-datetime') ),
+        tlStartDt   = new Date( data.timeline.attr('actual-start-datetime') ),
+        tlEndDt     = new Date( tlStartDt ),
+        tlType      = data.timeline.attr('type'),
+        tlScale     = data.timeline.attr('scale'),
+        tlRange     = Number( data.timeline.attr('range') ),
+//        minRangeDt  = new Date( data.timeline.attr('timeline-range-from') ),
+//        maxRangeDt  = new Date( data.timeline.attr('timeline-range-to') ),
+        tlMaxRow    = Number( data.timeline.attr('rows') ),
+        tlTotalCols = Number( data.timeline.attr('total-cols') ),
+        minGridPer  = Number( data.timeline.attr('min-grid-per') ),
+        minGridSize = Number( data.timeline.attr('min-grid-size') ),
+        coordinate  = { x: 0, y: 0, w: 0 },
+        tlWidth     = minGridSize * tlTotalCols - 1;
+    $this.find('.timeline-loader').css( 'display', 'block' );
+    
+    // Updated tlEndDt
+    switch( tlScale ) {
+      case 'years':
+        tlEndDt.setYear( tlEndDt.getFullYear() + tlRange );
+        break;
+      case 'months':
+        tlEndDt.setMonth( tlEndDt.getMonth() + tlRange - 1 );
+        break;
+      case 'days':
+        tlEndDt.setDate( tlEndDt.getDate() + tlRange );
+        break;
+    }
+    
+console.info([ 'placeEvents', data.timeline, eventNodes, tlStartDt, tlEndDt, tlTotalCols, tlWidth ]);
+    $this.find('.timeline-events').empty();
+    eventNodes.forEach(function( evt, i ) {
+      if ( evt.start ) {
+        var evtStartDt = new Date( evt.start ),
+            evtEndDt   = evt.end == undefined ? new Date( evt.start ) : new Date( evt.end ),
+            msMonth    = 30 * 24 * 60 * 60 * 1000, // base value
+            msDay      = 24 * 60 * 60 * 1000,
+            msHour     = 60 * 60 * 1000,
+            gridSize   = minGridPer * minGridSize,
+            tlNodeElm;
+        //if ( isBetweenTo( evtStartDt, minRangeDt, maxRangeDt ) && isBetweenTo( evtStartDt, tlStartDt, tlEndDt ) ) {
+        if ( isBetweenTo( evtStartDt, tlStartDt, tlEndDt ) ) {
+          // イベント開始日時が開始日時がタイムライン表示範囲内の場合
+          switch( tlScale ) {
+            case 'years':
+              coordinate.x = Math.round( ( ( evtStartDt - tlStartDt ) * tlWidth ) / ( tlEndDt - tlStartDt ) );
+              //coordinate.x = Math.floor( ( evtStartDt - tlStartDt ) / msMonth * gridSize );
+              break;
+            case 'months':
+              coordinate.x = Math.floor( ( evtStartDt - tlStartDt ) / msDay * gridSize );
+              break;
+            case 'days':
+              //coordinate.x = Math.round( ( ( evtStartDt - tlStartDt ) * tlWidth ) / ( tlEndDt - tlStartDt ) );
+              coordinate.x = Math.floor( ( evtStartDt - tlStartDt ) / msHour * gridSize );
+              break;
+          }
+          coordinate.y = typeof evt.row !== 'undefined' ? ( evt.row - 1 ) * rowH : 0;
+          if ( isBetweenTo( evtEndDt, tlStartDt, tlEndDt ) ) {
+            // イベント終了日時がタイムライン表示範囲内の場合: イベントブロックの横幅を定義
+            switch( tlScale ) {
+              case 'years':
+                coordinate.w = Math.floor( ( ( evtEndDt - tlStartDt ) / msMonth * gridSize ) - coordinate.x );
+                break;
+              case 'months':
+                coordinate.w = Math.floor( ( ( evtEndDt - tlStartDt ) / msDay * gridSize ) - coordinate.x );
+                break;
+              case 'days':
+                //coordinate.w = Math.round( ( ( evtEndDt - tlStartDt ) * tlWidth ) / ( tlEndDt - tlStartDt ) ) - coordinate.x;
+                coordinate.w = Math.floor( ( ( evtEndDt - tlStartDt ) / msHour * gridSize ) - coordinate.x );
+                break;
+            }
+            if ( coordinate.w == 0 ) {
+              coordinate.w = 1;
+            }
+          } else {
+            // イベント終了日時がタイムライン表示範囲を超える場合: イベントブロックの横幅をタイムライン表示域最大で定義
+            switch( tlScale ) {
+              case 'years':
+                coordinate.w = Math.floor( ( ( tlEndDt - tlStartDt ) / msMonth * gridSize ) - coordinate.x );
+                break;
+              case 'months':
+                coordinate.w = Math.floor( ( ( tlEndDt - tlStartDt ) / msDay * gridSize ) - coordinate.x );
+                break;
+              case 'days':
+                coordinate.w = Math.floor( ( ( tlEndDt - tlStartDt ) / msHour * gridSize ) - coordinate.x );
+                break;
+            }
+          }
+        } else
+        if ( isBetweenTo( evtEndDt, tlStartDt, tlEndDt ) ) {
+        //if ( isBetweenTo( evtEndDt, minRangeDt, maxRangeDt ) && isBetweenTo( evtEndDt, tlStartDt, tlEndDt ) ) {
+          // イベント終了日時がタイムライン表示範囲内の場合
+          coordinate.x = 0;
+          coordinate.y = typeof evt.row !== 'undefined' ? ( evt.row - 1 ) * rowH : 0;
+          switch( tlScale ) {
+            case 'years':
+              coordinate.w = Math.floor( ( evtEndDt - tlStartDt ) / msMonth * gridSize );
+              break;
+            case 'months':
+              coordinate.w = Math.floor( ( evtEndDt - tlStartDt ) / msDay * gridSize );
+              break;
+            case 'days':
+              coordinate.w = Math.floor( ( evtEndDt - tlStartDt ) / msHour * gridSize );
+              break;
+          }
+        } else
+        if ( isBetweenTo( tlStartDt, evtStartDt, evtEndDt ) && isBetweenTo( tlEndDt, evtStartDt, evtEndDt ) ) {
+          // イベント期間内にタイムライン表示範囲が含まれる場合(長期間の帯イベント用)
+          coordinate.x = 0;
+          coordinate.y = typeof evt.row !== 'undefined' ? ( evt.row - 1 ) * rowH : 0;
+          switch( tlScale ) {
+            case 'years':
+              coordinate.w = Math.floor( ( tlEndDt - tlStartDt ) / msMonth * gridSize );
+              break;
+            case 'months':
+              coordinate.w = Math.floor( ( tlEndDt - tlStartDt ) / msDay * gridSize );
+              break;
+            case 'days':
+              coordinate.w = Math.floor( ( tlEndDt - tlStartDt ) / msHour * gridSize );
+              break;
+          }
+        } else {
+          coordinate.w = 0;
+        }
+console.info([ coordinate.x, coordinate.y, coordinate.w, evtStartDt, evtEndDt, evt.eventId ]);
+        if ( coordinate.w > 0 ) {
+          if ( tlType === 'point' ) {
+            // For event view type: point
+            var margin = evt.margin ? Number( evt.margin ) : pointMargin;
+            margin = margin < 0 ? 0 : margin; 
+            margin = margin > (rowH / 2) ? (rowH / 2) - 1 : margin;
+            tlNodeElm = $('<div />', {
+              addClass: 'timeline-node timeline-event-pointer',
+              id: 'evt-' + evt.eventId,
+              css: {
+                left  : coordinate.x - Math.floor(rowH / 2) + margin + 'px',
+                top   : coordinate.y + margin + 'px',
+                width : rowH - (margin * 2) + 'px',
+                height: rowH - (margin * 2) + 'px'
+              },
+              title: evt.label
+            });
+            if ( evt.bdColor ) {
+              tlNodeElm.css('border-color', evt.bdColor );
+            } else 
+            if ( evt.bgColor ) {
+              tlNodeElm.css('border-color', evt.bgColor );
+            }
+            if ( evt.image ) {
+              tlNodeElm.css('background-image', 'url(' + evt.image +')');
+            }
+            if ( evt.relation ) {
+              $.each(evt.relation, function( key, value ) {
+                if ( $.inArray( key, [ 'before', 'after', 'size' ] ) != -1 && ! isNaN( value ) ) {
+                  tlNodeElm.attr( 'data-relay-' + key, Number( value ) );
+                } else
+                if ( key === 'curve' ) {
+                  if ( $.inArray( value, [ 'lt', 'rt', 'lb', 'rb' ] ) != -1 ) {
+                    tlNodeElm.attr( 'data-relay-curve', value );
+                  }
+                } else {
+                  tlNodeElm.attr( 'data-relay-' + key, value );
+                }
+              });
+            }
+          } else {
+            // For event view type: bar
+            tlNodeElm = $('<div />', {
+              addClass: 'timeline-node timeline-text-truncate',
+              id: 'evt-' + evt.eventId,
+              css: {
+                left  : coordinate.x + 'px',
+                top   : coordinate.y + 'px',
+                width : coordinate.w + 'px'
+              },
+              text: evt.label
+            });
+            if ( evt.color ) {
+              tlNodeElm.css('color', evt.color );
+            }
+            if ( coordinate.w < minGridSize ) {
+              tlNodeElm.css('padding-left', '1.5rem').css('padding-right', '0').css('text-overflow', 'clip');
+            }
+          }
+          if ( evt.bgColor ) {
+            tlNodeElm.css('background-color', evt.bgColor );
+          }
+          if ( evt.extend ) {
+            $.each(evt.extend, function( key, value ) {
+              tlNodeElm.attr( 'data-' + key, value );
+            });
+          }
+          $this.find('.timeline-events').append( tlNodeElm.prop('outerHTML') );
+        }
+      }
+      // End of forEach
+    });
+    $this.find('.timeline-loader').css( 'display', 'none' );
+    
+    if ( tlType === 'point' || tlType === 'mixed' ) {
+      drowRelationLine( $this );
+
+      // Set event of hovering event-node (point type)
+      $this.find('.timeline-event-pointer').hover(function(e){
+        var defaultAxis;
+        if ( e.type === 'mouseenter' ) {
+          defaultAxis = { left: parseInt( $(this).css('left') ), top: parseInt( $(this).css('top') ), width: parseInt( $(this).css('width') ), height: parseInt( $(this).css('height') ) };
+          $(this).attr( 'data-default-axis', JSON.stringify( defaultAxis ) );
+          // on hover action
+          if ( ! $(this).hasClass('hovered') ) {
+            $(this).addClass('hovered').animate({ left: defaultAxis.left - rowH/10, top: defaultAxis.top - rowH/10, width: defaultAxis.width + rowH/10*2, height: defaultAxis.height + rowH/10*2 },0);
+          }
+        } else
+        if ( e.type === 'mouseleave' ) {
+          defaultAxis = $(this).data( 'defaultAxis' );
+          $(this).css('left', defaultAxis.left + 'px').css('top', defaultAxis.top + 'px').css('width', defaultAxis.width + 'px').css('height', defaultAxis.height + 'px');
+          $(this).removeAttr( 'data-default-axis' );
+          // off hover action
+          if ( $(this).hasClass('hovered') ) {
+            $(this).removeClass('hovered');
+          }
+        }
+      });
+    
+    }
+  }
+
+  function drowRelationLine( obj ) {
+    var events   = obj.find('.timeline-node.timeline-event-pointer'),
+        relayMap = {},
+        canvas   = obj.find('.timeline-line-canvas')[0],
+        ctx;
+    if ( ! canvas.getContext ) {
+      return;
+    }
+    ctx = canvas.getContext('2d');
+    // Get data for drawing and draw line
+    events.each(function(){
+//console.log( $(this) );
+      var lineColor = $(this).data('relayLinecolor') == undefined ? $(this).css('border-left-color') : $(this).data('relayLinecolor'),
+          lineSize  = $(this).data('relayLinesize') == undefined ? Math.round(rowH/10) : $(this).data('relayLinesize'),
+          targetId, selfPoint, startPoint, endPoint, cv, controlPoint, diffRow;
+      // initialize
+      ctx.strokeStyle = lineColor;
+      ctx.lineWidth   = lineSize;
+      ctx.lineJoin    = 'round';
+      ctx.lineCap = 'round';
+      cv = {
+        x: (rowH - ctx.lineWidth) / 2,
+        y: rowH / 2
+      };
+      selfPoint = {
+        x: $(this)[0].offsetLeft + cv.x,
+        y: Math.floor( $(this)[0].offsetTop / rowH ) * rowH + cv.y
+      };
+      
+      // Draw lines
+      if ( $(this).data('relayBefore') != undefined ) {
+        // Draw from before-event to myself
+        if ( $(this).data('relayBefore') > 0 ) {
+          startPoint = {
+            x: $('#evt-' + $(this).data('relayBefore'))[0].offsetLeft + cv.x,
+            y: Math.floor( $('#evt-' + $(this).data('relayBefore'))[0].offsetTop / rowH ) * rowH + cv.y
+          };
+        } else {
+          startPoint = { x: 0, y: selfPoint.y };
+        }
+        diffRow = ( startPoint.y - selfPoint.y ) / rowH;
+        if ( Math.abs( diffRow ) > 0 && $(this).data('relayCurve') != undefined && $.inArray( $(this).data('relayCurve'), [ 'lt', 'rt', 'lb', 'rb' ] ) != -1 ) {
+          drawLine( startPoint, selfPoint, $(this).data('relayCurve') );
+        } else {
+          drawLine( startPoint, selfPoint );
+        }
+      }
+      if ( $(this).data('relayAfter') != undefined ) {
+        // Draw from myself to after-event
+        if ( $(this).data('relayAfter') > 0 ) {
+          endPoint = {
+            x: $('#evt-' + $(this).data('relayAfter'))[0].offsetLeft + cv.x,
+            y: Math.floor( $('#evt-' + $(this).data('relayAfter'))[0].offsetTop / rowH ) * rowH + cv.y
+          };
+        } else {
+          endPoint = { x: canvas.width, y: selfPoint.y };
+        }
+        diffRow = ( selfPoint.y - endPoint.y ) / rowH;
+        if ( Math.abs( diffRow ) > 0 && $(this).data('relayCurve') != undefined && $.inArray( $(this).data('relayCurve'), [ 'lt', 'rt', 'lb', 'rb' ] ) != -1 ) {
+          drawLine( selfPoint, endPoint, $(this).data('relayCurve') );
+        } else {
+          drawLine( selfPoint, endPoint );
+        }
+      }
+      
+    });
+    
+    function drawLine( start, end, curve ) {
+      if ( typeof start !== 'object' || typeof end !== 'object' ) {
+        return;
+      }
+      curve = curve || false;
+      var diff = { x: Math.abs( (start.x - end.x) / rowH ), y:Math.abs( (start.y - end.y) / rowH ) };
+      ctx.beginPath();
+      ctx.moveTo( start.x, start.y );
+      if ( curve !== false ) {
+        switch ( curve ) {
+          case 'lt':
+            controlPoint = {
+              relayStartX: start.x, 
+              relayStartY: end.y + rowH,
+              cpx: start.x,
+              cpy: end.y,
+              relayEndX: start.x + rowH,
+              relayEndY: end.y
+            };
+            break;
+          case 'rt':
+            controlPoint = {
+              relayStartX: end.x - rowH,
+              relayStartY: start.y,
+              cpx: end.x,
+              cpy: start.y,
+              relayEndX: end.x,
+              relayEndY: start.y + rowH
+            };
+            break;
+          case 'lb':
+            controlPoint = {
+              relayStartX: start.x,
+              relayStartY: end.y - rowH,
+              cpx: start.x,
+              cpy: end.y,
+              relayEndX: start.x + rowH,
+              relayEndY: end.y
+            };
+            break;
+          case 'rb':
+            controlPoint = {
+              relayStartX: end.x - rowH,
+              relayStartY: start.y,
+              cpx: end.x,
+              cpy: start.y,
+              relayEndX: end.x,
+              relayEndY: start.y - rowH
+            };
+            break;
+        }
+        if ( diff.x > 1 || diff.y > 1 ) {
+          ctx.lineTo( controlPoint.relayStartX, controlPoint.relayStartY );
+        }
+        ctx.quadraticCurveTo( controlPoint.cpx, controlPoint.cpy, controlPoint.relayEndX, controlPoint.relayEndY );
+      }
+      ctx.lineTo( end.x, end.y );
+      ctx.stroke();
+    }
+
+  }
+
+  function showEvent( eventData ) {
+    if ( $('.timeline-event-view').length == 0 ) {
+      return true;
+    }
+console.info( eventData );
+    $('.timeline-event-view').empty();
+    var tlevHeader = $('<div />', { addClass: "timeline-event-header" }),
+        tlevLabel  = $('<h3 />',  { addClass: "timeline-event-label" }),
+        tlevMeta   = $('<div />', { addClass: "timeline-event-meta" }),
+        tlevBody   = $('<div />', { addClass: "timeline-event-body" }),
+        tlevFooter = $('<div />', { addClass: "timeline-event-footer" }),
+        temp;
+    tlevLabel.text( eventData.label );
+    temp =  '<span class="timeline-event-start-date">' + formatDate( 'Y/m/d H:i', eventData.start ) + '</span>';
+    if ( eventData.end ) {
+      temp += '<span class="timeline-event-date-separator"></span>';
+      temp += '<span class="timeline-event-end-date">' + formatDate( 'Y/m/d H:i', eventData.end ) + '</span>';
+    }
+    tlevHeader.append( tlevLabel.prop('outerHTML') + tlevMeta.append( temp ).prop('outerHTML') );
+    if ( eventData.content ) {
+      tlevBody.html( eventData.content );
+    }
+    
+    $('.timeline-event-view').append( tlevHeader.prop('outerHTML') + tlevBody.prop('outerHTML') + tlevFooter.prop('outerHTML') );
+    
+    return true;
+  }
+
+  var retriveServerDate = function( ) {
+    // Retrive datetime from server
+    return $.ajax({
+      type: 'GET'
+    }).done(function(d,s,xhr){
+      $('body').data('serverDate', new Date(xhr.getResponseHeader('Date')));
+    }).promise();
+  };
+
+  function setCurrentDate( fromServer ) {
+    // Setting currently datetime
+    var currentDate = new Date();
+    if ( fromServer ) {
+      retriveServerDate().then(function() {
+        currentDate = $('body').data('serverDate');
+        $.removeData('body', 'serverDate');
+      }, function() {
+        currentDate = new Date();
+      });
+    }
+    return currentDate;
+  }
+  
+  function isBetweenTo( targetDate, beginDate, endDate ) {
+    // Determine whether the specified date and time is within range
+    var targetDt = new Date( targetDate ).getTime(),
+        beginDt  = new Date( beginDate ).getTime(),
+        endDt    = new Date( endDate ).getTime();
+    return targetDt - beginDt >= 0 && endDt - targetDt >= 0;
+  }
+  
+  function getAbscissa( targetDt, dataObject ) {
+    var targetDt    = Object.prototype.toString.call( targetDt ) === '[object Date]' ? targetDt : new Date( targetDt ),
+        data        = dataObject.timeline,
+        //justify     = $.inArray( justify.toLowerCase(), [ 'left', 'center' ] ) != -1 ? justify.toLowerCase() : 'center',
+        startDt     = new Date( data.attr('actual-start-datetime') ),
+        endDt       = new Date( startDt ),
+        scale       = data.attr('scale'),
+        range       = Number( data.attr('range') ),
+        tlTotalCols = Number( data.attr('total-cols') ),
+        minGridPer  = Number( data.attr('min-grid-per') ),
+        minGridSize = Number( data.attr('min-grid-size') ),
+        tlWidth     = minGridSize * tlTotalCols - 1,
+        msDay       = 24 * 60 * 60 * 1000,
+        msHour      = 60 * 60 * 1000,
+        gridSize    = minGridPer * minGridSize,
+        posX;
+    // Set end datetime
+    switch ( scale ) {
+      case 'years':
+        endDt = new Date( endDt.setFullYear( endDt.getFullYear() + range - 1 ) );
+        break;
+      case 'months':
+        endDt = new Date( endDt.setMonth( endDt.getMonth() + range - 1 ) );
+        break;
+      case 'days':
+        endDt = new Date( endDt.setDate( endDt.getDate() + range - 1 ) );
+        break;
+    }
+    if ( isBetweenTo( targetDt, startDt, endDt ) ) {
+      switch ( scale ) {
+        case 'years':
+          posX = Math.round( ( ( targetDt - startDt ) * tlWidth ) / ( endDt - startDt ) );
+          break;
+        case 'months':
+          posX = Math.floor( ( targetDt - startDt ) / msDay * gridSize );
+          break;
+        case 'days':
+          posX = Math.floor( ( targetDt - startDt ) / msHour * gridSize );
+          break;
+      }
+      return posX;
+    } else {
+      return false;
+    }
+  }
+  
+  function retriveDaysGrid( minuteInterval, minGridPer ) {
+    // Deprecated
+    if ( minGridPer == 30 ) {
+      return Math.floor( 60 / Number( minuteInterval ) );
+    } else {
+      return Number( minGridPer );
+    }
+  }
+  
+  function array_sum( ary ) {
+    // Sum all values in array
+    return ary.reduce(function( prev, current, i, ary ) {
+      return prev + current;
+    });
+  }
+  
+  function object_values( obj ) {
+    // Return array of values in object
+    var r = [];
+    for( var k in obj ) {
+      if ( obj.hasOwnProperty( k ) ) {
+        r.push( obj[k] );
+      }
+    }
+    return r;
+  }
+  
+  function object_keys( obj ) {
+    // Return array of keys in object
+    var r = [];
+    for ( var k in obj ) {
+      if ( obj.hasOwnProperty( k ) ) {
+        r.push( k );
+      }
+    }
+    return r;
+  }
+  
+  function zerofill( num, digit ) {
+    // Return numeric string with zero-fill the specific upper digits
+    var strDuplicate = function( n, str ) {
+          return Array( n + 1 ).join( str );
+        },
+        zero = strDuplicate( digit - 1, '0' );
+    return String( num ).length == digit ? num : ( zero + num ).substr( num * -1 );
+  }
+  
+  function formatDate( format, date ) {
+    // Date format like PHP
+    var baseDt  = Object.prototype.toString.call( date ) === '[object Date]' ? date : new Date( date ),
+        month   = { 'Jan': 'January', 'Feb': 'February', 'Mar': 'March', 'Apr': 'April', 'May': 'May', 'Jun': 'June', 'Jul': 'July', 'Aug': 'August', 'Sep': 'September', 'Oct': 'October', 'Nov': 'November', 'Dec': 'December' },
+        day     = { 'Sun': 'Sunday', 'Mon': 'Monday', 'Tue': 'Tuesday', 'Wed': 'Wednesday', 'Thu': 'Thurseday', 'Fri': 'Friday', 'Sat': 'Saturday' },
+        ma      = [ 'am', 'pm' ],
+        formatStrings = format.split(''),
+        converted = '',
+        esc = false,
+        lastDayOfMonth = function( dateObj ) {
+          var _tmp = new Date( dateObj.getFullYear(), dateObj.getMonth() + 1, 1 );
+          _tmp.setTime( _tmp.getTime() - 1 );
+          return _tmp.getDate();
+        },
+        isLeapYear = function( dateObj ) {
+          var _tmp = new Date( dateObj.getFullYear(), 0, 1 ),
+              sum  = 0, i;
+          for ( i = 0; i < 12; i++ ) {
+            _tmp.setMonth(i);
+            sum += lastDayOfMonth( _tmp );
+          }
+          return ( sum === 365 ) ? 0 : 1;
+        },
+        dateCount = function( dateObj ) {
+          var _tmp = new Date( dateObj.getFullYear(), 0, 1 ),
+              sum = 0, i;
+          for ( i=0; i<dateObj.getMonth(); i++ ) {
+            _tmp.setMonth(i);
+            sum += lastDayOfMonth( _tmp );
+          }
+          return sum + dateObj.getDate();
+        },
+        half_hours = function( dateObj ) {
+          var h = dateObj.getHours();
+          return h > 12 ? h - 12 : h;
+        },
+        ampm = function( dateObj ) {
+          var h = dateObj.getHours();
+          return h > 12 ? ma[1] : ma[0];
+        };
+
+    if ( format === '' ) {
+      return baseDt;
+    }
+
+    // localize
+    if ( typeof $.timeline.global === 'object' ) {
+      month = typeof $.timeline.global.month === 'object' ? $.timeline.global.month : month;
+      day   = typeof $.timeline.global.day   === 'object' ? $.timeline.global.day   : day;
+      ma    = typeof $.timeline.global.ma    === 'object' ? $.timeline.global.ma    : ma;
+    }
+
+    formatStrings.forEach( function( str, i ) {
+      var res, tmp, sign;
+      if ( esc === false ) {
+        switch( str ) {
+          case 'Y': // Full year | ruby %Y
+          case 'o': // Full year (ISO-8601)
+            res = baseDt.getFullYear();
+            break;
+          case 'y': // Two digits year | ruby %y
+            res = ('' + baseDt.getFullYear()).slice(-2);
+            break;
+          case 'm': // Zerofill month (01-12) | ruby %m
+            res = ('0' + (baseDt.getMonth() + 1)).slice(-2);
+            break;
+          case 'n': // Month
+            res = baseDt.getMonth() + 1;
+            break;
+          case 'F': // Full month name | ruby %B
+            res = object_values( month )[baseDt.getMonth()];
+            break;
+          case 'M': // Short month name | ruby %b
+            res = object_keys( month )[baseDt.getMonth()];
+            break;
+          case 'd': // Zerofill day (01-31) | ruby %d
+            res = ('0' + baseDt.getDate()).slice(-2);
+            break;
+          case 'j': // Day
+            res = baseDt.getDate();
+            break;
+          case 'S': // Day with suffix
+            var suffix = [ 'st', 'nd', 'rd', 'th' ],
+                suffix_index = function(){
+                  var d = baseDt.getDate();
+                  if ( d == 1 || d == 2 || d == 3 || d == 21 || d == 22 || d == 23 || d == 31 ) {
+                    return Number( ('' + d).slice(-1) - 1 );
+                  } else {
+                    return 3;
+                  }
+                };
+            res = suffix[suffix_index()];
+            break;
+          case 'w': // Day of the week (number) | ruby %w
+          case 'W': // Day of the week (ISO-8601 number)
+            res = baseDt.getDay();
+            break;
+          case 'l': // Day of the week (full) | ruby %A
+            res = object_values( day )[baseDt.getDay()];
+            break;
+          case 'D': // Day of the week (short) | ruby %a
+            res = object_keys( day )[baseDt.getDay()];
+            break;
+          case 'N': // Day of the week (ISO-8601 number)
+            res = baseDt.getDay() === 0 ? 7 : baseDt.getDay();
+            break;
+          case 'a': // am or pm
+            res = ampm(baseDt);
+            break;
+          case 'A': // AM or PM
+            res = ampm(baseDt).toUpperCase();
+            break;
+          case 'g': // Half hours (1-12)
+            res = half_hours( baseDt );
+            break;
+          case 'h': // Zerofill half hours (01-12) | ruby %I
+            res = ('0' + half_hours(baseDt)).slice(-2);
+            break;
+          case 'G': // Full hours (0-23)
+            res = baseDt.getHours();
+            break;
+          case 'H': // Zerofill full hours (00-23) | ruby %H
+            res = ('0' + baseDt.getHours()).slice(-2);
+            break;
+          case 'i': // Zerofill minutes (00-59) | ruby %M
+            res = ('0' + baseDt.getMinutes()).slice(-2);
+            break;
+          case 's': // Zerofill seconds (00-59) | ruby %S
+            res = ('0' + baseDt.getSeconds()).slice(-2);
+            break;
+          case 'z': // Day of the year (1-366) | ruby %j
+            res = dateCount( baseDt );
+            break;
+          case 't': // Days of specific month
+            res = lastDayOfMonth( baseDt );
+            break;
+          case 'L': // Whether a leap year
+            res = isLeapYear( baseDt );
+            break;
+          case 'c': // Date of ISO-8601
+            tmp = baseDt.getTimezoneOffset();
+            tzo = [ Math.floor( Math.abs( tmp ) / 60 ), Math.abs( tmp ) % 60 ];
+            sign = tmp < 0 ? '+' : '-';
+            res  = baseDt.getFullYear() +'-'+ zerofill( baseDt.getMonth() + 1, 2 ) +'-'+ zerofill( baseDt.getDate(), 2 ) +'T';
+            res += zerofill( baseDt.getHours(), 2 ) +':'+ zerofill( baseDt.getMinutes(), 2 ) +':'+ zerofill( baseDt.getSeconds(), 2 );
+            res += sign + zerofill( tzo[0], 2 ) +':'+ zerofill( tzo[1], 2 );
+            break;
+          case 'r': // Date of RFC-2822
+            tmp = baseDt.getTimezoneOffset();
+            tzo = [ Math.floor( Math.abs( tmp ) / 60 ), Math.abs( tmp ) % 60 ];
+            sign = tmp < 0 ? '+' : '-';
+            res  = object_keys( day )[baseDt.getDay()] +', '+ baseDt.getDate() +' '+ object_keys( month )[baseDt.getMonth()] +' '+ baseDt.getFullYear() +' ';
+            res += zerofill( baseDt.getHours(), 2 ) +':'+ zerofill( baseDt.getMinutes(), 2 ) +':'+ zerofill( baseDt.getSeconds(), 2 ) +' ';
+            res += sign + zerofill( tzo[0], 2 ) + zerofill( tzo[1], 2 );
+            break;
+          case 'u': // Millisecond
+            res = baseDt.getTime();
+            break;
+          case 'U': // Unix Epoch seconds
+            res = Date.parse( baseDt ) / 1000;
+            break;
+          case "\\": // escape
+            esc = true;
+            res = formatStrings[i + 1];
+            break;
+          default:
+            res = str;
+            break;
+        }
+        converted += res;
+      } else {
+        esc = false;
+        return true;
+      }
+    });
+    return converted;
+  }
+  
+  
+})( jQuery );
\ No newline at end of file
diff --git a/src/timeline.org.css b/src/timeline.org.css
new file mode 100644
index 0000000000000000000000000000000000000000..cadb0a02494119024b58e1bf21fefa50c7a3e7d9
--- /dev/null
+++ b/src/timeline.org.css
@@ -0,0 +1,474 @@
+@charset "UTF-8";
+/**
+ * JQuery Timeline Plugin Styles
+ * ------------------------
+ * Version: 1.0.0
+ * Coded by: ka2 (https://ka2.org/)
+ * Lisenced: MIT
+ */
+@font-face {
+  font-family: 'jQueryTimeline';
+  src:  url('fonts/jQueryTimeline.eot?t4qpol');
+  src:  url('fonts/jQueryTimeline.eot?t4qpol#iefix') format('embedded-opentype'),
+    url('fonts/jQueryTimeline.ttf?t4qpol') format('truetype'),
+    url('fonts/jQueryTimeline.woff?t4qpol') format('woff'),
+    url('fonts/jQueryTimeline.svg?t4qpol#jQueryTimeline') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+[class^="jqtl-"], [class*=" jqtl-"] {
+  /* use !important to prevent issues with browser extensions that change fonts */
+  font-family: 'jQueryTimeline' !important;
+  speak: none;
+  font-style: normal;
+  font-weight: normal;
+  font-variant: normal;
+  text-transform: none;
+  line-height: 1;
+
+  /* Better Font Rendering =========== */
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.jqtl-pushpin:before {
+  content: "\ea37";
+}
+.jqtl-calendar:before {
+  content: "\ea60";
+}
+.jqtl-spinner:before {
+  content: "\eb24";
+}
+.jqtl-more:before {
+  content: "\ec5b";
+}
+.jqtl-more-horizontal:before {
+  content: "\ec5c";
+}
+.jqtl-more-vertical:before {
+  content: "\ec6a";
+}
+.jqtl-dot:before {
+  content: "\ec6b";
+}
+.jqtl-plus:before {
+  content: "\ed5d";
+}
+.jqtl-minus:before {
+  content: "\ed5e";
+}
+.jqtl-cross:before {
+  content: "\ed6d";
+}
+.jqtl-circle-right:before {
+  content: "\edee";
+}
+.jqtl-circle-left:before {
+  content: "\edf2";
+}
+.jqtl-circle-fill-right:before {
+  content: "\edf6";
+}
+.jqtl-circle-fill-left:before {
+  content: "\edfa";
+}
+.jqtl-arrow-down:before {
+  content: "\ee29";
+}
+*, ::after, ::before {
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.timeline-container {
+  position: relative;
+  display: block;
+  visibility: hidden;
+  margin: 15px;
+  font-size: 1rem;
+  line-height: 1.5;
+}
+.timeline-header {
+  text-align: left;
+}
+.timeline-headline {
+  margin-top: 0;
+  margin-bottom: .5rem;
+  font-family: inherit;
+  font-size: 1.3rem;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+.timeline-from-date, .timeline-to-date {
+  margin-right: .3rem;
+}
+.timeline-from-date:before {
+  content: "\ea60";
+  font-family: 'jQueryTimeline' !important;
+  margin-right: .3rem;
+  color: #7f7f7f;
+  font-weight: 400;
+}
+.timeline-to-date:before {
+  content: "\301C";
+  margin-right: .3rem;
+  color: #7f7f7f;
+  font-weight: 400;
+}
+.timeline-body {
+  position: relative;
+  display: block;
+  margin: 0 auto;
+  width: inherit;
+  overflow-x: auto;
+  overflow-y: hidden;
+  text-align: center;
+  z-index: 1;
+}
+.timeline-wrapper {
+  position: relative;
+  display: inline-block;
+  margin: 0 1px;
+  width: auto;
+  height: 259px; /* default: index-table(59px) + timeline-grid(200px)  */
+}
+.timeline-wrapper:before, .timeline-wrapper:after {
+  content: "";
+  position: absolute;
+  top: 0;
+  width: 1px;
+  height: 100%;
+}
+.timeline-wrapper:before {
+  left: 0;
+  border-left: 1px solid #ddd;
+}
+.timeline-wrapper:after {
+  right: 0;
+  border-right: 1px solid #ddd;
+}
+.timeline-timetable {
+  display: table;
+  position: relative;
+  border-collapse: collapse;
+  border-spacing: 0;
+  border-color: #ddd;
+  border-top: 1px solid #ddd;
+  border-right: 0;
+  border-bottom: 1px solid #ddd;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th {
+  border: 0;
+}
+.timeline-timetable>thead>tr>th.scale-major {
+  padding-top: 4px;
+  padding-bottom: 4px;
+  font-size: 100%;
+  color: #555;
+  text-align: center;
+  border-top: 0;
+  border-right: 1px solid #ddd;
+  border-bottom: 0;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th.scale-medium {
+  /* width: calc( 100% / 24 ); */
+  padding-top: 0;
+  padding-bottom: 4px;
+  font-size: 85%;
+  color: #777;
+  text-align: center;
+  border-top: 0;
+  border-right: 1px solid #ddd;
+  border-bottom: 0;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th.scale-major:last-child, 
+.timeline-timetable>thead>tr>th.scale-medium:last-child {
+  border-right: 0;
+}
+.timeline-timetable>thead>tr>th.scale-small {
+  padding: 0;
+  border-top: 0;
+  border-right: 1px solid #ddd;
+  border-bottom: 1px solid #ddd;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th.scale-small:last-child {
+  border-right: 0;
+}
+.timeline-to-prev {
+  position: absolute;
+  top: -2rem;
+  left: 15px;
+  z-index: 9;
+}
+.timeline-to-next {
+  position: absolute;
+  top: -2rem;
+  right: 15px;
+  z-index: 9;
+}
+.scale-days {
+  
+}
+.scale-hours {
+  
+}
+.scale-minutes {
+  
+}
+.spacer-cell {
+  display: block;
+  width: 29px;
+  min-height: 5px;
+}
+.timeline-events {
+  position: absolute;
+  display: block;
+  left: 0;
+  width: 100%;
+  height: 200px;
+  z-index: 9;
+}
+.timeline-node {
+  position: absolute;
+  display: block;
+  margin: 6px 0;
+  padding: 4px 25px 4px 10px;
+  height: auto;
+  line-height: 20px;
+  vertical-align: middle;
+  text-align: left;
+  background-color: #e3d7a3;
+  color: #777e41;
+  user-select: none;
+  border-radius: 4px;
+  cursor: pointer;
+  z-index: 8;
+  -moz-transition: all 1s ease 0;
+  -webkit-transition: all 1s ease 0;
+  -o-transition: all 1s ease 0;
+  -ms-transition: all 1s ease 0;
+  transition: all 1s ease 0;
+}
+.timeline-event-pointer {
+  margin: 0;
+  padding: 0;
+  line-height: 1;
+  text-align: center;
+  background-color: #f0f0f0;
+  border-radius: 100%;
+  border: solid 4px #4496d3;
+  background-image: none;
+  background-size: cover;
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+.timeline-node.timeline-event-pointer.hovered {
+  z-index: 99;
+}
+.timeline-node.timeline-event-pointer.active {
+  box-shadow: 0px 10px 6px -6px rgba(51,51,51,.25);
+  z-index: 99;
+}
+.timeline-text-truncate {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.timeline-node.timeline-text-truncate.active {
+  margin: 2px 0 4px;
+  border: solid 1px rgba(61,61,61,.25);
+  box-shadow: 0px 10px 6px -6px rgba(51,51,51,.25);
+  z-index: 99;
+}
+.timeline-node.timeline-text-truncate:after {
+  content: "\ec5c";
+  font-family: 'jQueryTimeline' !important;
+  font-size: 14px;
+  position: absolute;
+  right: 5px;
+}
+.timeline-loader {
+  position: absolute;
+  display: inline-block;
+  width: 48px;
+  height: 48px;
+  margin: 0;
+  padding: 0;
+  top: 50%;
+  left: 50%;
+  opacity: .3;
+  -webkit-animation: spin 2.1s linear infinite;
+  -moz-animation: spin 2.1s linear infinite;
+  -ms-animation: spin 2.1s linear infinite;
+  -o-animation: spin 2.1s linear infinite;
+  animation: spin 2.1s linear infinite;
+}
+.timeline-loader i {
+  position: absolute;
+  top: 0;
+  left: 0;
+  font-size: 48px;
+}
+@-webkit-keyframes spin {
+  0% {-webkit-transform: rotate(0deg);}
+  100% {-webkit-transform: rotate(360deg);}
+}
+@-moz-keyframes spin {
+  0% {-moz-transform: rotate(0deg);}
+  100% {-moz-transform: rotate(360deg);}
+}
+@-ms-keyframes spin {
+  0% {-ms-transform: rotate(0deg);}
+  100% {-ms-transform: rotate(360deg);}
+}
+@-o-keyframes spin {
+  0% {-o-transform: rotate(0deg);}
+  100% {-o-transform: rotate(360deg);}
+}
+@keyframes spin {
+  0% {transform: rotate(0deg);}
+  100% {transform: rotate(360deg);}
+}
+.timeline-line-canvas {
+  position: absolute;
+  display: block;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 200px;
+  z-index: 6;
+}
+.timeline-grids {
+  position: absolute;
+  left: 0;
+  height: 200px;
+  border-top: 1px solid #ddd;
+  z-index: 0;
+}
+.timeline-grids>tbody>tr>td {
+  padding: 0;
+  border-top: 0;
+  border-right: 1px dotted #ddd;
+  border-bottom: 0;
+  border-left: 0;
+  vertical-align: bottom;
+}
+.timeline-grids>tbody>tr>td:first-child {
+  border-left: 0;
+}
+.timeline-grids>tbody>tr>td:last {
+  border-right: 0;
+}
+.timeline-needle-pointer {
+  position: absolute;
+  display: block;
+  top: 56px;
+  width: 1px;
+  height: calc( 100% - 56px );
+  border-left: 2px dotted #e8383d;
+  z-index: 19;
+}
+.timeline-needle-pointer:before {
+  content: "\ea37";
+  font-family: 'jQueryTimeline' !important;
+  position: absolute;
+  top: -8px;
+  left: -7.5px;
+  font-size: 13px;
+  color: #e8383d;
+}
+.timeline-footer {
+  position: relative;
+  top: 50%;
+  width: 100%;
+  z-index: 5;
+}
+.timeline-nav {
+  width: inherit;
+}
+.timeline-to-prev-default, .timeline-to-next-default {
+  width: 2rem;
+  height: 2rem;
+  line-height: 2rem;
+  font-size: 2rem;
+  color: rgba(71,71,71,.325);
+  text-decoration: none;
+}
+.timeline-to-prev-default:hover, .timeline-to-next-default:hover, 
+.timeline-to-prev-default:active, .timeline-to-next-default:active, 
+.timeline-to-prev-default:focus, .timeline-to-next-default:focus {
+  color: rgba(71,71,71,.75);
+  text-decoration: none;
+}
+.timeline-to-prev-custom, .timeline-to-next-custom {
+  width: 2rem;
+  height: 2rem;
+  line-height: 2rem;
+  vertical-align: middle;
+  text-align: center;
+  border-radius: 50%;
+  background-color: rgba(51,51,51,.2);
+  color: #fff;
+  text-decoration: none;
+}
+.timeline-to-prev-custom:hover, .timeline-to-next-custom:hover, 
+.timeline-to-prev-custom:active, .timeline-to-next-custom:active, 
+.timeline-to-prev-custom:focus, .timeline-to-next-custom:focus {
+  background-color: rgba(51,51,51,.3);
+  color: rgba(255,255,255,.75);
+  text-decoration: none;
+}
+/*  */
+.timeline-event-view {
+  display: block;
+  margin: 0 1em;
+}
+.timeline-event-header {
+  margin-top: 0;
+  margin-bottom: 1rem;
+  border-bottom: dotted 1px #a8a8a8;
+}
+.timeline-event-label {
+  font-family: inherit;
+  font-size: 1.75rem;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+.timeline-event-meta {
+  margin-top: 0;
+  margin-bottom: 0.5rem;
+  font-size: 1rem;
+  font-weight: 300;
+}
+.timeline-event-meta:before {
+  content: "\ea60";
+  font-family: 'jQueryTimeline' !important;
+  color: #999;
+  margin-right: 0.5rem;
+}
+.timeline-event-start-date, .timeline-event-end-date {
+  
+}
+.timeline-event-date-separator {
+  display: inline-block;
+}
+.timeline-event-date-separator:after {
+  content: "\301c";
+  color: #777;
+  font-weight: 400;
+  margin-left: 0.5rem;
+  margin-right: 0.5rem;
+}
+.timeline-event-body {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
+.timeline-event-footer {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
diff --git a/src/timeline.org.js b/src/timeline.org.js
new file mode 100644
index 0000000000000000000000000000000000000000..71f137e8d22c9dca11bdb0b64d79b555a1cffcd8
--- /dev/null
+++ b/src/timeline.org.js
@@ -0,0 +1,1662 @@
+/**
+ * JQuery Timeline Plugin Scripts
+ * ------------------------
+ * Version: 1.0.0
+ * Coded by: Ka2 (https://ka2.org/)
+ * Lisenced: MIT
+ */
+;(function( $ ) {
+
+  // Constant values
+  var pluginName   = 'jQuery.Timeline',
+      rowH         = typeof $.timeline.global === 'object' && typeof $.timeline.global.rowH !== 'undefined' ? Number( $.timeline.global.rowH ) : 40,
+      pointMargin  = 2,
+      tlEventAreaH = 0,
+      dft;
+
+  // If the "moment.js" usable
+  if ( $.fn.moment != undefined && typeof $.fn.moment === 'function' ) {
+    dft = moment();
+  }
+
+  var methods = {
+    init : function( options ) {
+      
+      // Default settings
+      var settings = $.extend( {
+        type            : "bar", // View type of timeline event is either "bar" or "point"
+        scale           : "days", // Timetable's top level scale is either "years" or "months" or "days"
+        startDatetime   : "currently", // Default set datetime as viewing timetable; format is ( "^[-+]d{4}(/|-)d{2}(/|-)d{2}\sd{2}:d{2}:d{2}$" ) or "currently"
+//        timelineRange   : { // Begin Datetime and Final Datetime; format is ( "^[-+]d{4}(/|-)d{2}(/|-)d{2}\sd{2}:d{2}:d{2}$" )
+//          from          : "1-01-01 00:00:00",
+//          to            : "9999-12-31 23:59:59"
+//        },
+        datetimePrefix  : "", // The prefix of the date and time notation displayed in the headline
+        showHeadline    : true, // Whether to display headline
+        datetimeFormat  : {
+          full          : "Y/m/d",
+          year          : "Y",
+          month         : "n", // or "F" etc.
+          day           : "n/j" // or "j" etc.
+        },
+        minuteInterval  : 30, // Recommend more than 5 minutes; only if top scale is "days" ; Deprecated
+        zerofillYear    : false, // It's outputted at the "0099" if true, the "99" if false
+        range           : 3, // The default view range of the timetable starting from the `startDatetime`
+        rows            : 5, // Rows of timeline event area
+        height          : "auto", // Fixed height (pixel) of timeline event area; default "auto" is (rows * 40)px
+        minGridPer      : 2, // Minimum grid per
+        minGridSize     : 30, // Minimum size (pixel) of timeline grid; It needs 5 pixels or more
+        rangeAlign      : "current", // Possible values are "left", "center", "right", "current", "latest" and specific event id
+        naviIcon        : { // Define class name
+          left          : "jqtl-circle-left",
+          right         : "jqtl-circle-right"
+        },
+        showPointer     : true
+      }, options);
+      
+      // initialize plugin
+      return this.each(function(){
+        
+        var $this = $(this),
+            data = $this.data('timeline'),
+            timeline = $('<div />', {
+              "title"                 : $this.find('.timeline-headline').text(),
+              "type"                  : settings.type,
+              "scale"                 : settings.scale,
+              "start-datetime"        : settings.startDatetime,
+//              "timeline-range-from"   : settings.timelineRange.from,
+//              "timeline-range-to"     : settings.timelineRange.to,
+              "datetime-prefix"       : settings.datetimePrefix,
+              "show-headline"         : settings.showHeadline ? 1 : 0,
+              "datetime-format-full"  : settings.datetimeFormat.full,
+              "datetime-format-year"  : settings.datetimeFormat.year,
+              "datetime-format-month" : settings.datetimeFormat.month,
+              "datetime-format-day"   : settings.datetimeFormat.day,
+              "minute-interval"       : settings.minuteInterval,
+              "zerofill-year"         : settings.zerofillYear ? 1 : 0,
+              "range"                 : settings.range,
+              "rows"                  : settings.rows,
+              "timeline-height"       : settings.height,
+              "min-grid-per"          : settings.minGridPer,
+              "min-grid-size"         : settings.minGridSize,
+              "range-align"           : settings.rangeAlign,
+              "navi-icon-left"        : settings.naviIcon.left,
+              "navi-icon-right"       : settings.naviIcon.right,
+              "show-pointer"          : settings.showPointer ? 1 : 0,
+              "text"                  : ""
+          });
+        
+        // Set Events
+        //$(window).on( 'resize.timeline', methods.render );
+        $this.on( 'click.timeline', '.timeline-to-prev', methods.dateback );
+        $this.on( 'click.timeline', '.timeline-to-next', methods.dateforth );
+        $this.on( 'click.timeline', '.timeline-node', methods.openEvent );
+        $this.on( 'align.timeline', methods.alignment );
+        
+        // If uninitialized yet
+        if ( ! data ) {
+          
+          $this.data('timeline', {
+            target: $this,
+            timeline : timeline
+          });
+          
+          // Retrive Current Date
+          var currentDt, currentDate, _tmp, _regx;
+          if ( settings.startDatetime === 'currently' ) {
+            currentDt = setCurrentDate( true );
+          } else {
+            currentDt = new Date( settings.startDatetime );
+            _regx = /-|\//;
+            _tmp = settings.startDatetime.split( _regx );
+            if ( Number( _tmp[0] ) < 100 ) {
+              // for 0 - 99 years map
+              currentDt.setFullYear( Number( _tmp[0] ) );
+            }
+          }
+          switch( settings.scale ) {
+            case 'years':
+              currentDate = currentDt.getFullYear() +'-01-01 00:00:00';
+              break;
+            case 'months':
+              currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-01 00:00:00';
+              break;
+            case 'days':
+              currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' 00:00:00';
+              break;
+            default:
+              currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' '+ currentDate.getHours() +':00:00';
+          }
+console.info( currentDt, currentDate );
+          $this.data('timeline').timeline.attr( 'actual-start-datetime', currentDate );
+        
+          renderTimeline( $this );
+          
+          // timeline container sizing
+          resizeTimeline( $this );
+          
+          // do methods.alignment
+          $this.trigger( 'align.timeline', [ settings.rangeAlign ] );
+          
+          $this.css('visibility','visible');
+          
+        }
+        
+// for debug
+        var wait = 0,
+            sleep = setInterval(function() {
+              wait++;
+              if ( wait == 1 ) {
+                placeEvents( $this );
+                clearInterval( sleep );
+              }
+            }, 300);
+        //placeEvents( $this );
+        
+      });
+      
+    },
+    destroy : function( ) {
+      // destroy object
+      return this.each(function(){
+        var $this = $(this),
+          data = $this.data('timeline');
+        
+        $(window).off('.timeline');
+        if ( data ) {
+          data.timeline.remove();
+          $this.removeData('timeline');
+        }
+        
+      });
+    },
+    render : function( options ) {
+      // render timeline object
+      return this.each(function(){
+        var $this = $(this),
+            data = $this.data('timeline');
+        
+        // update options
+        if ( 'type' in options ) {
+          data.timeline.attr( 'type', options.type );
+        }
+        if ( 'scale' in options ) {
+          data.timeline.attr( 'scale', options.scale );
+        }
+        if ( 'startDatetime' in options ) {
+          data.timeline.attr( 'start-datetime', options.startDatetime );
+        }
+/*
+        if ( 'timelineRange' in options ) {
+          if ( typeof options.timelineRange.from != undefined ) {
+            data.timeline.attr( 'timeline-range-from', options.timelineRange.from );
+          }
+          if ( typeof options.timelineRange.to != undefined ) {
+            data.timeline.attr( 'timeline-range-to', options.timelineRange.to );
+          }
+        }
+*/
+        if ( 'datetimePrefix' in options ) {
+          data.timeline.attr( 'datetime-prefix', options.datetimePrefix );
+        }
+        if ( 'showHeadline' in options ) {
+          data.timeline.attr( 'show-headline', options.showHeadline ? 1 : 0 );
+        }
+        if ( 'datetimeFormat' in options ) {
+          if ( typeof options.datetimeFormat.full != undefined ) {
+            data.timeline.attr( 'datetime-format-full', options.datetimeFormat.full );
+          }
+          if ( typeof options.datetimeFormat.year != undefined ) {
+            data.timeline.attr( 'datetime-format-year', options.datetimeFormat.year );
+          }
+          if ( typeof options.datetimeFormat.day != undefined ) {
+            data.timeline.attr( 'datetime-format-day', options.datetimeFormat.day );
+          }
+        }
+        if ( 'minuteInterval' in options ) {
+          data.timeline.attr( 'minute-interval', options.minuteInterval );
+        }
+        if ( 'zerofillYear' in options ) {
+          data.timeline.attr( 'zerofill-year', options.zerofillYear ? 1 : 0 );
+        }
+        if ( 'range' in options ) {
+          data.timeline.attr( 'range', options.range );
+        }
+        if ( 'rows' in options ) {
+          data.timeline.attr( 'rows', options.rows );
+        }
+        if ( 'height' in options ) {
+          data.timeline.attr( 'timeline-height', options.height );
+        }
+        if ( 'minGridPer' in options ) {
+          data.timeline.attr( 'min-grid-per', options.minGridPer );
+        }
+        if ( 'minGridSize' in options ) {
+          data.timeline.attr( 'min-grid-size', options.minGridSize );
+        }
+        if ( 'rangeAlign' in options ) {
+          data.timeline.attr( 'range-align', options.rangeAlign );
+        }
+        if ( 'naviIcon' in options ) {
+          if ( typeof options.naviIcon.left != undefined ) {
+            data.timeline.attr( 'navi-icon-left', options.naviIcon.left );
+          }
+          if ( typeof options.naviIcon.right != undefined ) {
+            data.timeline.attr( 'navi-icon-right', options.naviIcon.right );
+          }
+        }
+        if ( 'showPointer' in options ) {
+          data.timeline.attr( 'show-pointer', options.showPointer ? 1 : 0 );
+        }
+
+        // Retrive current Date
+        var currentDt, currentDate, _tmp, _regx;
+        if ( data.timeline.attr('start-datetime') === 'currently' ) {
+          currentDt = setCurrentDate( true );
+        } else {
+          currentDt = new Date( data.timeline.attr('start-datetime') );
+          _regx = /-|\//;
+          _tmp = data.timeline.attr('start-datetime').split( _regx );
+          if ( Number( _tmp[0] ) < 100 ) {
+            // for 0 - 99 years map
+            currentDt.setFullYear( Number( _tmp[0] ) );
+          }
+        }
+        switch( data.timeline.attr('scale') ) {
+          case 'years':
+            currentDate = currentDt.getFullYear() +'-01-01 00:00:00';
+            break;
+          case 'months':
+            currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-01 00:00:00';
+            break;
+          case 'days':
+            currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' 00:00:00';
+            break;
+          default:
+            currentDate = currentDt.getFullYear() +'-'+ (currentDt.getMonth() + 1) +'-'+ currentDt.getDate() +' '+ currentDate.getHours() +':00:00';
+        }
+        data.timeline.attr( 'actual-start-datetime', currentDate );
+
+console.info( 'Fired "render" method', options, data.timeline );
+        $this.find('.timeline-container').empty().removeClass('timeline-container');
+        renderTimeline( $this );
+        resizeTimeline( $this );
+        placeEvents( $this );
+        
+        // do methods.alignment
+        $this.trigger( 'align.timeline', [ data.timeline.attr('range-align') ] );
+      });
+    },
+    show : function( ) {
+      return this.each(function(){
+        $(this).css('display', 'block').css('visibility', 'visible');
+      });
+    },
+    hide : function( ) {
+      return this.each(function(){
+        $(this).css('visibility', 'hidden').css('display', 'none');
+      });
+    },
+    initialized : function( callback ) {
+      return this.each(function(){
+        var $this = $(this),
+          data = $this.data('timeline');
+        
+        if ( data && typeof callback === 'function' ) {
+          console.info( 'Fired "initialized" method after initialize this plugin.' );
+          callback( $this, data );
+        }
+      });
+    },
+    dateback  : function( evt ) {
+//console.info([ 'Fired "dateback" method', this, evt ]);
+      evt.preventDefault();
+      var $root = $(this).parents('.timeline-container'),
+          data = $root.data('timeline'),
+          visibleTimelineWidth = $root.find('.timeline-body')[0].clientWidth,
+          fullTimelineWidth = $root.find('.timeline-wrapper')[0].scrollWidth,
+          currentTimelinePos = $root.find('.timeline-body').scrollLeft(),
+          mov = 0;
+      if ( fullTimelineWidth > visibleTimelineWidth ) {
+//console.info([ fullTimelineWidth / visibleTimelineWidth, currentTimelinePos, fullTimelineWidth - currentTimelinePos, (currentTimelinePos / visibleTimelineWidth) ]);
+        if ( (currentTimelinePos / visibleTimelineWidth) > 1 ) {
+          mov = currentTimelinePos - visibleTimelineWidth;
+        } else {
+          mov = currentTimelinePos - ((fullTimelineWidth - visibleTimelineWidth) / Number( data.timeline.attr('range') ));
+        }
+        mov = mov < 0 ? 0 : mov;
+        $root.find('.timeline-body').animate( { scrollLeft: mov }, 300 );
+      }
+      return this;
+    },
+    dateforth : function( evt ) {
+//console.info([ 'Fired "dateforth" method', this, evt ]);
+      evt.preventDefault();
+      var $root = $(this).parents('.timeline-container'),
+          data = $root.data('timeline'),
+          visibleTimelineWidth = $root.find('.timeline-body')[0].clientWidth,
+          fullTimelineWidth = $root.find('.timeline-wrapper')[0].scrollWidth,
+          currentTimelinePos = $root.find('.timeline-body').scrollLeft(),
+          mov = 0;
+      if ( fullTimelineWidth > visibleTimelineWidth ) {
+        if ( (fullTimelineWidth - currentTimelinePos) / visibleTimelineWidth > 1 ) {
+          mov = currentTimelinePos + visibleTimelineWidth;
+        } else {
+          mov = currentTimelinePos + ((fullTimelineWidth - visibleTimelineWidth) / Number( data.timeline.attr('range') ));
+        }
+        mov = mov > (fullTimelineWidth - visibleTimelineWidth + 1) ? fullTimelineWidth - visibleTimelineWidth + 1 : mov;
+        $root.find('.timeline-body').animate( { scrollLeft: mov }, 300 );
+      }
+      return this;
+    },
+    alignment : function( ) {
+      var args = arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [ arguments[0] ],
+          control = args[0].toLowerCase(),
+          animateSpeed = typeof args[1] !== 'undefined' ? String( args[1] ).toLowerCase() : 0;
+//console.info([ 'Fired "alignment" method', this, control, animateSpeed ]);
+      var visibleTimelineWidth = $(this).find('.timeline-body')[0].clientWidth, // 表示域
+          fullTimelineWidth = $(this).find('.timeline-wrapper')[0].scrollWidth, // 全長
+          mov = 0; // 初期位置(= left)
+      if ( fullTimelineWidth > visibleTimelineWidth ) { // 表示域より全長が大きい場合(横スクロールが発生する場合)
+        switch ( control ) {
+          case "left":
+            // Move to beginning of timetable range
+            mov = 0;
+            break;
+          case "right":
+            // Move to last of timetable range
+            mov = fullTimelineWidth - visibleTimelineWidth + 1;
+            break;
+          case "center":
+            // Move to central of timetable range
+            mov = (fullTimelineWidth - visibleTimelineWidth) / 2;
+            break;
+          case "current":
+            // Move to nearest current time on timetable (default)
+            var currentDt = setCurrentDate( true ),
+                data      = $(this).data('timeline'),
+                posX      = getAbscissa( currentDt, data );
+            if ( posX > -1 ) {
+              if ( (posX - visibleTimelineWidth / 2) > (fullTimelineWidth - visibleTimelineWidth + 1) ) {
+                mov = fullTimelineWidth - visibleTimelineWidth + 1;
+              } else {
+                mov = posX - visibleTimelineWidth / 2;
+              }
+            } else {
+              mov = fullTimelineWidth - visibleTimelineWidth + 1;
+            }
+            break;
+          case "latest":
+            // Move to latest event on the timetable
+            var data        = $(this).data('timeline'),
+                eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+                diffDt, cur, latestKey, latestDt, posX;
+            $.each( eventNodes, function( i, evt ) {
+              cur = formatDate( 'U', evt.start );
+              if ( i == 0 ) {
+                diffDt = cur;
+                latestKey = i;
+              } else {
+                if ( cur >= diffDt ) {
+                  diffDt = cur;
+                  latestKey = i;
+                }
+              }
+            });
+//console.info([ latestKey, eventNodes[latestKey] ]);
+            latestDt = new Date( eventNodes[latestKey].start ),
+            posX     = getAbscissa( latestDt, data );
+            if ( posX > -1 ) {
+              if ( (posX - visibleTimelineWidth / 2) > (fullTimelineWidth - visibleTimelineWidth + 1) ) {
+                mov = fullTimelineWidth - visibleTimelineWidth + 1;
+              } else {
+                mov = posX - visibleTimelineWidth / 2;
+              }
+            } else {
+              mov = fullTimelineWidth - visibleTimelineWidth + 1;
+            }
+            break;
+          default:
+            // Move to specific event that has targeted id
+            mov = 0;
+            var targetId = '#' + control;
+            if ( $(targetId).length ) {
+              var posX = $(targetId).position().left;
+              if ( (posX - visibleTimelineWidth / 2) > (fullTimelineWidth - visibleTimelineWidth + 1) ) {
+                mov = fullTimelineWidth - visibleTimelineWidth + 1;
+              } else {
+                mov = posX - visibleTimelineWidth / 2;
+              }
+            }
+            break;
+        }
+        if ( $.inArray( animateSpeed, [ "slow", 'normal', 'fast' ] ) != -1 || Number( animateSpeed ) > 0 ) {
+          $(this).find('.timeline-body').animate({ scrollLeft: mov }, animateSpeed);
+        } else {
+          $(this).find('.timeline-body').scrollLeft( mov );
+        }
+      }
+      return this;
+    },
+    getOptions : function( ) {
+      var $this = $(this),
+          data  = $this.data('timeline');
+      return {
+        title          : data.timeline.attr('title'),
+        type           : data.timeline.attr('type'),
+        scale          : data.timeline.attr('scale'),
+        startDatetime  : data.timeline.attr('start-datetime'),
+/*
+        timelineRange  : {
+          from         : data.timeline.attr('timeline-range-from'),
+          to           : data.timeline.attr('timeline-range-to'),
+        },
+*/
+        datetimePrefix : data.timeline.attr('datetime-prefix'),
+        showHeadline   : Number( data.timeline.attr('show-headline') ) == 1 ? true : false,
+        datetimeFormat : {
+          full         : data.timeline.attr('datetime-format-full'),
+          year         : data.timeline.attr('datetime-format-year'),
+          month        : data.timeline.attr('datetime-format-month'),
+          day          : data.timeline.attr('datetime-format-day'),
+        },
+        minuteInterval : Number( data.timeline.attr('minute-interval') ),
+        zerofillYear   : Number( data.timeline.attr('zerofill-year') ) == 1 ? true : false,
+        range          : Number( data.timeline.attr('range') ),
+        rows           : Number( data.timeline.attr('rows') ),
+        height         : data.timeline.attr('timeline-height') === 'auto' ? 'auto' : Number( data.timeline.attr('timeline-height') ),
+        minGridPer     : Number( data.timeline.attr('min-grid-per') ),
+        minGridSize    : Number( data.timeline.attr('min-grid-size') ),
+        rangeAlign     : data.timeline.attr('range-align'),
+        naviIcon       : {
+          left         : data.timeline.attr('navi-icon-left'),
+          right        : data.timeline.attr('navi-icon-right'),
+        },
+        showPointer    : data.timeline.attr('show-pointer'),
+        events         : ( new Function( 'return ' + data.timeline.text() ) )()
+      };
+    },
+    addEvent : function( events, callback ) {
+      return this.each(function(){
+        var $this       = $(this),
+            data        = $this.data('timeline'),
+            eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+            incrementId = 1,
+            _ids        = [ incrementId ];
+        // add events
+        if ( events.length > 0 ) {
+          $.each(eventNodes, function( i, evt ) {
+            _ids.push( Number( evt.eventId ) );
+          });
+          incrementId = Math.max.apply( null, _ids ) + 1;
+          $.each(events, function( i, evt ) {
+            evt['eventId'] = incrementId;
+            incrementId++;
+            eventNodes.push(evt);
+          });
+          data.timeline.text( JSON.stringify( eventNodes ) );
+        }
+        
+        placeEvents( $this );
+        
+        // Alignment to current node
+        $(this).trigger( 'align.timeline', [ 'evt-' + (incrementId - 1), 'fast' ] );
+        
+        if ( data && typeof callback === 'function' ) {
+          console.info( 'Fired "addEvent" method after events addition.' );
+          callback( $this, data );
+        }
+      });
+    },
+    removeEvent : function( ) { // arguments is optional
+      var eventIds, callback;
+      if ( arguments.length == 0 ) {
+        eventIds = 'all';
+        callback = null;
+      } else
+      if ( arguments.length == 1 ) {
+        if ( typeof arguments[0] === 'function' ) {
+          eventIds = 'all';
+          callback = arguments[0];
+        } else {
+          eventIds = arguments[0];
+          callback = null;
+        }
+      } else {
+        eventIds = arguments[0];
+        callback = arguments[1];
+      }
+      return this.each(function(){
+        var $this       = $(this),
+            data        = $this.data('timeline'),
+            eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )();
+        
+        // remove events
+        if ( eventIds === 'all' ) {
+          eventNodes = [];
+        } else {
+          var newEventNodes = [];
+          $.each(eventNodes, function( i, evt ) {
+            if ( $.inArray( evt.eventId, eventIds ) == -1 ) {
+              newEventNodes.push(evt);
+            }
+          });
+          eventNodes = newEventNodes;
+        }
+        data.timeline.text( JSON.stringify( eventNodes ) );
+        
+        placeEvents( $this );
+        
+        if ( data && typeof callback === 'function' ) {
+          console.info( 'Fired "removeEvent" method after events removing.' );
+          callback( $this, data );
+        }
+      });
+    },
+    updateEvent : function( events, callback ) {
+      if ( typeof events === 'undefined' ) {
+        return false;
+      }
+      return this.each(function(){
+        var $this       = $(this),
+            data        = $this.data('timeline'),
+            eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+            _ids        = [],
+            lastUpdated;
+        // update events
+        if ( events.length > 0 ) {
+          $.each( events, function( i, newEvt ) {
+            _ids.push(newEvt.eventId);
+          });
+        }
+        
+        if ( eventNodes.length > 0 && _ids.length > 0 ) {
+          $.each( eventNodes, function( i, evt ) {
+            if ( $.inArray( evt.eventId, _ids ) != -1 ) {
+              var newEvent;
+              $.each( events, function( j, newEvt ) {
+                if ( newEvt.eventId == evt.eventId ) {
+                  newEvent = newEvt;
+                  lastUpdated = newEvt.eventId;
+                  return false;
+                }
+              });
+              eventNodes[i] = newEvent;
+            }
+          });
+          data.timeline.text( JSON.stringify( eventNodes ) );
+        }
+        
+        placeEvents( $this );
+        
+        // Alignment to current node
+        $(this).trigger( 'align.timeline', [ 'evt-' + lastUpdated, 'fast' ] );
+        
+        if ( data && typeof callback === 'function' ) {
+console.info( 'Fired "updateEvent" method after events updating.' );
+          callback( $this, data );
+        }
+      });
+    },
+    openEvent : function( event ) {
+      var eventId         = Number( $(event.target).attr('id').replace('evt-', '') ),
+          currentTimeline = event.delegateTarget;
+      if ( eventId === '' || eventId == 0 ) {
+        return false;
+      }
+      return $(currentTimeline).each(function(){
+        var data       = $(this).data('timeline'),
+            eventNodes = ( new Function( 'return ' + data.timeline.text() ) )(), eventData;
+        $.each( eventNodes, function( i, evt ) {
+          if ( evt.eventId == eventId ) {
+            eventData = evt;
+            return false;
+          }
+        });
+        
+        // Activate focused event
+        $(this).find('.timeline-node').each(function(){
+          if ( $(this).attr('id') === 'evt-' + eventId ) {
+            $(this).addClass('active');
+          } else {
+            $(this).removeClass('active');
+          }
+        });
+        
+        // Alignment to current node
+        $(this).trigger( 'align.timeline', [ 'evt-' + eventId, 'fast' ] );
+        
+        if ( showEvent( eventData ) && eventData.callback ) {
+console.info( 'Fired "openEvent" method after event shown.' );
+          Function.call( null, 'return ' + eventData.callback )();
+          //var callback = Function.call( null, 'return ' + eventData.callback )();
+          //callback.call( eventData );
+        }
+      });
+    }
+  };
+
+  $.fn.timeline = function( method ) {
+    // Dispatcher of Plugin
+    if ( methods[method] ) {
+      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+    } else 
+    if ( typeof method === 'object' || ! method ) {
+      return methods.init.apply( this, arguments );
+    } else {
+      $.error( 'Method ' + method + ' does not exist on jQuery.timeline.' );
+    }
+    
+  };
+
+  function renderTimeline( obj ) {
+    // Rendering timeline view
+    var $this = $(obj), i, _tmp, _regx, 
+        data = $this.data('timeline');
+//console.info([ 'Called "renderTimeline" function', $this, data.timeline ]);
+console.info( data.timeline[0].attributes );
+    
+    _regx = /-|\/|\s|\:/;
+    _tmp = data.timeline.attr('actual-start-datetime').split( _regx );
+    var startDt = new Date( Number( _tmp[0] ), Number( _tmp[1] ) - 1, Number( _tmp[2] ), Number( _tmp[3] ), Number( _tmp[4] ), Number( _tmp[5] ) );
+    if ( Number( _tmp[0] ) < 100 ) {
+      // for 0 - 99 years map
+      startDt.setFullYear( Number( _tmp[0] ) );
+    }
+    
+    var tlHeader = $('<div />', { addClass: "timeline-header" }),
+        tlBody   = $('<div />', { addClass: "timeline-body" }),
+        tlFooter = $('<div />', { addClass: "timeline-footer" }),
+        tlWrapper= $('<div />', { addClass: "timeline-wrapper" }),
+        tlScale  = $('<table />', { addClass: "timeline-timetable timeline-scale" }),
+        tlEvents = $('<div />', { addClass: "timeline-events" }),
+        tlGrids  = $('<table />', { addClass: "timeline-timetable timeline-grids" }),
+        tlPointer= $('<div />', { addClass: "timeline-needle-pointer" }),
+        dfEvents = $('<div />', { addClass: "timeline-events default-events" }),
+        endDt    = new Date( startDt ),
+        scaleSet = {
+          years  : {
+            "medium_scale": "months",
+            "medium_cols": 12,
+            "small_scale": "days",
+            "small_cols": Number( data.timeline.attr('min-grid-per') )
+          },
+          months : {
+            "medium_scale": "days",
+            "medium_cols": new Date( startDt.getFullYear(), startDt.getMonth() + 1, 0 ).getDate(),
+            "small_scale": "hours",
+            "small_cols": Number( data.timeline.attr('min-grid-per') )
+          },
+          days   : {
+            "medium_scale": "hours",
+            "medium_cols": 24,
+            "small_scale": "minutes",
+            "small_cols": Number( data.timeline.attr('min-grid-per') ) // retriveDaysGrid( data.timeline.attr('minute-interval'), data.timeline.attr('min-grid-per') )
+          }
+        },
+        topScale = data.timeline.attr('scale'),
+        midScale = scaleSet[topScale]['medium_scale'],
+        smlScale = scaleSet[topScale]['small_scale'],
+        mediumCellSize = Number( data.timeline.attr( 'min-grid-per' ) ) * Number( data.timeline.attr( 'min-grid-size' ) ),
+        scaleMediumCols = [ scaleSet[topScale]['medium_cols'] ],
+        scaleSmallCols;
+    
+//console.info([ scaleSet.years['small_cols'], scaleSet.months['small_cols'], scaleSet.days['small_cols'] ]);
+    // initialize element
+    if ( ! $this.hasClass('timeline-container') ) {
+      $this.addClass('timeline-container');
+    }
+    if ( $this.find('.timeline-events').length > 0 ) {
+      $this.find('.timeline-events').clone().appendTo( dfEvents );
+      defaultEvents( dfEvents, data );
+    }
+    if ( data.timeline.attr( 'type' ) === 'point' || data.timeline.attr( 'type' ) === 'mixed' ) {
+      var tlLineCanvas = $('<canvas />', { addClass: "timeline-line-canvas" });
+    }
+    $this.empty();
+    
+    // Set endDate
+    if ( data.timeline.attr('scale') === 'years' ) {
+      endDt = new Date( endDt.setFullYear( endDt.getFullYear() + Number( data.timeline.attr('range') ) - 1 ) );
+    } else
+    if ( data.timeline.attr('scale') === 'months' ) {
+      endDt = new Date( endDt.setMonth( endDt.getMonth() + Number( data.timeline.attr('range') ) - 1 ) );
+    } else {
+      endDt = new Date( endDt.setDate( endDt.getDate() + Number( data.timeline.attr('range') ) - 1 ) );
+    }
+//console.info([ startDt, endDt ]);
+    
+    // Set scaleMediumCols
+    if ( midScale === 'days' && Number( data.timeline.attr('range') ) > 1 ) {
+      for ( i = 1; i < Number( data.timeline.attr('range') ); i++ ) {
+         scaleMediumCols.push( new Date( startDt.getFullYear(), startDt.getMonth() + 1 + i, 0 ).getDate() );
+      }
+    } else {
+      for ( i = 1; i < Number( data.timeline.attr('range') ); i++ ) {
+        scaleMediumCols.push( scaleSet[topScale]['medium_cols'] );
+      }
+    }
+    
+    // Create header
+    if ( data.timeline.attr('show-headline') ) {
+      var fromDate, toDate, zf, zt, tlTitle;
+      switch( data.timeline.attr('scale') ) {
+        case "years":
+          zf = zt = '';
+          if ( data.timeline.attr('zerofill-year') == 1 ) {
+            if ( startDt.getFullYear() < 100 ) {
+              zf = '00';
+            } else
+            if ( startDt.getFullYear() < 1000 ) {
+              zf = '0';
+            }
+            if ( endDt.getFullYear() < 100 ) {
+              zt = '00';
+            } else
+            if ( endDt.getFullYear() < 1000 ) {
+              zt = '0';
+            }
+          }
+          fromDate = data.timeline.attr('datetime-prefix') + zf + formatDate( data.timeline.attr('datetime-format-year'), startDt );
+          toDate   = data.timeline.attr('datetime-prefix') + zt + formatDate( data.timeline.attr('datetime-format-year'), endDt );
+          break;
+        case "months":
+          fromDate = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-year') + data.timeline.attr('datetime-format-month'), startDt );
+          toDate   = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-year') + data.timeline.attr('datetime-format-month'), endDt );
+          break;
+        case "days":
+          fromDate = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-full'), startDt );
+          toDate   = data.timeline.attr('datetime-prefix') + formatDate( data.timeline.attr('datetime-format-full'), endDt );
+          break;
+      }
+      tlTitle = '<span class="timeline-from-date">' + fromDate + '</span><span class="timeline-to-date">' + toDate + '</span>';
+      tlHeader.append('<h3 class="timeline-headline">' + tlTitle + '</h3>');
+    }
+    
+    // Create Time Scale
+    var topLevelRow = mediumLevelRow = smallLevelRow = '<tr>',
+        scaleSmallCols = array_sum( scaleMediumCols ) * scaleSet[topScale]['small_cols'],
+        tmpDate, resMod, label;
+    
+    // Stored total cols
+    data.timeline.attr( 'total-cols', scaleSmallCols );
+    
+    // Row of top level time scale
+    for ( i = 0; i < Number( data.timeline.attr('range') ); i++ ) {
+      topLevelRow += '<th colspan="' + ( scaleMediumCols[i] * scaleSet[topScale]['small_cols'] ) + '" class="scale-major scale-' + topScale + '">';
+      tmpDate = new Date( startDt );
+      switch ( topScale ) {
+        case 'years':
+          tmpDate.setFullYear( tmpDate.getFullYear() + i );
+          label = formatDate( data.timeline.attr('datetime-format-year'), tmpDate ); // tmpDate.getFullYear()
+          break;
+        case 'months':
+          tmpDate.setMonth( tmpDate.getMonth() + i );
+          label = formatDate( data.timeline.attr('datetime-format-month'), tmpDate ); // tmpDate.getFullYear() + '/' + ( tmpDate.getMonth() + 1 );
+          break;
+        case 'days':
+          tmpDate.setDate( tmpDate.getDate() + i );
+          label = formatDate( data.timeline.attr('datetime-format-day'), tmpDate ); // ( tmpDate.getMonth() + 1 ) + '/' + tmpDate.getDate();
+          break;
+      }
+      topLevelRow += label + '</th>';
+    }
+    topLevelRow += '</tr>';
+    
+    // Row of medium level time scale
+    for ( i = 0; i < array_sum( scaleMediumCols ); i++ ) {
+      mediumLevelRow += '<th colspan="' + scaleSet[topScale]['small_cols'] + '" class="scale-medium scale-' + midScale + '">';
+      tmpDate = new Date( startDt );
+      switch ( midScale ) {
+        case 'months':
+          resMod = i % scaleSet[topScale]['medium_cols'];
+          label = mediumCellSize < 18 ? '' : resMod + 1;
+          break;
+        case 'days':
+          tmpDate.setDate( tmpDate.getDate() + i );
+          label = mediumCellSize < 20 ? '' : tmpDate.getDate();
+          break;
+        case 'hours':
+          resMod = i % scaleSet[topScale]['medium_cols'];
+          label = mediumCellSize < 40 ? '' : resMod + ':00';
+          break;
+      }
+      mediumLevelRow += label + '</th>';
+    }
+    mediumLevelRow += '</tr>';
+    
+    // Row of small level time scale
+    for ( i = 0; i < scaleSmallCols; i++ ) {
+      smallLevelRow += '<th class="scale-small scale-' + smlScale + '"><span class="spacer-cell"></span></th>';
+    }
+    
+    // Create Timeline grids
+    var tlGridsRow = '<tr>';
+    for ( i = 0; i < scaleSmallCols; i++ ) {
+      tlGridsRow += '<td class="scale-small"><span class="spacer-cell"></span></td>';
+    }
+    tlGridsRow += '</tr>';
+    
+    // Create Timeline needle pointer
+    if ( data.timeline.attr( 'show-pointer' ) == 0 ) {
+      tlPointer.css('display', 'none');
+    } else {
+    	var currentDt = setCurrentDate( true ),
+    	    posX = getAbscissa( currentDt, data );
+    	if ( posX > -1 ) {
+        tlPointer.css('left', posX + 'px');
+      } else {
+        tlPointer.css('display', 'none');
+      }
+    }
+    
+    // Create Timeline loader & Timeline Events
+    var tlLoader = $('<div />', { addClass: "timeline-loader", css: { display: 'block' } });
+    tlLoader.append( '<i class="jqtl-spinner"></i><span class="sr-only">Loading...</span>' );
+    //tlEvents.append( tlLoader.prop('outerHTML') ).css('display','block');
+    
+    // Create Timeline footer
+    var tlFooterNav    = '<div class="timeline-nav">',
+        tlNavLeft      = data.timeline.attr( 'navi-icon-left' ) === '' ? 'jqtl-circle-left' : data.timeline.attr( 'navi-icon-left' ),
+        tlNavRight     = data.timeline.attr( 'navi-icon-right' ) === '' ? 'jqtl-circle-right' : data.timeline.attr( 'navi-icon-right' ),
+        tlNavPrevClass = /^jqtl-circle-.*$/.test( tlNavLeft ) ? 'timeline-to-prev-default' : 'timeline-to-prev-custom',
+        tlNavNextClass = /^jqtl-circle-.*$/.test( tlNavRight ) ? 'timeline-to-next-default' : 'timeline-to-next-custom';
+//console.info([ tlNavLeft, tlNavRight ]);
+    tlFooterNav += '<a href="javascript:void(0);" class="timeline-to-prev ' + tlNavPrevClass + '"><i class="' + tlNavLeft + '"></i></a>';
+    tlFooterNav += '<a href="javascript:void(0);" class="timeline-to-next ' + tlNavNextClass + '"><i class="' + tlNavRight + '"></i></a>';
+    tlFooterNav += '</div>';
+    
+    // Build Elements
+    tlScale.append( '<thead>' + topLevelRow + mediumLevelRow + smallLevelRow + '</thead>' );
+    tlGrids.append( '<tbody>' + tlGridsRow + '</tbody>' );
+    if ( data.timeline.attr( 'type' ) === 'point' || data.timeline.attr( 'type' ) === 'mixed' ) {
+      tlWrapper.append( tlScale.prop('outerHTML') + tlEvents.prop('outerHTML') + tlLineCanvas.prop('outerHTML') + tlGrids.prop('outerHTML') + tlPointer.prop('outerHTML') );
+    } else {
+      tlWrapper.append( tlScale.prop('outerHTML') + tlEvents.prop('outerHTML') + tlGrids.prop('outerHTML') + tlPointer.prop('outerHTML') );
+    }
+    tlBody.append( tlWrapper );
+    tlFooter.append( tlFooterNav );
+    
+    $this.append( tlHeader );
+    $this.append( tlBody );
+    $this.append( tlFooter );
+    $this.append( tlLoader.prop('outerHTML') );
+    
+    return $this;
+  }
+
+  function resizeTimeline( obj ) {
+    // Resizing timeline view
+    var $this = $(obj), i,
+        data = $this.data('timeline');
+
+    if ( data.timeline.attr('timeline-height') === "auto" || typeof data.timeline.attr('timeline-height') !== "number" ) {
+      tlEventAreaH = Number( data.timeline.attr('rows') ) * rowH;
+    } else {
+      tlEventAreaH = Number( data.timeline.attr('timeline-height') );
+    }
+    var timetableSize = {
+      width : $this.find('.timeline-timetable.timeline-scale').outerWidth(),
+      height: 63 // $this.find('.timeline-timetable.timeline-scale').outerHeight() だと正確な値が取れない(bootstrap利用だとOK)(なぜだ!?)
+    };
+    //console.info([ document.getElementsByClassName( 'timeline-scale' )[0].clientHeight, $(document).find('.timeline-timetable:first-child').height(), $this.find('.timeline-timetable:first-child').height(),$this.find('.timeline-timetable:first-child').innerHeight(),$this.find('.timeline-timetable:first-child').outerHeight(),$this.find('.timeline-timetable:first-child').outerHeight(true) ]);
+    //console.info([ timetableSize, $(this).find('.timeline-wrapper').height(), $(this).find('.spacer-cell').width() ]);
+    if ( $this.find('.timeline-wrapper')[0].offsetHeight != timetableSize.height + tlEventAreaH ) {
+      $this.find('.timeline-wrapper').css('height', (timetableSize.height + tlEventAreaH) + 'px');
+      $this.find('.timeline-events').css('height', tlEventAreaH + 'px');
+      $this.find('.timeline-line-canvas').css('height', tlEventAreaH + 'px').attr('width', timetableSize.width).attr('height', tlEventAreaH);
+      $this.find('.timeline-grids').css('height', tlEventAreaH + 'px');
+    }
+    data.timeline.attr('min-grid-size', Number( data.timeline.attr('min-grid-size') ) < 5 ? 30 : Number( data.timeline.attr('min-grid-size') ) );
+    if ( $this.find('.spacer-cell').width() != data.timeline.attr('min-grid-size') - 1 ) {
+      $this.find('.spacer-cell').css('width', (data.timeline.attr('min-grid-size') - 1) + 'px');
+    }
+    
+    // Adjust position of navi icons
+    var basePos     = ( $this.find('.timeline-body').outerHeight() - $this.find('.timeline-scale').outerHeight() ) / 2,
+        navIconH    = $this.find('.timeline-to-prev').outerHeight(),
+        navPosition = -1 * ( basePos + navIconH );
+    $this.find('.timeline-to-prev').css('top', navPosition + 'px');
+    $this.find('.timeline-to-next').css('top', navPosition + 'px');
+    
+    // Set event of scrolling timeline
+    $this.find('.timeline-body').scroll(function(){
+      var currentScrollLeft = $(this).scrollLeft();
+      if ( currentScrollLeft < 1 ) {
+        // Terminated Left
+        $this.find('.timeline-to-prev').hide();
+      } else
+      if ( currentScrollLeft >= (timetableSize.width - $(this).outerWidth() - 2) ) {
+        // Terminated Right
+        $this.find('.timeline-to-next').hide();
+      } else {
+        $this.find('.timeline-to-prev').show();
+        $this.find('.timeline-to-next').show();
+      }
+    });
+    
+    return $this;
+  }
+
+  function defaultEvents( obj, data ) {
+    // Defining default events
+    if ( $(obj).find('.timeline-events').children().length > 0 ) {
+      var eventData = [],
+          eventIds = [],
+          startEventId = 0;
+      $(obj).find('.timeline-events').children().each(function(){
+        if ( $(this).data('timelineNode') ) {
+          var event = ( new Function( 'return ' + $(this).data('timelineNode') ) )();
+          event['label'] = $(this).text();
+          if ( event.eventId ) 
+            eventIds.push( Number( event.eventId ) );
+          eventData.push( event );
+        }
+      });
+      if ( eventData.length > 0 ) {
+        startEventId = eventIds.length > 0 ? Math.max.apply( null, eventIds ) + 1 : startEventId;
+        eventData.forEach(function( evt, i, ary ) {
+          if ( ! evt.eventId ) {
+            ary[i]['eventId'] = startEventId;
+            startEventId++;
+          }
+        });
+        data.timeline.text( JSON.stringify( eventData ) );
+      }
+    }
+    return;
+  }
+
+  function placeEvents( obj ) {
+    // Placing all events
+    var $this       = $(obj),
+        data        = $this.data('timeline'),
+        eventNodes  = ( new Function( 'return ' + data.timeline.text() ) )(),
+        //tlStartDt   = new Date( data.timeline.attr('start-datetime') === 'currently' ? data.timeline.attr('actual-start-datetime') : data.timeline.attr('start-datetime') ),
+        tlStartDt   = new Date( data.timeline.attr('actual-start-datetime') ),
+        tlEndDt     = new Date( tlStartDt ),
+        tlType      = data.timeline.attr('type'),
+        tlScale     = data.timeline.attr('scale'),
+        tlRange     = Number( data.timeline.attr('range') ),
+//        minRangeDt  = new Date( data.timeline.attr('timeline-range-from') ),
+//        maxRangeDt  = new Date( data.timeline.attr('timeline-range-to') ),
+        tlMaxRow    = Number( data.timeline.attr('rows') ),
+        tlTotalCols = Number( data.timeline.attr('total-cols') ),
+        minGridPer  = Number( data.timeline.attr('min-grid-per') ),
+        minGridSize = Number( data.timeline.attr('min-grid-size') ),
+        coordinate  = { x: 0, y: 0, w: 0 },
+        tlWidth     = minGridSize * tlTotalCols - 1;
+    $this.find('.timeline-loader').css( 'display', 'block' );
+    
+    // Updated tlEndDt
+    switch( tlScale ) {
+      case 'years':
+        tlEndDt.setYear( tlEndDt.getFullYear() + tlRange );
+        break;
+      case 'months':
+        tlEndDt.setMonth( tlEndDt.getMonth() + tlRange - 1 );
+        break;
+      case 'days':
+        tlEndDt.setDate( tlEndDt.getDate() + tlRange );
+        break;
+    }
+    
+console.info([ 'placeEvents', data.timeline, eventNodes, tlStartDt, tlEndDt, tlTotalCols, tlWidth ]);
+    $this.find('.timeline-events').empty();
+    eventNodes.forEach(function( evt, i ) {
+      if ( evt.start ) {
+        var evtStartDt = new Date( evt.start ),
+            evtEndDt   = evt.end == undefined ? new Date( evt.start ) : new Date( evt.end ),
+            msMonth    = 30 * 24 * 60 * 60 * 1000, // base value
+            msDay      = 24 * 60 * 60 * 1000,
+            msHour     = 60 * 60 * 1000,
+            gridSize   = minGridPer * minGridSize,
+            tlNodeElm;
+        //if ( isBetweenTo( evtStartDt, minRangeDt, maxRangeDt ) && isBetweenTo( evtStartDt, tlStartDt, tlEndDt ) ) {
+        if ( isBetweenTo( evtStartDt, tlStartDt, tlEndDt ) ) {
+          // イベント開始日時が開始日時がタイムライン表示範囲内の場合
+          switch( tlScale ) {
+            case 'years':
+              coordinate.x = Math.round( ( ( evtStartDt - tlStartDt ) * tlWidth ) / ( tlEndDt - tlStartDt ) );
+              //coordinate.x = Math.floor( ( evtStartDt - tlStartDt ) / msMonth * gridSize );
+              break;
+            case 'months':
+              coordinate.x = Math.floor( ( evtStartDt - tlStartDt ) / msDay * gridSize );
+              break;
+            case 'days':
+              //coordinate.x = Math.round( ( ( evtStartDt - tlStartDt ) * tlWidth ) / ( tlEndDt - tlStartDt ) );
+              coordinate.x = Math.floor( ( evtStartDt - tlStartDt ) / msHour * gridSize );
+              break;
+          }
+          coordinate.y = typeof evt.row !== 'undefined' ? ( evt.row - 1 ) * rowH : 0;
+          if ( isBetweenTo( evtEndDt, tlStartDt, tlEndDt ) ) {
+            // イベント終了日時がタイムライン表示範囲内の場合: イベントブロックの横幅を定義
+            switch( tlScale ) {
+              case 'years':
+                coordinate.w = Math.floor( ( ( evtEndDt - tlStartDt ) / msMonth * gridSize ) - coordinate.x );
+                break;
+              case 'months':
+                coordinate.w = Math.floor( ( ( evtEndDt - tlStartDt ) / msDay * gridSize ) - coordinate.x );
+                break;
+              case 'days':
+                //coordinate.w = Math.round( ( ( evtEndDt - tlStartDt ) * tlWidth ) / ( tlEndDt - tlStartDt ) ) - coordinate.x;
+                coordinate.w = Math.floor( ( ( evtEndDt - tlStartDt ) / msHour * gridSize ) - coordinate.x );
+                break;
+            }
+            if ( coordinate.w == 0 ) {
+              coordinate.w = 1;
+            }
+          } else {
+            // イベント終了日時がタイムライン表示範囲を超える場合: イベントブロックの横幅をタイムライン表示域最大で定義
+            switch( tlScale ) {
+              case 'years':
+                coordinate.w = Math.floor( ( ( tlEndDt - tlStartDt ) / msMonth * gridSize ) - coordinate.x );
+                break;
+              case 'months':
+                coordinate.w = Math.floor( ( ( tlEndDt - tlStartDt ) / msDay * gridSize ) - coordinate.x );
+                break;
+              case 'days':
+                coordinate.w = Math.floor( ( ( tlEndDt - tlStartDt ) / msHour * gridSize ) - coordinate.x );
+                break;
+            }
+          }
+        } else
+        if ( isBetweenTo( evtEndDt, tlStartDt, tlEndDt ) ) {
+        //if ( isBetweenTo( evtEndDt, minRangeDt, maxRangeDt ) && isBetweenTo( evtEndDt, tlStartDt, tlEndDt ) ) {
+          // イベント終了日時がタイムライン表示範囲内の場合
+          coordinate.x = 0;
+          coordinate.y = typeof evt.row !== 'undefined' ? ( evt.row - 1 ) * rowH : 0;
+          switch( tlScale ) {
+            case 'years':
+              coordinate.w = Math.floor( ( evtEndDt - tlStartDt ) / msMonth * gridSize );
+              break;
+            case 'months':
+              coordinate.w = Math.floor( ( evtEndDt - tlStartDt ) / msDay * gridSize );
+              break;
+            case 'days':
+              coordinate.w = Math.floor( ( evtEndDt - tlStartDt ) / msHour * gridSize );
+              break;
+          }
+        } else
+        if ( isBetweenTo( tlStartDt, evtStartDt, evtEndDt ) && isBetweenTo( tlEndDt, evtStartDt, evtEndDt ) ) {
+          // イベント期間内にタイムライン表示範囲が含まれる場合(長期間の帯イベント用)
+          coordinate.x = 0;
+          coordinate.y = typeof evt.row !== 'undefined' ? ( evt.row - 1 ) * rowH : 0;
+          switch( tlScale ) {
+            case 'years':
+              coordinate.w = Math.floor( ( tlEndDt - tlStartDt ) / msMonth * gridSize );
+              break;
+            case 'months':
+              coordinate.w = Math.floor( ( tlEndDt - tlStartDt ) / msDay * gridSize );
+              break;
+            case 'days':
+              coordinate.w = Math.floor( ( tlEndDt - tlStartDt ) / msHour * gridSize );
+              break;
+          }
+        } else {
+          coordinate.w = 0;
+        }
+console.info([ coordinate.x, coordinate.y, coordinate.w, evtStartDt, evtEndDt, evt.eventId ]);
+        if ( coordinate.w > 0 ) {
+          if ( tlType === 'point' ) {
+            // For event view type: point
+            var margin = evt.margin ? Number( evt.margin ) : pointMargin;
+            margin = margin < 0 ? 0 : margin; 
+            margin = margin > (rowH / 2) ? (rowH / 2) - 1 : margin;
+            tlNodeElm = $('<div />', {
+              addClass: 'timeline-node timeline-event-pointer',
+              id: 'evt-' + evt.eventId,
+              css: {
+                left  : coordinate.x - Math.floor(rowH / 2) + margin + 'px',
+                top   : coordinate.y + margin + 'px',
+                width : rowH - (margin * 2) + 'px',
+                height: rowH - (margin * 2) + 'px'
+              },
+              title: evt.label
+            });
+            if ( evt.bdColor ) {
+              tlNodeElm.css('border-color', evt.bdColor );
+            } else 
+            if ( evt.bgColor ) {
+              tlNodeElm.css('border-color', evt.bgColor );
+            }
+            if ( evt.image ) {
+              tlNodeElm.css('background-image', 'url(' + evt.image +')');
+            }
+            if ( evt.relation ) {
+              $.each(evt.relation, function( key, value ) {
+                if ( $.inArray( key, [ 'before', 'after', 'size' ] ) != -1 && ! isNaN( value ) ) {
+                  tlNodeElm.attr( 'data-relay-' + key, Number( value ) );
+                } else
+                if ( key === 'curve' ) {
+                  if ( $.inArray( value, [ 'lt', 'rt', 'lb', 'rb' ] ) != -1 ) {
+                    tlNodeElm.attr( 'data-relay-curve', value );
+                  }
+                } else {
+                  tlNodeElm.attr( 'data-relay-' + key, value );
+                }
+              });
+            }
+          } else {
+            // For event view type: bar
+            tlNodeElm = $('<div />', {
+              addClass: 'timeline-node timeline-text-truncate',
+              id: 'evt-' + evt.eventId,
+              css: {
+                left  : coordinate.x + 'px',
+                top   : coordinate.y + 'px',
+                width : coordinate.w + 'px'
+              },
+              text: evt.label
+            });
+            if ( evt.color ) {
+              tlNodeElm.css('color', evt.color );
+            }
+            if ( coordinate.w < minGridSize ) {
+              tlNodeElm.css('padding-left', '1.5rem').css('padding-right', '0').css('text-overflow', 'clip');
+            }
+          }
+          if ( evt.bgColor ) {
+            tlNodeElm.css('background-color', evt.bgColor );
+          }
+          if ( evt.extend ) {
+            $.each(evt.extend, function( key, value ) {
+              tlNodeElm.attr( 'data-' + key, value );
+            });
+          }
+          $this.find('.timeline-events').append( tlNodeElm.prop('outerHTML') );
+        }
+      }
+      // End of forEach
+    });
+    $this.find('.timeline-loader').css( 'display', 'none' );
+    
+    if ( tlType === 'point' || tlType === 'mixed' ) {
+      drowRelationLine( $this );
+
+      // Set event of hovering event-node (point type)
+      $this.find('.timeline-event-pointer').hover(function(e){
+        var defaultAxis;
+        if ( e.type === 'mouseenter' ) {
+          defaultAxis = { left: parseInt( $(this).css('left') ), top: parseInt( $(this).css('top') ), width: parseInt( $(this).css('width') ), height: parseInt( $(this).css('height') ) };
+          $(this).attr( 'data-default-axis', JSON.stringify( defaultAxis ) );
+          // on hover action
+          if ( ! $(this).hasClass('hovered') ) {
+            $(this).addClass('hovered').animate({ left: defaultAxis.left - rowH/10, top: defaultAxis.top - rowH/10, width: defaultAxis.width + rowH/10*2, height: defaultAxis.height + rowH/10*2 },0);
+          }
+        } else
+        if ( e.type === 'mouseleave' ) {
+          defaultAxis = $(this).data( 'defaultAxis' );
+          $(this).css('left', defaultAxis.left + 'px').css('top', defaultAxis.top + 'px').css('width', defaultAxis.width + 'px').css('height', defaultAxis.height + 'px');
+          $(this).removeAttr( 'data-default-axis' );
+          // off hover action
+          if ( $(this).hasClass('hovered') ) {
+            $(this).removeClass('hovered');
+          }
+        }
+      });
+    
+    }
+  }
+
+  function drowRelationLine( obj ) {
+    var events   = obj.find('.timeline-node.timeline-event-pointer'),
+        relayMap = {},
+        canvas   = obj.find('.timeline-line-canvas')[0],
+        ctx;
+    if ( ! canvas.getContext ) {
+      return;
+    }
+    ctx = canvas.getContext('2d');
+    // Get data for drawing and draw line
+    events.each(function(){
+//console.log( $(this) );
+      var lineColor = $(this).data('relayLinecolor') == undefined ? $(this).css('border-left-color') : $(this).data('relayLinecolor'),
+          lineSize  = $(this).data('relayLinesize') == undefined ? Math.round(rowH/10) : $(this).data('relayLinesize'),
+          targetId, selfPoint, startPoint, endPoint, cv, controlPoint, diffRow;
+      // initialize
+      ctx.strokeStyle = lineColor;
+      ctx.lineWidth   = lineSize;
+      ctx.lineJoin    = 'round';
+      ctx.lineCap = 'round';
+      cv = {
+        x: (rowH - ctx.lineWidth) / 2,
+        y: rowH / 2
+      };
+      selfPoint = {
+        x: $(this)[0].offsetLeft + cv.x,
+        y: Math.floor( $(this)[0].offsetTop / rowH ) * rowH + cv.y
+      };
+      
+      // Draw lines
+      if ( $(this).data('relayBefore') != undefined ) {
+        // Draw from before-event to myself
+        if ( $(this).data('relayBefore') > 0 ) {
+          startPoint = {
+            x: $('#evt-' + $(this).data('relayBefore'))[0].offsetLeft + cv.x,
+            y: Math.floor( $('#evt-' + $(this).data('relayBefore'))[0].offsetTop / rowH ) * rowH + cv.y
+          };
+        } else {
+          startPoint = { x: 0, y: selfPoint.y };
+        }
+        diffRow = ( startPoint.y - selfPoint.y ) / rowH;
+        if ( Math.abs( diffRow ) > 0 && $(this).data('relayCurve') != undefined && $.inArray( $(this).data('relayCurve'), [ 'lt', 'rt', 'lb', 'rb' ] ) != -1 ) {
+          drawLine( startPoint, selfPoint, $(this).data('relayCurve') );
+        } else {
+          drawLine( startPoint, selfPoint );
+        }
+      }
+      if ( $(this).data('relayAfter') != undefined ) {
+        // Draw from myself to after-event
+        if ( $(this).data('relayAfter') > 0 ) {
+          endPoint = {
+            x: $('#evt-' + $(this).data('relayAfter'))[0].offsetLeft + cv.x,
+            y: Math.floor( $('#evt-' + $(this).data('relayAfter'))[0].offsetTop / rowH ) * rowH + cv.y
+          };
+        } else {
+          endPoint = { x: canvas.width, y: selfPoint.y };
+        }
+        diffRow = ( selfPoint.y - endPoint.y ) / rowH;
+        if ( Math.abs( diffRow ) > 0 && $(this).data('relayCurve') != undefined && $.inArray( $(this).data('relayCurve'), [ 'lt', 'rt', 'lb', 'rb' ] ) != -1 ) {
+          drawLine( selfPoint, endPoint, $(this).data('relayCurve') );
+        } else {
+          drawLine( selfPoint, endPoint );
+        }
+      }
+      
+    });
+    
+    function drawLine( start, end, curve ) {
+      if ( typeof start !== 'object' || typeof end !== 'object' ) {
+        return;
+      }
+      curve = curve || false;
+      var diff = { x: Math.abs( (start.x - end.x) / rowH ), y:Math.abs( (start.y - end.y) / rowH ) };
+      ctx.beginPath();
+      ctx.moveTo( start.x, start.y );
+      if ( curve !== false ) {
+        switch ( curve ) {
+          case 'lt':
+            controlPoint = {
+              relayStartX: start.x, 
+              relayStartY: end.y + rowH,
+              cpx: start.x,
+              cpy: end.y,
+              relayEndX: start.x + rowH,
+              relayEndY: end.y
+            };
+            break;
+          case 'rt':
+            controlPoint = {
+              relayStartX: end.x - rowH,
+              relayStartY: start.y,
+              cpx: end.x,
+              cpy: start.y,
+              relayEndX: end.x,
+              relayEndY: start.y + rowH
+            };
+            break;
+          case 'lb':
+            controlPoint = {
+              relayStartX: start.x,
+              relayStartY: end.y - rowH,
+              cpx: start.x,
+              cpy: end.y,
+              relayEndX: start.x + rowH,
+              relayEndY: end.y
+            };
+            break;
+          case 'rb':
+            controlPoint = {
+              relayStartX: end.x - rowH,
+              relayStartY: start.y,
+              cpx: end.x,
+              cpy: start.y,
+              relayEndX: end.x,
+              relayEndY: start.y - rowH
+            };
+            break;
+        }
+        if ( diff.x > 1 || diff.y > 1 ) {
+          ctx.lineTo( controlPoint.relayStartX, controlPoint.relayStartY );
+        }
+        ctx.quadraticCurveTo( controlPoint.cpx, controlPoint.cpy, controlPoint.relayEndX, controlPoint.relayEndY );
+      }
+      ctx.lineTo( end.x, end.y );
+      ctx.stroke();
+    }
+
+  }
+
+  function showEvent( eventData ) {
+    if ( $('.timeline-event-view').length == 0 ) {
+      return true;
+    }
+console.info( eventData );
+    $('.timeline-event-view').empty();
+    var tlevHeader = $('<div />', { addClass: "timeline-event-header" }),
+        tlevLabel  = $('<h3 />',  { addClass: "timeline-event-label" }),
+        tlevMeta   = $('<div />', { addClass: "timeline-event-meta" }),
+        tlevBody   = $('<div />', { addClass: "timeline-event-body" }),
+        tlevFooter = $('<div />', { addClass: "timeline-event-footer" }),
+        temp;
+    tlevLabel.text( eventData.label );
+    temp =  '<span class="timeline-event-start-date">' + formatDate( 'Y/m/d H:i', eventData.start ) + '</span>';
+    if ( eventData.end ) {
+      temp += '<span class="timeline-event-date-separator"></span>';
+      temp += '<span class="timeline-event-end-date">' + formatDate( 'Y/m/d H:i', eventData.end ) + '</span>';
+    }
+    tlevHeader.append( tlevLabel.prop('outerHTML') + tlevMeta.append( temp ).prop('outerHTML') );
+    if ( eventData.content ) {
+      tlevBody.html( eventData.content );
+    }
+    
+    $('.timeline-event-view').append( tlevHeader.prop('outerHTML') + tlevBody.prop('outerHTML') + tlevFooter.prop('outerHTML') );
+    
+    return true;
+  }
+
+  var retriveServerDate = function( ) {
+    // Retrive datetime from server
+    return $.ajax({
+      type: 'GET'
+    }).done(function(d,s,xhr){
+      $('body').data('serverDate', new Date(xhr.getResponseHeader('Date')));
+    }).promise();
+  };
+
+  function setCurrentDate( fromServer ) {
+    // Setting currently datetime
+    var currentDate = new Date();
+    if ( fromServer ) {
+      retriveServerDate().then(function() {
+        currentDate = $('body').data('serverDate');
+        $.removeData('body', 'serverDate');
+      }, function() {
+        currentDate = new Date();
+      });
+    }
+    return currentDate;
+  }
+  
+  function isBetweenTo( targetDate, beginDate, endDate ) {
+    // Determine whether the specified date and time is within range
+    var targetDt = new Date( targetDate ).getTime(),
+        beginDt  = new Date( beginDate ).getTime(),
+        endDt    = new Date( endDate ).getTime();
+    return targetDt - beginDt >= 0 && endDt - targetDt >= 0;
+  }
+  
+  function getAbscissa( targetDt, dataObject ) {
+    var targetDt    = Object.prototype.toString.call( targetDt ) === '[object Date]' ? targetDt : new Date( targetDt ),
+        data        = dataObject.timeline,
+        //justify     = $.inArray( justify.toLowerCase(), [ 'left', 'center' ] ) != -1 ? justify.toLowerCase() : 'center',
+        startDt     = new Date( data.attr('actual-start-datetime') ),
+        endDt       = new Date( startDt ),
+        scale       = data.attr('scale'),
+        range       = Number( data.attr('range') ),
+        tlTotalCols = Number( data.attr('total-cols') ),
+        minGridPer  = Number( data.attr('min-grid-per') ),
+        minGridSize = Number( data.attr('min-grid-size') ),
+        tlWidth     = minGridSize * tlTotalCols - 1,
+        msDay       = 24 * 60 * 60 * 1000,
+        msHour      = 60 * 60 * 1000,
+        gridSize    = minGridPer * minGridSize,
+        posX;
+    // Set end datetime
+    switch ( scale ) {
+      case 'years':
+        endDt = new Date( endDt.setFullYear( endDt.getFullYear() + range - 1 ) );
+        break;
+      case 'months':
+        endDt = new Date( endDt.setMonth( endDt.getMonth() + range - 1 ) );
+        break;
+      case 'days':
+        endDt = new Date( endDt.setDate( endDt.getDate() + range - 1 ) );
+        break;
+    }
+    if ( isBetweenTo( targetDt, startDt, endDt ) ) {
+      switch ( scale ) {
+        case 'years':
+          posX = Math.round( ( ( targetDt - startDt ) * tlWidth ) / ( endDt - startDt ) );
+          break;
+        case 'months':
+          posX = Math.floor( ( targetDt - startDt ) / msDay * gridSize );
+          break;
+        case 'days':
+          posX = Math.floor( ( targetDt - startDt ) / msHour * gridSize );
+          break;
+      }
+      return posX;
+    } else {
+      return false;
+    }
+  }
+  
+  function retriveDaysGrid( minuteInterval, minGridPer ) {
+    // Deprecated
+    if ( minGridPer == 30 ) {
+      return Math.floor( 60 / Number( minuteInterval ) );
+    } else {
+      return Number( minGridPer );
+    }
+  }
+  
+  function array_sum( ary ) {
+    // Sum all values in array
+    return ary.reduce(function( prev, current, i, ary ) {
+      return prev + current;
+    });
+  }
+  
+  function object_values( obj ) {
+    // Return array of values in object
+    var r = [];
+    for( var k in obj ) {
+      if ( obj.hasOwnProperty( k ) ) {
+        r.push( obj[k] );
+      }
+    }
+    return r;
+  }
+  
+  function object_keys( obj ) {
+    // Return array of keys in object
+    var r = [];
+    for ( var k in obj ) {
+      if ( obj.hasOwnProperty( k ) ) {
+        r.push( k );
+      }
+    }
+    return r;
+  }
+  
+  function zerofill( num, digit ) {
+    // Return numeric string with zero-fill the specific upper digits
+    var strDuplicate = function( n, str ) {
+          return Array( n + 1 ).join( str );
+        },
+        zero = strDuplicate( digit - 1, '0' );
+    return String( num ).length == digit ? num : ( zero + num ).substr( num * -1 );
+  }
+  
+  function formatDate( format, date ) {
+    // Date format like PHP
+    var baseDt  = Object.prototype.toString.call( date ) === '[object Date]' ? date : new Date( date ),
+        month   = { 'Jan': 'January', 'Feb': 'February', 'Mar': 'March', 'Apr': 'April', 'May': 'May', 'Jun': 'June', 'Jul': 'July', 'Aug': 'August', 'Sep': 'September', 'Oct': 'October', 'Nov': 'November', 'Dec': 'December' },
+        day     = { 'Sun': 'Sunday', 'Mon': 'Monday', 'Tue': 'Tuesday', 'Wed': 'Wednesday', 'Thu': 'Thurseday', 'Fri': 'Friday', 'Sat': 'Saturday' },
+        ma      = [ 'am', 'pm' ],
+        formatStrings = format.split(''),
+        converted = '',
+        esc = false,
+        lastDayOfMonth = function( dateObj ) {
+          var _tmp = new Date( dateObj.getFullYear(), dateObj.getMonth() + 1, 1 );
+          _tmp.setTime( _tmp.getTime() - 1 );
+          return _tmp.getDate();
+        },
+        isLeapYear = function( dateObj ) {
+          var _tmp = new Date( dateObj.getFullYear(), 0, 1 ),
+              sum  = 0, i;
+          for ( i = 0; i < 12; i++ ) {
+            _tmp.setMonth(i);
+            sum += lastDayOfMonth( _tmp );
+          }
+          return ( sum === 365 ) ? 0 : 1;
+        },
+        dateCount = function( dateObj ) {
+          var _tmp = new Date( dateObj.getFullYear(), 0, 1 ),
+              sum = 0, i;
+          for ( i=0; i<dateObj.getMonth(); i++ ) {
+            _tmp.setMonth(i);
+            sum += lastDayOfMonth( _tmp );
+          }
+          return sum + dateObj.getDate();
+        },
+        half_hours = function( dateObj ) {
+          var h = dateObj.getHours();
+          return h > 12 ? h - 12 : h;
+        },
+        ampm = function( dateObj ) {
+          var h = dateObj.getHours();
+          return h > 12 ? ma[1] : ma[0];
+        };
+
+    if ( format === '' ) {
+      return baseDt;
+    }
+
+    // localize
+    if ( typeof $.timeline.global === 'object' ) {
+      month = typeof $.timeline.global.month === 'object' ? $.timeline.global.month : month;
+      day   = typeof $.timeline.global.day   === 'object' ? $.timeline.global.day   : day;
+      ma    = typeof $.timeline.global.ma    === 'object' ? $.timeline.global.ma    : ma;
+    }
+
+    formatStrings.forEach( function( str, i ) {
+      var res, tmp, sign;
+      if ( esc === false ) {
+        switch( str ) {
+          case 'Y': // Full year | ruby %Y
+          case 'o': // Full year (ISO-8601)
+            res = baseDt.getFullYear();
+            break;
+          case 'y': // Two digits year | ruby %y
+            res = ('' + baseDt.getFullYear()).slice(-2);
+            break;
+          case 'm': // Zerofill month (01-12) | ruby %m
+            res = ('0' + (baseDt.getMonth() + 1)).slice(-2);
+            break;
+          case 'n': // Month
+            res = baseDt.getMonth() + 1;
+            break;
+          case 'F': // Full month name | ruby %B
+            res = object_values( month )[baseDt.getMonth()];
+            break;
+          case 'M': // Short month name | ruby %b
+            res = object_keys( month )[baseDt.getMonth()];
+            break;
+          case 'd': // Zerofill day (01-31) | ruby %d
+            res = ('0' + baseDt.getDate()).slice(-2);
+            break;
+          case 'j': // Day
+            res = baseDt.getDate();
+            break;
+          case 'S': // Day with suffix
+            var suffix = [ 'st', 'nd', 'rd', 'th' ],
+                suffix_index = function(){
+                  var d = baseDt.getDate();
+                  if ( d == 1 || d == 2 || d == 3 || d == 21 || d == 22 || d == 23 || d == 31 ) {
+                    return Number( ('' + d).slice(-1) - 1 );
+                  } else {
+                    return 3;
+                  }
+                };
+            res = suffix[suffix_index()];
+            break;
+          case 'w': // Day of the week (number) | ruby %w
+          case 'W': // Day of the week (ISO-8601 number)
+            res = baseDt.getDay();
+            break;
+          case 'l': // Day of the week (full) | ruby %A
+            res = object_values( day )[baseDt.getDay()];
+            break;
+          case 'D': // Day of the week (short) | ruby %a
+            res = object_keys( day )[baseDt.getDay()];
+            break;
+          case 'N': // Day of the week (ISO-8601 number)
+            res = baseDt.getDay() === 0 ? 7 : baseDt.getDay();
+            break;
+          case 'a': // am or pm
+            res = ampm(baseDt);
+            break;
+          case 'A': // AM or PM
+            res = ampm(baseDt).toUpperCase();
+            break;
+          case 'g': // Half hours (1-12)
+            res = half_hours( baseDt );
+            break;
+          case 'h': // Zerofill half hours (01-12) | ruby %I
+            res = ('0' + half_hours(baseDt)).slice(-2);
+            break;
+          case 'G': // Full hours (0-23)
+            res = baseDt.getHours();
+            break;
+          case 'H': // Zerofill full hours (00-23) | ruby %H
+            res = ('0' + baseDt.getHours()).slice(-2);
+            break;
+          case 'i': // Zerofill minutes (00-59) | ruby %M
+            res = ('0' + baseDt.getMinutes()).slice(-2);
+            break;
+          case 's': // Zerofill seconds (00-59) | ruby %S
+            res = ('0' + baseDt.getSeconds()).slice(-2);
+            break;
+          case 'z': // Day of the year (1-366) | ruby %j
+            res = dateCount( baseDt );
+            break;
+          case 't': // Days of specific month
+            res = lastDayOfMonth( baseDt );
+            break;
+          case 'L': // Whether a leap year
+            res = isLeapYear( baseDt );
+            break;
+          case 'c': // Date of ISO-8601
+            tmp = baseDt.getTimezoneOffset();
+            tzo = [ Math.floor( Math.abs( tmp ) / 60 ), Math.abs( tmp ) % 60 ];
+            sign = tmp < 0 ? '+' : '-';
+            res  = baseDt.getFullYear() +'-'+ zerofill( baseDt.getMonth() + 1, 2 ) +'-'+ zerofill( baseDt.getDate(), 2 ) +'T';
+            res += zerofill( baseDt.getHours(), 2 ) +':'+ zerofill( baseDt.getMinutes(), 2 ) +':'+ zerofill( baseDt.getSeconds(), 2 );
+            res += sign + zerofill( tzo[0], 2 ) +':'+ zerofill( tzo[1], 2 );
+            break;
+          case 'r': // Date of RFC-2822
+            tmp = baseDt.getTimezoneOffset();
+            tzo = [ Math.floor( Math.abs( tmp ) / 60 ), Math.abs( tmp ) % 60 ];
+            sign = tmp < 0 ? '+' : '-';
+            res  = object_keys( day )[baseDt.getDay()] +', '+ baseDt.getDate() +' '+ object_keys( month )[baseDt.getMonth()] +' '+ baseDt.getFullYear() +' ';
+            res += zerofill( baseDt.getHours(), 2 ) +':'+ zerofill( baseDt.getMinutes(), 2 ) +':'+ zerofill( baseDt.getSeconds(), 2 ) +' ';
+            res += sign + zerofill( tzo[0], 2 ) + zerofill( tzo[1], 2 );
+            break;
+          case 'u': // Millisecond
+            res = baseDt.getTime();
+            break;
+          case 'U': // Unix Epoch seconds
+            res = Date.parse( baseDt ) / 1000;
+            break;
+          case "\\": // escape
+            esc = true;
+            res = formatStrings[i + 1];
+            break;
+          default:
+            res = str;
+            break;
+        }
+        converted += res;
+      } else {
+        esc = false;
+        return true;
+      }
+    });
+    return converted;
+  }
+  
+  
+})( jQuery );
\ No newline at end of file
diff --git a/src/timeline.scss b/src/timeline.scss
new file mode 100644
index 0000000000000000000000000000000000000000..9ebbcf22a9497d6cf65b69e118dcf8f8e4dd1b26
--- /dev/null
+++ b/src/timeline.scss
@@ -0,0 +1,449 @@
+@charset "UTF-8";
+/**
+ * JQuery Timeline Plugin Styles
+ * ------------------------
+ * Version: 1.0.0
+ * Coded by: ka2 (https://ka2.org/)
+ * Lisenced: MIT
+ */
+@font-face {
+  font-family: 'jQueryTimeline';
+  src:  url('fonts/jQueryTimeline.eot?t4qpol');
+  src:  url('fonts/jQueryTimeline.eot?t4qpol#iefix') format('embedded-opentype'),
+    url('fonts/jQueryTimeline.ttf?t4qpol') format('truetype'),
+    url('fonts/jQueryTimeline.woff?t4qpol') format('woff'),
+    url('fonts/jQueryTimeline.svg?t4qpol#jQueryTimeline') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+[class^="jqtl-"], [class*=" jqtl-"] {
+  /* use !important to prevent issues with browser extensions that change fonts */
+  font-family: 'jQueryTimeline' !important;
+  speak: none;
+  font-style: normal;
+  font-weight: normal;
+  font-variant: normal;
+  text-transform: none;
+  line-height: 1;
+
+  /* Better Font Rendering =========== */
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.jqtl-pushpin:before {
+  content: "\ea37";
+}
+.jqtl-calendar:before {
+  content: "\ea60";
+}
+.jqtl-spinner:before {
+  content: "\eb24";
+}
+.jqtl-more:before {
+  content: "\ec5b";
+}
+.jqtl-more-horizontal:before {
+  content: "\ec5c";
+}
+.jqtl-more-vertical:before {
+  content: "\ec6a";
+}
+.jqtl-dot:before {
+  content: "\ec6b";
+}
+.jqtl-plus:before {
+  content: "\ed5d";
+}
+.jqtl-minus:before {
+  content: "\ed5e";
+}
+.jqtl-cross:before {
+  content: "\ed6d";
+}
+.jqtl-circle-right:before {
+  content: "\edee";
+}
+.jqtl-circle-left:before {
+  content: "\edf2";
+}
+.jqtl-circle-fill-right:before {
+  content: "\edf6";
+}
+.jqtl-circle-fill-left:before {
+  content: "\edfa";
+}
+.jqtl-arrow-down:before {
+  content: "\ee29";
+}
+*, ::after, ::before {
+  box-sizing: border-box;
+}
+.timeline-container {
+  position: relative;
+  display: block;
+  visibility: hidden;
+  margin: 15px;
+  font-size: 1rem;
+  line-height: 1.5;
+}
+.timeline-header {
+  text-align: left;
+}
+.timeline-headline {
+  margin-top: 0;
+  margin-bottom: .5rem;
+  font-family: inherit;
+  font-size: 1.3rem;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+.timeline-from-date, .timeline-to-date {
+  margin-right: .3rem;
+}
+.timeline-from-date:before {
+  content: "\ea60";
+  font-family: 'jQueryTimeline' !important;
+  margin-right: .3rem;
+  color: #7f7f7f;
+  font-weight: 400;
+}
+.timeline-to-date:before {
+  content: "\301C";
+  margin-right: .3rem;
+  color: #7f7f7f;
+  font-weight: 400;
+}
+.timeline-body {
+  position: relative;
+  display: block;
+  margin: 0 auto;
+  width: inherit;
+  overflow-x: auto;
+  overflow-y: hidden;
+  text-align: center;
+  z-index: 1;
+}
+.timeline-wrapper {
+  position: relative;
+  display: inline-block;
+  margin: 0 1px;
+  width: auto;
+  height: 259px; /* default: index-table(59px) + timeline-grid(200px)  */
+}
+.timeline-wrapper:before, .timeline-wrapper:after {
+  content: "";
+  position: absolute;
+  top: 0;
+  width: 1px;
+  height: 100%;
+}
+.timeline-wrapper:before {
+  left: 0;
+  border-left: 1px solid #ddd;
+}
+.timeline-wrapper:after {
+  right: 0;
+  border-right: 1px solid #ddd;
+}
+.timeline-timetable {
+  display: table;
+  position: relative;
+  border-collapse: collapse;
+  border-spacing: 0;
+  border-color: #ddd;
+  border-top: 1px solid #ddd;
+  border-right: 0;
+  border-bottom: 1px solid #ddd;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th {
+  border: 0;
+}
+.timeline-timetable>thead>tr>th.scale-major {
+  padding-top: 4px;
+  padding-bottom: 4px;
+  font-size: 100%;
+  color: #555;
+  text-align: center;
+  border-top: 0;
+  border-right: 1px solid #ddd;
+  border-bottom: 0;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th.scale-medium {
+  /* width: calc( 100% / 24 ); */
+  padding-top: 0;
+  padding-bottom: 4px;
+  font-size: 85%;
+  color: #777;
+  text-align: center;
+  border-top: 0;
+  border-right: 1px solid #ddd;
+  border-bottom: 0;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th.scale-major:last-child, 
+.timeline-timetable>thead>tr>th.scale-medium:last-child {
+  border-right: 0;
+}
+.timeline-timetable>thead>tr>th.scale-small {
+  padding: 0;
+  border-top: 0;
+  border-right: 1px solid #ddd;
+  border-bottom: 1px solid #ddd;
+  border-left: 0;
+}
+.timeline-timetable>thead>tr>th.scale-small:last-child {
+  border-right: 0;
+}
+.timeline-to-prev {
+  position: absolute;
+  top: -2rem;
+  left: 15px;
+  z-index: 9;
+}
+.timeline-to-next {
+  position: absolute;
+  top: -2rem;
+  right: 15px;
+  z-index: 9;
+}
+.scale-days {
+  
+}
+.scale-hours {
+  
+}
+.scale-minutes {
+  
+}
+.spacer-cell {
+  display: block;
+  width: 29px;
+  min-height: 5px;
+}
+.timeline-events {
+  position: absolute;
+  display: block;
+  left: 0;
+  width: 100%;
+  height: 200px;
+  z-index: 9;
+}
+.timeline-node {
+  position: absolute;
+  display: block;
+  margin: 6px 0;
+  padding: 4px 25px 4px 10px;
+  height: auto;
+  line-height: 20px;
+  vertical-align: middle;
+  text-align: left;
+  background-color: #e3d7a3;
+  color: #777e41;
+  user-select: none;
+  border-radius: 4px;
+  cursor: pointer;
+  z-index: 8;
+  transition: all 1s ease 0;
+}
+.timeline-event-pointer {
+  margin: 0;
+  padding: 0;
+  line-height: 1;
+  text-align: center;
+  background-color: #f0f0f0;
+  border-radius: 100%;
+  border: solid 4px #4496d3;
+  background-image: none;
+  background-size: cover;
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+.timeline-node.timeline-event-pointer.hovered {
+  z-index: 99;
+}
+.timeline-node.timeline-event-pointer.active {
+  box-shadow: 0px 10px 6px -6px rgba(51,51,51,.25);
+  z-index: 99;
+}
+.timeline-text-truncate {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.timeline-node.timeline-text-truncate.active {
+  margin: 2px 0 4px;
+  border: solid 1px rgba(61,61,61,.25);
+  box-shadow: 0px 10px 6px -6px rgba(51,51,51,.25);
+  z-index: 99;
+}
+.timeline-node.timeline-text-truncate:after {
+  content: "\ec5c";
+  font-family: 'jQueryTimeline' !important;
+  font-size: 14px;
+  position: absolute;
+  right: 5px;
+}
+.timeline-loader {
+  position: absolute;
+  display: inline-block;
+  width: 48px;
+  height: 48px;
+  margin: 0;
+  padding: 0;
+  top: 50%;
+  left: 50%;
+  opacity: .3;
+  animation: spin 2.1s linear infinite;
+}
+.timeline-loader i {
+  position: absolute;
+  top: 0;
+  left: 0;
+  font-size: 48px;
+}
+@keyframes spin {
+  0% {transform: rotate(0deg);}
+  100% {transform: rotate(360deg);}
+}
+.timeline-line-canvas {
+  position: absolute;
+  display: block;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 200px;
+  z-index: 6;
+}
+.timeline-grids {
+  position: absolute;
+  left: 0;
+  height: 200px;
+  border-top: 1px solid #ddd;
+  z-index: 0;
+}
+.timeline-grids>tbody>tr>td {
+  padding: 0;
+  border-top: 0;
+  border-right: 1px dotted #ddd;
+  border-bottom: 0;
+  border-left: 0;
+  vertical-align: bottom;
+}
+.timeline-grids>tbody>tr>td:first-child {
+  border-left: 0;
+}
+.timeline-grids>tbody>tr>td:last {
+  border-right: 0;
+}
+.timeline-needle-pointer {
+  position: absolute;
+  display: block;
+  top: 56px;
+  width: 1px;
+  height: calc( 100% - 56px );
+  border-left: 2px dotted #e8383d;
+  z-index: 19;
+}
+.timeline-needle-pointer:before {
+  content: "\ea37";
+  font-family: 'jQueryTimeline' !important;
+  position: absolute;
+  top: -8px;
+  left: -7.5px;
+  font-size: 13px;
+  color: #e8383d;
+}
+.timeline-footer {
+  position: relative;
+  top: 50%;
+  width: 100%;
+  z-index: 5;
+}
+.timeline-nav {
+  width: inherit;
+}
+.timeline-to-prev-default, .timeline-to-next-default {
+  width: 2rem;
+  height: 2rem;
+  line-height: 2rem;
+  font-size: 2rem;
+  color: rgba(71,71,71,.325);
+  text-decoration: none;
+}
+.timeline-to-prev-default:hover, .timeline-to-next-default:hover, 
+.timeline-to-prev-default:active, .timeline-to-next-default:active, 
+.timeline-to-prev-default:focus, .timeline-to-next-default:focus {
+  color: rgba(71,71,71,.75);
+  text-decoration: none;
+}
+.timeline-to-prev-custom, .timeline-to-next-custom {
+  width: 2rem;
+  height: 2rem;
+  line-height: 2rem;
+  vertical-align: middle;
+  text-align: center;
+  border-radius: 50%;
+  background-color: rgba(51,51,51,.2);
+  color: #fff;
+  text-decoration: none;
+}
+.timeline-to-prev-custom:hover, .timeline-to-next-custom:hover, 
+.timeline-to-prev-custom:active, .timeline-to-next-custom:active, 
+.timeline-to-prev-custom:focus, .timeline-to-next-custom:focus {
+  background-color: rgba(51,51,51,.3);
+  color: rgba(255,255,255,.75);
+  text-decoration: none;
+}
+/*  */
+.timeline-event-view {
+  display: block;
+  margin: 0 1em;
+}
+.timeline-event-header {
+  margin-top: 0;
+  margin-bottom: 1rem;
+  border-bottom: dotted 1px #a8a8a8;
+}
+.timeline-event-label {
+  font-family: inherit;
+  font-size: 1.75rem;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+.timeline-event-meta {
+  margin-top: 0;
+  margin-bottom: 0.5rem;
+  font-size: 1rem;
+  font-weight: 300;
+}
+.timeline-event-meta:before {
+  content: "\ea60";
+  font-family: 'jQueryTimeline' !important;
+  color: #999;
+  margin-right: 0.5rem;
+}
+.timeline-event-start-date, .timeline-event-end-date {
+  
+}
+.timeline-event-date-separator {
+  display: inline-block;
+}
+.timeline-event-date-separator:after {
+  content: "\301c";
+  color: #777;
+  font-weight: 400;
+  margin-left: 0.5rem;
+  margin-right: 0.5rem;
+}
+.timeline-event-body {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
+.timeline-event-footer {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}