PageSourceSearch

https://qoly.jp/static/lib/js/jquery-utils.js?260929023659

js qoly.jp collected 2026-10-02 05:19:02 UTC 76,956 bytes, 2,517 lines download raw bytes

1/*
2 * jQury Utils plugin
3 * 
4 * The MIT License
5 * 
6 * Copyright (c) 2012- Shoji Matsumoto ([email protected])
7 * 
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 * 
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 * 
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 * 
26 *********************************************************************
27 * 
28 * This is a jQuery plugin includes some useful small functions.
29 * 
30 * $.typeOf() : better 'typeof'
31 *   -> 'null','undefined','boolean','string','number','function','date','regexp','object'
32 * 
33 * var bound_func = $.closure([arg1,arg2,...],thisObj,function(_binded_arg1,_binded_arg2,..., arg1,arg2){});
34 * bound_func(arg2, arg2);
35 * 
36 * $.doLater(function(){...},delay).then(function(){success}).fail(function(ex){...};
37 * $.doLaterWith([arg1,arg2,...],thisObj,function(_arg1,_arg2,...){...},delay).then(function(){success}).fail(function(ex){...};
38 * 
39 * $.resolve({a:{b:"resolved a.b value"}},"a.b")
40 *   -> "resolved a.b
41 * var obj = {a:{b:"value"}};
42 * $.resolve(obj, "b", "modified value for a.b");
43 * 
44 * $.parseISO8601('1970-01-01T00:00:00Z')
45 *   -> Date(0)
46 * 
47 * $.dateformat(new Date(0), 'yyyy/MM/dd HH:mm')
48 *   -> "1970/01/01 00:00"
49 * 
50 * $.numformat.comma3(1234.5678) -> '1,234.567'
51 * 
52 * $.numformat.round(12345, 3) -> 12300
53 * $.numformat.round(12345.678, -1, true) -> 12345.600
54 * 
55 * $.numformat.kilo(1024) -> 1
56 * $.numformat.mega(1024*1024) -> 1
57 * 
58 * $.encodeHtml('test<a>test') -> 'test&lt;a&gt;test'
59 * $.decodeHtml('text&amp;text') -> 'text&text'
60 * 
61 * $.relativeTime(new Date()) -> 'Now', 'xxx min later', ...
62 * 
63 * $.calcAge('2000-01-01') -> 12 (age for person birthed at '1950-01-01' as int)
64 * 
65 */
66
67(function($) {
68	
69	// useful polyfills Array.from / array.includes / array.fill
70	// (*) every,filter,forEach,map,reduce,some are already supported by IE9+/Edge
71	!function(A,P,U){
72		A.from=A.from||function(a,f,t){var r=P.slice.apply(a);return f?r.map(f.bind(t)):r};
73		P.includes||Object.defineProperty(P,'includes',{value:function(e,i){return this.slice(i===U?0:i).indexOf(e)>=0}});
74		P.fill||Object.defineProperty(P,'fill',{value:function(v,s,e){var i,l=this.length;s=(s===U?0:s);e=(e===U?l:e);s=(s<0?l-s:s);for(i=s;i<e;i++){this[i]=v;};return this}});
75	}(Array,Array.prototype,undefined);
76	
77	// ECMA262 WhiteSpace match <USP:Unicode Spaces>
78	// https://www.ecma-international.org/ecma-262/5.1/#sec-15.5.4.20
79	// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/trim
80	String.prototype.trimasc = function(){ return this.replace(/(^[ \f\n\r\t\v​\u00a0\ufeff]+|[ \f\n\r\t\v​\u00a0\ufeff]+$)/g, '') }
81	
82	var _div = $("<div>");
83	var loremIpsum_src = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In dignissim sem et arcu imperdiet molestie. Curabitur non libero at diam eleifend molestie id ac justo. Sed viverra, est ut mattis faucibus, lacus diam cursus mauris, eu laoreet nibh augue nec ante. Vestibulum id elit sit amet velit pulvinar fermentum et egestas libero. Nullam hendrerit nunc non orci convallis at sodales sem pellentesque. Integer imperdiet porttitor faucibus. Etiam placerat ultrices venenatis. Nam lectus est, posuere at interdum non, ullamcorper sit amet augue. Integer tristique tellus ut eros fermentum molestie sollicitudin tortor molestie. Nam facilisis auctor mattis. Sed et lectus leo. Aliquam erat volutpat. In iaculis vehicula arcu, scelerisque sodales turpis vehicula vel. Quisque eleifend porttitor dolor ac fermentum. Suspendisse nec lectus vel elit euismod vestibulum. "
84			.split(' ');
85	var scrollbarWidth = null, scrollbarHeight = null;
86	
87	/**
88	 * extend $.brwoser for iOS, Android and add css to <body>.
89	 * $.browser.{iphone,ipod,ipad} = true|false
90	 *   $.browser.ios.version = iOS version (ex: 5.1.1)
91	 * $.browser.android
92	 *   $.browser.android.version = Android version (ex:2.3.4)
93	 *   $.browser.android.{mobile,tablet}
94	 * 
95	 * append class to <body>:
96	 *   ua-{webkit,safari,msie,mozilla,opera,ios,android},
97	 *   ua-{webkit,safari,msie,mozilla,opera,ios,android}-<version>,		ex) ua-ios-5.1.1
98	 *   ua-{webkit,safari,msie,mozilla,opera,ios,android}-<version|x.x>,	ex) ua-ios-5.1
99	 *   ua-{webkit,safari,msie,mozilla,opera,ios,android}-<version|x>		ex) ua-ios-5
100	 */
101	var _ua = navigator.userAgent, m, k, i;
102	
103	// $.browser = $.browser || {};
104	$.browser = { useragent: _ua };
105	
106	// http://www.useragentstring.com/
107	var rxs = [
108		// key, regexp(ver), ismobile, break 
109		['webkit', /AppleWebKit\/([0-9.]+)/, false, false]
110		,['ios', /iPhone OS ([\d_]+)/, true, false]
111		,['ios', /iPad;(?: U;)? CPU OS ([\d_]+)/, true, false]
112		,['macosx', /Mac OS X ([\d_]+)/, false, false]
113		,['operamini', /Opera Mini\/([0-9.]+)$/, true, false]
114		,['operamobi', /Opera Mobi\/([^ ;]+)$/, true, false]
115		,['opera', /^Opera\/.*Version\/([0-9.]+)$/, false, true]
116		,['opera', /^Opera ([0-9.]+)/, false, true]
117		,['opera', /Opera[\/ ]([0-9.]+)/, false, true]
118		,['chrome', /CriOS\/([0-9.]+)/, true, true]
119		,['chrome', /Chrome\/([0-9.]+)/, false, true]
120		,['firefox', /Fennec\/([0-9.]+)/, true, true]
121		,['firefox', /Firefox\/([0-9.]+)/, false, true]
122		,['safari', /Version\/([0-9.]+) Safari\/([0-9.]+)/, false, true]
123		,['safari', /Safari\/([0-9.]+)/, false, true]
124		,['msie', /IEMobile\/([0-9.]+)/, true, true]
125		,['msie', /MSIE ([0-9.]+)/, false, true]
126	];
127	$.each(rxs, function(i, v){
128		var k = v[0];
129		var m = _ua.match(v[1]);
130		if (m) {
131			$.browser[k] = {
132				version: m[1].replace(/_/g, '.'),
133				mobile: v[2]
134			};
135			$.browser.version = $.browser[k].version;
136			$.browser.mobile = v[2];
137			if (v[3]) {
138				return false;
139			}
140		}
141	});
142	
143	if ($.browser.opera) {
144		m = _ua.match(/Opera Mini\/([0-9.]+)/);
145		if (m) {
146			$.browser.opera.mini = { version:m[1] };
147			$.browser.opera.mobile = true;
148		}
149	}
150	if ($.browser.safari) {
151		m = _ua.match(/ Mobile\//);
152		if (m) {
153			$.browser.safari.mobile = true;
154		}
155	}
156	if ($.browser.msie) {
157		$.browser.msie.backcompat = document.compatMode == 'BackCompat';
158		// see http://d.hatena.ne.jp/favril/20090424/1240548931
159	}
160	
161	$.browser.mozilla = $.browser.firefox;
162	
163	if (m = _ua.match(/Android ([0-9.]+)/)) {
164		$.browser.android = {
165			mobile: !!_ua.match(/Mobile/),
166			tablet: !(_ua.match(/Mobile/)),
167			version: m[1]
168		};
169	} else if (m = _ua.match(/Android;/)) {
170		$.browser.android = {
171			mobile: true,
172			firefox: true,
173			version:'unknown'
174		};
175	}
176
177	if ($.browser.ios) {
178		$.browser.iphone = !!_ua.match(/iPhone/);
179		$.browser.ipod = !!_ua.match(/iPod/);
180		$.browser.ipad = !!_ua.match(/iPad/);
181		$.browser.ios.mobile = $.browser.iphone || $.browser.ipod;
182		$.browser.ios.tablet = $.browser.ipad;
183	}
184
185	$.browser.mobile = $.browser.iphone || $.browser.ipod 
186		|| ($.browser.android && $.browser.android.mobile)
187		|| ($.browser.msie && $.browser.msie.mobile)
188		|| ($.browser.firefox && $.browser.firefox.mobile);
189	$.browser.tablet = $.browser.ipad || ($.browser.android && $.browser.android.tablet);
190	$.browser.desktop = !$.browser.mobile && !$.browser.tablet;
191	$.browser.touchable = !!('ontouchstart' in window);
192	
193	$.each(['msie', 'webkit', 'safari', 'opera', 'mozilla', 'firefox', 'chrome', 'opera'], function(i, v){
194		var _b = $.browser[v];
195		if (_b){
196			$('html').addClass('ua-' + v);
197			var _v = (_b.version || $.browser.version).split('.');
198			if (_v) {
199				$('html')
200					.addClass('ua-' + v + '-' + _v.join('.'))
201					.addClass('ua-' + v + '-' + _v[0] + '.' + _v[1])
202					.addClass('ua-' + v + '-' + _v[0]);
203			}
204		}
205	});
206	
207	$.each($.browser, function(k, v){
208		if (!v) {
209			delete $.browser[k];
210		}
211	});
212	
213	$.each(['ios', 'android'], function(i, v){
214		var _b = $.browser[v];
215		if (_b){
216			$('html').addClass('ua-' + v);
217			var _v = $.browser[v].version.split('.');
218			if (_v) {
219				$('html')
220					.addClass('ua-' + v + '-' + _v.join('.'))
221					.addClass('ua-' + v + '-' + _v[0] + '.' + _v[1])
222					.addClass('ua-' + v + '-' + _v[0]);
223			}
224		}
225	});
226	
227	// CSSの小数点丸め
228	// http://iwb.jp/decimal-point/ 
229	$.browser.cssRound = function(v){
230		return Math.round(v);
231	};
232	if ($.browser.webkit) {
233		$.browser.cssRound = function(v) {
234			return Math.floor(v + 0.01);
235		};
236	} else if ($.browser.firefox) {
237		$.browser.cssRound = function(v) {
238			return Math.floor(v + (1 - 0.49166));
239		};
240	} else if ($.browser.msie) {
241		$.browser.cssRound = function(v) {
242			return Math.floor(v);
243		};
244	}
245	
246	/*
247	$.each(['mobile', 'tablet', 'desktop'], function(i, v){
248		$('body').toggleClass('ua-' + v, $.browser[v]);
249	});
250	*/
251	
252
253	if (!('console' in window)) {
254		window.console = { log:$.noop, error:$.noop, warn:$.noop, info:$.noop };
255	} else if (typeof window.console.log != 'function') {
256		// for IE
257		var _console = window.console;
258		window.console = {};
259		$.each(['log', 'error', 'warn', 'info'], function(i, v){
260			(function(method){
261				var org = _console[method];
262				window.console[method] = function(){
263					return org(Array.prototype.slice.apply(arguments).join(', '));
264				};
265			})(v);
266		});
267	}
268	
269	$(document).ready(function(){
270		var $div = $('#_dpi') || $('<div>').attr('id', '_dpi').css({
271			position: 'absolute',
272			width: '1in',
273			height: '0',
274			padding: 0
275		}).appendTo('body');
276		$.browser.dpi = $div.width();
277	});
278	
279	$(document).ready(function(){
280		var dummy_console = $('textarea#console');
281		if (dummy_console[0]){
282			var dump = function(){
283				var args = Array.prototype.slice.apply(arguments);
284				return $.map(args, function(v){
285					if (v === window) return '[Window]';
286					// if (v instanceof jQuery) return '[jQuery:[' + v.map(function(i, v){return dumpHTMLElement(v);}).toArray().join(',') + ']]';
287					if ($.isXMLDoc(v)) return '[Node:' + dumpHTMLElement(v) + ']';
288					if ($.isPlainObject) return ($.toJSON ? $.toJSON(v) : ''+v );
289					return "" + v;
290				}).join(',');
291			};
292			$.each([['log',''], ['error','\nERR: '], ['warn','WARN: '], ['info', 'INFO: ']], function(i, v){
293				(function(method){
294					var lead = method[1], method = method[0], org = window.console[method];
295					window.console[method] = function(){
296						var args = Array.prototype.slice.apply(arguments);
297						dummy_console.val(dummy_console.val() + lead + dump.apply(this, args) + '\n').scrollTop(100000);
298						return org.apply(console, arguments);
299					};
300				})(v);
301			});
302			console.log('--- start console ---');
303		}
304	});
305	
306	
307	$.extend({
308		
309		_log : function() {
310			if ('console' in window) {
311				console.log.apply(console, arguments);
312			}
313		},
314		
315		_error : function() {
316			if ('console' in window) {
317				console.error.apply(console, [(new Error()).stack].concat(arguments));
318			}
319		},
320
321		_typeOf_constructors : {
322			array : (new Array()).constructor,
323			date : (new Date()).constructor,
324			regexp : (new RegExp()).constructor,
325			string : (new String()).constructor,
326			number : (new Number()).constructor,
327			boolean : (new Boolean()).constructor
328		},
329
330		typeOf : function(v) {
331			/**
332			 * return better 'typeof' / jQuery 1,2 compat
333			 */
334			if (v === null) {
335				return 'null';
336			}
337			if (typeof v !== 'object') {
338				return typeof v;
339			}
340			var typeString = Object.prototype.toString.call(v);
341			var typeMap = {
342				'[object Array]': 'array',
343				'[object Date]': 'date',
344				'[object RegExp]': 'regexp',
345				'[object Function]': 'function',
346				'[object Arguments]': 'arguments',
347				'[object Error]': 'error',
348				'[object Boolean]': 'boolean',
349				'[object Number]': 'number',
350				'[object String]': 'string',
351				'[object Map]': 'map',
352				'[object Set]': 'set',
353				'[object WeakMap]': 'weakmap',
354				'[object WeakSet]': 'weakset',
355				'[object ArrayBuffer]': 'arraybuffer',
356				'[object DataView]': 'dataview',
357				'[object Int8Array]': 'int8array',
358				'[object Uint8Array]': 'uint8array',
359				'[object Uint8ClampedArray]': 'uint8clampedarray',
360				'[object Int16Array]': 'int16array',
361				'[object Uint16Array]': 'uint16array',
362				'[object Int32Array]': 'int32array',
363				'[object Uint32Array]': 'uint32array',
364				'[object Float32Array]': 'float32array',
365				'[object Float64Array]': 'float64array'
366			};
367
368			return typeMap[typeString] || 'object';
369		},
370		
371		min : function(){
372			/**
373			 * return minimum argument value (for number, string, Date)
374			 */
375			var ret = arguments[0];
376			Array.prototype.forEach.call(arguments, function(v){
377				if (v === undefined || v === null) { return; }
378				if (ret > v) { ret = v; }
379			});
380			return ret;
381		},
382		
383		max : function(){
384			/**
385			 * return maximum argument value (for number, string, Date)
386			 * ignore null, undefined
387			 */
388			var ret = arguments[0];
389			Array.prototype.forEach.call(arguments, function(v){
390				if (v === undefined || v === null) { return; }
391				if (ret < v) { ret = v; }
392			});
393			return ret;
394		},
395		
396		isDeferred : function(obj) {
397			return obj && obj.then && obj.fail && typeof obj.always === 'function';
398		},
399
400		closure : function(args, thisobj, func) {
401			/**
402			 * make args binded closure for func. 
403			 * func is called with arg(args[0], args[1], ... , arguments[0], arguments[1].
404			 * ex)
405			 *   var f2 = $.closure([1,2], null, function(_a, _b, c) { print _a,_b,c; });
406			 *   f2(3); -> 1,2,3
407			 * 
408			 * @param args
409			 *            array of binding arguments
410			 * @param thisobj
411			 *            binding 'this' object
412			 * @param func
413			 *            closure function
414			 * @return args and 'this' binded function
415			 */
416			var _args = Array.prototype.slice.call(args);
417			return function() {
418				return func.apply(thisobj, _args.concat(Array.prototype.slice.apply(arguments)));
419			};
420		},
421
422		doLaterWith : function(args, thisobj, func, delay) {
423			/**
424			 * Deferred setTimeout with closure
425			 */
426			delay = (delay === undefined) ? 0 : delay;
427			var c = $.closure(args, thisobj, func);
428			return $.Deferred(function(_d) {
429				setTimeout(function() {
430					try {
431						_d.resolve(c());
432					} catch (ex) {
433						_d.reject(ex);
434						throw ex;
435					}
436				}, delay);
437			});
438		},
439
440		doLater : function(func, delay) {
441			/**
442			 * Deferred setTimeout
443			 */
444			if (typeof func == 'function') {
445				return $.doLaterWith([], null, func, delay);
446			} else {
447				return $.doLaterWith([], null, function() {
448				}, func, 1);
449			}
450		},
451		
452		pollWith : function(args, thisobj, func, timeout, interval) {
453			/**
454			 * while func returns true, func is called repeatedly by interval
455			 */
456			interval = (interval === undefined) ? 250 : interval;
457			timeout = (timeout == undefined) ? -1 : timeout;
458			var c = $.closure(args, thisobj, func), remain = timeout * 1000 / interval;
459			return $.Deferred($.closure([timeout, remain, interval], null, function(timeout, remain, interval, _d){
460				var ret, _t = null;
461				if ((ret = c()) !== true) {
462					_d.resolve(ret);
463				} else {
464					_t = setInterval(function(){
465						if (timeout > 0 && remain < 0) {
466							clearInterval(_t);
467							_d.resolve('timeout');
468						} else if ((ret = c()) !== true) {
469							clearInterval(_t);
470							_d.resolve(ret);
471						}
472						remain--;
473					}, interval);
474				}
475			}));
476		},
477		
478		poll : function(func, timeout, interval) {
479			return $.pollWith([], null, func, timeout, interval);
480		},
481
482		resolve : function(obj, str, val) {
483			/**
484			 * resolve object by string. 
485			 * ex) 
486			 *   $.resolve(obj, 'var'); -> obj.var
487			 *   $.resolve(obj, 'arr[10]'); -> obj.arr[10]
488			 *   $.resolve(obj, 'func()'); -> obj.func()
489			 *   $.resolve(obj, 'var.func()'); -> obj.var.func()
490			 *   $.resolve(obj, 'var.arr[1]'); -> obj.var.arr[1]
491			 *   $.resolve(obj, 'func()[10]'); -> obj
492			 */
493
494			var bits = str.split('.'), bit, settable = false;
495			var curobj = obj;
496			var curname = '';
497			while (bit = bits.shift()) {
498
499				if (curobj === undefined) {
500					throw new Error('ResolveError: obj is undefined:<obj>' + curname);
501				}
502
503				curname = curname + '.' + bit;
504				var res = bit.match(/^([a-zA-Z0-9_]+)(\(\))?(\[(\d+)\])?/);
505
506				var name = res[1];
507				var isfunc = res[2] == '()';
508				var isarray = (res[3] != undefined) && (res[3] != ''); // ''
509				// for
510				// IE7
511				var arraynum = parseInt(res[4], 10);
512
513				if (isfunc || isarray) {
514					if (curobj[name] === undefined) {
515						throw new Error('ResolveError: property is undefined:<obj>' + curname);
516					}
517					if (isfunc) {
518						settable = false;
519						if (curobj[name].call === undefined) {
520							throw new Error('ResolveError:property is not callable:<obj>' + curname);
521						}
522						curobj = curobj[name].call(curobj);
523					} else {
524						settable = true;
525						if (curobj[name] === undefined) {
526							throw new Error('ResolveError:undefined property:<obj>' + curname);
527						}
528						curobj = curobj[name][arraynum];
529					}
530				} else {
531					settable = true;
532					curobj = curobj[name];
533				}
534			}
535
536			if (val !== undefined) {
537				if (settable) {
538					eval('(function(obj,v){obj.' + str + ' = v;})(obj,val)');
539				}
540			}
541
542			return curobj;
543
544		},
545
546		lpad : function(chr, len, str, do_cut){
547			/**
548			 * padding <chr> character to left of str to length <len>.
549			 * if do_cut = true, force cut over length.
550			 * ex)
551			 * 	lpad('0', 4, '321') => '0321'
552			 * 	lpad(' ', 3, 'a') => '  a'
553			 * 	lpad(' ', 3, 'abcd') => 'abcd'
554			 * 	lpad(' ', 3, 'abcd', true) => 'bcd'
555			 */
556			if (!do_cut && str.length >= len) { return str; }
557			return (Array.apply(null, Array(len)).map(function(){ return chr; }).join('') + str).splice(-len);
558		},
559		
560		parseISO8601 : function(str) {
561			/**
562			 * parse ISO8601 "YYYY-MM-DDTHH:MM:SS+TTTT" to Date().
563			 */
564			var p = str.match(/(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?T(\d{2})(?::(\d{2})(?::(\d{2})(?:\.(\d+))?)?)(Z|([+-]\d{2})(?::?(\d{2}))?)/);
565			if (p === null) {
566				throw new Error('ISO8601ParseError', 'Invalid ISO8601 DateTime : ' + str);
567			}
568			for ( var i = 0; i < p.length; i++) {
569				switch (i) {
570				case 2:
571				case 3:
572					if (p[i] === undefined) {
573						p[i] = '01';
574					}
575					;
576					break;
577				case 4:
578				case 5:
579				case 6:
580				case 7:
581				case 9:
582				case 10:
583					if (p[i] === undefined) {
584						p[i] = '00';
585					}
586					;
587					break;
588				case 8:
589					if (p[i] === 'Z') {
590						p[9] = '+00';
591					}
592					;
593					break;
594				}
595			}
596			return new Date(Date.parse([ p[1], p[2], p[3] ].join('/') + ' ' + [ p[4], p[5], p[6] ].join(':') + ' GMT' + [ p[9], p[10] ].join('')));
597		},
598
599		toISO8601 : function(date) {
600			/**
601			 * Date() to ISO8601 string.
602			 * need jquery-json.js
603			 */
604			return $.toJSON(date).replace(/"/g, '');
605		},
606
607		dateformat : function(date, format, to_utc) {
608			/**
609			 * format Date() with dateformat (Java SimpleDateFormat())
610			 * 
611			 * @param date
612			 *            Date()
613			 * @param format
614			 *            dateformat string. supported: YymndjHGisShgaA. default -
615			 *            yyyy/M/d h:mm
616			 */
617			
618			if (! date instanceof Date) {
619				console.error('dateformat:date is not Date', date);
620				return 'Invalid Date';
621			}
622			
623			if (isNaN(date.getTime())) {
624				return 'Invalid Date';
625			}
626			
627			to_utc = (to_utc === undefined) ? false : true;
628			format = (format === undefined) ? 'yyyy/M/d h:mm' : format;
629			function pad0(num, len) {
630				return ('000000' + num).split('').reverse().splice(0, len).reverse().join('');
631			}
632			var dt = date, y, M, d, H, m, s, S;
633			if (to_utc) {
634				y = dt.getUTCFullYear();
635				M = dt.getUTCMonth() + 1;
636				d = dt.getUTCDate();
637				H = dt.getUTCHours();
638				m = dt.getUTCMinutes();
639				s = dt.getUTCSeconds();
640			} else {
641				y = dt.getFullYear();
642				M = dt.getMonth() + 1;
643				d = dt.getDate();
644				H = dt.getHours();
645				m = dt.getMinutes();
646				s = dt.getSeconds();
647			}
648			S = dt.getMilliseconds();
649			
650			var formatted = {
651				yyyy : y,
652				yy : (y + '').substring(2, 4), // year
653				MM : pad0(M, 2),
654				M : M, // month
655				dd : pad0(d, 2),
656				d : d, // day
657				HH : pad0(H, 2),
658				H : H, // hour
659				mm : pad0(m, 2), // min
660				m : m,
661				ss : pad0(s, 2), // sec
662				s : s,
663				SSS : pad0(S, 3), // msec
664				KK : pad0(H % 12, 2),
665				K : H % 12,
666				hh : pad0((H % 12) == 0 ? 12 : (H % 12), 2),
667				h : (H % 12) == 0 ? 12 : (H % 12),
668				a : H < 12 ? 'AM' : 'PM'
669			};
670			var ret = [], bit, bits = format.split("'");
671			while (bits.length) {
672				bit = bits.shift();
673				if (bit == '') {
674					ret.push('\'');
675				} else {
676					ret.push(bit.replace(/(yyyy|yy|[MdhHmsK]{1,2}|S{1,3}|a)/g, function(m0, m1, m2, idx) {
677						return formatted[m1];
678					}));
679				}
680				bit = bits.shift();
681				if (bits.length) {
682					ret.push(bit);
683				}
684			}
685			return ret.join('');
686		},
687		
688		dateCalc : function(base_date, delta_str) {
689			/**
690			 * calcurate Date().
691			 * ex)
692			 *   $.dateCalc(new Date(), '+1d');
693			 *   $.dateCalc(new Date(), '-1y-1d');
694			 *   $.dateCalc(new Date(), '+24h');
695			 *   
696			 * @param base_date Date()
697			 * @param delta_str string delta from base_date.
698			 *   format : [+-]\d+[yMdHms]
699			 *   ex) '+1d' : after 1day, '-1d' before 1day, '1y, 1M' after 1 year and 1day
700			 * @return Date() from base_date + delta_str
701			 */
702			var m = delta_str.match(/([-+]?\d+[yMdHms],?\s*)/g);
703			if (m === null) {
704				throw new Error('invalid delta_str: ' + delta_str);
705			}
706			var d = {'y' : 0, 'M' : 0, 'd' : 0, 'H' : 0, 'm' : 0, 's' : 0};
707			$.each(m, function(i, v){
708				var n = v.match(/^([-+]?\d+)([yMdHms])$/);
709				d[n[2]] = parseInt(n[1], 10);
710			});
711			return new Date(base_date.getFullYear()+d.y, base_date.getMonth()+d.M, base_date.getDate()+d.d, base_date.getHours()+d.H, base_date.getMinutes()+d.m, base_date.getSeconds()+d.s);
712		},
713		
714		relativeTime : function(date, options) {
715			/**
716			 * return relative time string.
717			 * @param date Date()
718			 * @param options {
719			 *   now : <Date() : origin>,
720			 *   dateformat : 'yyyy/M/d H:MM',
721			 *   thresholds : [ [<min in seconds>, <duration in secons>, '<suffix string>'],
722			 *   suffixes : [ '<ago string>', '<later string>']
723			 * }
724			 */
725			options = $.extend({
726				now : new Date(),
727				dateformat : 'yyyy/M/d H:MM',
728				thresholds : [ [ 10, 0, 'Now' ], [ 60, 1, ' sec' ], [ 60 * 60, 60, ' min' ], [ 2 * 60 * 60, 60 * 60, ' hour' ],
729						[ 24 * 60 * 60, 60 * 60, ' hours' ], [ 2 * 24 * 60 * 60, 24 * 60 * 60, ' day' ], [ 30 * 24 * 60 * 60, 24 * 60 * 60, ' days' ] ],
730				suffixes : [ ' ago', ' later' ]
731			}, options);
732			var suffix = (options.now.getTime() + 100 > date.getTime()) ? options.suffixes[0] : options.suffixes[1];
733			var delta = Math.floor(Math.abs((options.now.getTime() - date.getTime()) / 1000));
734			for ( var i = 0, l = options.thresholds.length; i < l; i++) {
735				var th = options.thresholds[i];
736				if (delta < th[0]) {
737					if (th[1] > 0) {
738						return Math.max(1, Math.floor(delta / th[1])) + th[2] + suffix;
739					} else {
740						return th[2];
741					}
742				}
743			}
744			return $.dateformat(date, options.dateformat);
745		},
746		
747		calcAge : function(birthday_str) {
748			/**
749			 * calc age
750			 * @param birthday_str 'yyyy-MM-dd'
751			 * @return age int()
752			 */
753			var _birth = parseInt(birthday_str.replace(/[-\/]/g, ''));
754			var _today = parseInt($.dateformat(new Date(), 'yyyyMMdd'));
755			return parseInt((_today - _birth) / 10000);
756		},
757
758		numformat : {
759			comma3 : function(v) {
760				/**
761				 * return 'comma formatted string' of number
762				 */
763				if (!isFinite(v) || isNaN(v)) {
764					return v;
765				}
766				if (v < 1000 && v > -1000) {
767					return new String(v);
768				}
769				v = (new String(v)).match(/^([-+]?)(\d+)(\.\d+)?$/);
770				v[2] = v[2].replace(/\B(?=(?:\d{3})+(?!\d))/g, ',');
771				v[3] = v[3] === undefined ? '' : v[3];
772				return v[1] + v[2] + v[3];
773			},
774			round : function(v, pos, pad0) {
775				/**
776				 * return rounded number. 
777				 * @param pos round position ( 0=1, 1=10, 2=100, -1=0.1, -2=0.01 )
778				 * @param pad0 padding 0 for decimal points
779				 */
780				pad0 = (pad0 === undefined) ? true : pad0;
781				pos = (pos === undefined) ? 0 : pos;
782				var ret = v;
783				if (pos < 0) {
784					ret = Math.round(v * Math.pow(10, -pos)) / Math.pow(10, -pos);
785				} else {
786					ret = Math.round(v / Math.pow(10, pos)) * Math.pow(10, pos);
787				}
788				if (pad0 && pos < 0) {
789					ret = ret.toFixed(-pos);
790				}
791				return ret;
792			},
793			kilo : function(v, use_si) {
794				/**
795				 * return kilo value of v (1024 = 1k)
796				 * @param use_si : use 1000 = 1K
797				 */
798				return $.numformat.round(v / (use_si?1000:1024), -2, false);
799			},
800			mega : function(v, use_si) {
801				/**
802				 * return mega value of v (1024*1024 = 1Mi)
803				 * @param use_si : 1M = 1000*1000
804				 */
805				return $.numformat.round(v / (use_si?1000*1000:1024*1024), -2, false);
806			},
807			tera : function(v, use_si) {
808				/**
809				 * return mega value of v (1024*1024*1024 = 1Ti)
810				 * @param use_si : 1T = 1000*1000*1000
811				 */
812				return $.numformat.round(v / (use_si?1000*1000*1000:1024*1024*1024), -2, false);
813			},
814			shorten : function(v, use_si) {
815				/**
816				 * return auto formatted value
817				 */
818				var a = Math.abs(v), n = v < 0 ? -1 : 1,
819					u = use_si ? 1000 : 1024,
820					r;
821				if (a < u) {
822					r = $.numformat.round(a, -2, false);
823					s = '';
824				} else if (a < u*u) {
825					r = $.numformat.kilo(a, use_si);
826					s = use_si ? 'k' : 'Ki';
827				} else if (a < u*u*u) {
828					r = $.numformat.mega(a, use_si);
829					s = use_si ? 'M' : 'Mi';
830				} else {
831					r = $.numformat.tera(a, use_si); 
832					s = use_si ? 'T' : 'Ti';
833				}
834				if (r < 10) {
835					
836				} if (r < 100) {
837					r = $.numformat.round(r, -1, true);
838				} else {
839					r = $.numformat.round(r, 0, true);
840				}
841				
842				r = (r * n) + s;
843				return r;
844			}
845		},
846
847		cookie : function(key, val, options) {
848			/**
849			 * get/set cookie (expect uri encoding)
850			 * @param key key
851			 * @param val value
852			 * @param options {
853			 *   expires : <Date()> | <days:number> | 'never',
854			 *   path : '<path>',
855			 *   domain : '<domain>',
856			 *   secure : <false|true>
857			 * }
858			 */
859			if (arguments.length <= 1) {
860				var cookies = {}, bit, bits = document.cookie.split('; ');
861				while (bit = bits.shift()) {
862					bit = bit.split('=');
863					try {
864						cookies[decodeURIComponent(bit[0])] = decodeURIComponent(bit[1] || '');
865					} catch(ex) {
866						console.error('$.cookie: unexpecedly encoded:' + bit[0] + '=' + bit[1]);
867						cookies[bit[0]] = bit[1];
868					}
869				}
870				if (key !== undefined) {
871					return cookies[key];
872				}
873				return cookies;
874			} else {
875				// delete cookie
876				options = $.extend({
877					expires : '',
878					maxAge : null,
879					path : '',
880					domain : '',
881					secure : false
882				}, options);
883				if (val === null) {
884					val = '';
885					options.expires = new Date(0);
886					options.maxAge = 0;
887					console.log('$.cookie:will delete:' + key);
888				} else {
889					if ($.typeOf(key) != 'string'){
890						throw new Error('$.cookie:key is not string.');
891					}
892					if ($.typeOf(val) != 'string' && $.typeOf(val) != 'number') {
893						throw new Error('$.cookie:value is not string: ' + $.typeOf(val));
894					}
895				}
896				if (options.maxAge) {
897					var expires = new Date();
898					expires.setTime(new Date().getTime() + options.maxAge * 1000);
899					options.expires = expires;
900				}
901				
902				if (options.expires) {
903					if (options.expires === 'never') {
904						// var t = new Date('2038-01-19T04:14Z');/* max epoch : 2038-01-19T04:14:07.999Z */
905						options.expires = 365*10; 
906					}
907					if (typeof options.expires === 'number') {
908						var days = options.expires, t = options.expires = new Date();
909						t.setTime(+t + days * 864e+5);
910					}
911					if (!options.expires instanceof Date) {
912						console.error('$.cookie: expires is not Date() : ' + key);
913					}
914				}
915				console.log('$.cookie:will set:' + key + '=' + val, options);
916				var ret = document.cookie = [
917						encodeURIComponent(key) + '=' + encodeURIComponent(val),
918						// options.expires ? ('; expires=' + options.expires.toUTCString()) : '', /* 非推奨 */
919						options.expires ? ('; max-age=' + Math.round((options.expires.getTime() - new Date().getTime())/1000)) : '',
920						options.path ? ('; path=' + options.path) : '',
921						options.domain ? ('; domain=' + options.domain) : '',
922						options.secure ? '; secure' : '' ].join('');
923				console.log('$.cookie:result:' + key + '=' + $.cookie(key));
924				return ret;
925			}
926
927		},
928
929		encodeHtml : function(text) {
930			return _div.text(text).html();
931		},
932
933		decodeHtml : function(html) {
934			return _div.html(html).text();
935		},
936
937		anchor : function(val, skip) {
938			var fn = arguments.callee;
939			switch (typeof val) {
940			// getter
941			case "undefined":
942				var ret = location.hash;
943				if (!ret) {
944					return null;
945				}
946				ret = ret.replace(/^#/, "");
947				return $.browser.fx ? ret : decodeURIComponent(ret);
948				// callback
949			case "function":
950				if (!fn.tid) {
951					fn.hash = location.hash;
952					(function rec() {
953						if (!fn.skip && fn.hash !== location.hash) {
954							fn.hash = location.hash;
955							$(window).trigger("changeAnchor", $.anchor());
956						}
957						fn.tid = setTimeout(rec, 300);
958					})();
959				}
960				return $(window).bind("changeAnchor", val);
961				// setter
962			default:
963				if (skip) {
964					fn.skip = true;
965					location.hash = encodeURIComponent(val);
966					fn.hash = location.hash;
967					fn.skip = false;
968				} else {
969					location.hash = encodeURIComponent(val);
970				}
971				return;
972			}
973		},
974
975		loremIpsum : function(min_words, max_words) {
976			/**
977			 * make loremIpsum strings.
978			 */
979			min_words = (min_words === undefined) ? 5 : min_words;
980			max_words = (max_words === undefined) ? 20 : max_words;
981			var ret = [];
982			var words_count = min_words + Math.floor(Math.random() * (max_words - max_words));
983			for ( var i = 0; i < min_words; i++) {
984				ret.push(loremIpsum_src[Math.round(Math.random() * loremIpsum_src.length)]);
985			}
986			for (i = min_words; i < words_count; i++) {
987				ret.push(loremIpsum_src[Math.round(Math.random() * loremIpsum_src.length)]);
988			}
989			return ret.join(' ');
990		},
991
992		loadCss : function(href, flag) {
993			/**
994			 * load css file.
995			 * @param href url
996			 * @parm flag <true|false> load or unload
997			 * @return loaded '<link>' element.
998			 */
999			if (flag == false) {
1000				return $.unloadCss(href);
1001				return;
1002			}
1003			if ($('head link[href="' + href + '"][rel="stylesheet"]')[0]) {
1004				return;
1005			}
1006			$('head').append('<link>');
1007			var css = $('head').children(':last');
1008			css.attr({
1009				'href' : href,
1010				'rel' : 'stylesheet'
1011			});
1012			return $('head').children(':last');
1013		},
1014
1015		unloadCss : function(elem) {
1016			/**
1017			 * unload <link> element.
1018			 */
1019			if ($.typeOf(elem) === 'string') {
1020				elem = $('head link[rel="stylesheet"][href="' + elem + '"]');
1021			}
1022			elem.remove();
1023		},
1024		
1025		setStyle : function(style, id) {
1026			/**
1027			 * add or set <style> in <head>
1028			 * ex)
1029			 *   var $style_elm = $.setStyle('body .someclass { display:none; }');
1030			 * @param style string
1031			 * @param id id for <style>
1032			 * @return <style> element
1033			 */
1034			
1035			if (! id === undefined ) {
1036				if (!$('#'+id).is('style')) {
1037					console.error('$.setStyle:#' + id + ' is not <style>.' );
1038					return $();
1039				}
1040			}
1041			var cnt = $.setStyle._cnt = ($.setStyle._cnt || 0) + 1, id = id || 'setstyle-' + cnt;
1042			var $new = $('<style id="' + id + '">' + style + '</style>');
1043			var $exists = $('#' + id);
1044			if ($exists[0]) {
1045				$exists.removeAttr('id');
1046				$new.insertAfter($exists);
1047				$exists.remove();
1048			} else {
1049				$new.appendTo($('head'));
1050			}
1051			return $new;
1052		},
1053		
1054		removeStyle : function(target) {
1055			/**
1056			 * remove <style> in <head>
1056 generated with $.setStyle
1057			 * ex)
1058			 *   $.setStyle('.elm { property:value; }', 'mystyleid');
1059			 *   $.removeStyle('mystyleid');
1060			 *   
1061			 *   var $style = $.setStyle(...);
1062			 *   $.removeStyle($style);
1063			 *   
1064			 * 
1065			 */
1066			if (! id_or_$style_elm instanceof $) {
1067				id_or_$style_elm = $('#' + id_or_$style_elm);
1068			}
1069			if (id_or_$style_elm.is('style')) {
1070				id_or_$style_elm.remove();
1071			}
1072		},
1073		
1074		getScrollbarWidth : function(){
1075			if (scrollbarWidth !== null) {
1076				return scrollbarWidth;
1077			}
1078			var div = $('<div>').css({
1079				position: 'absolute',
1080				top: '-100px',
1081				left: '-100px',
1082				width: '100px',
1083				height: '100px',
1084				overflowY: 'scroll'
1085			}).appendTo('body');
1086			scrollbarWidth = 100 - div[0].clientWidth;
1087			div.remove();
1088			return scrollbarWidth;
1089		},
1090		
1091		getScrollbarHeight : function(){
1092			if (scrollbarHeight !== null) {
1093				return scrollbarHeight;
1094			}
1095			var div = $('<div>').css({
1096				position: 'absolute',
1097				top: '-100px',
1098				left: '-100px',
1099				width: '100px',
1100				height: '100px',
1101				overflowX: 'scroll'
1102			}).appendTo('body');
1103			scrollbarHeight = 100 - div[0].clientHeight;
1104			div.remove();
1105			return scrollbarHeight;
1106		},
1107		
1108		redraw : function(func){
1109			$('body').redraw(func);
1110		},
1111		
1112		arrayMap : function(array, key, ignore_null) {
1113			ignore_null = ignore_null === undefined ? true : ignore_null;
1114			var ret = {};
1115			$.each(array, function(i, v){
1116				if (ignore_null && v == null) {
1117					return;
1118				}
1119				if (key in v) {
1120					ret[v[key]] = v;
1121				} else {
1122					throw 'arrayMap():object array[' + i + '] is not have "' + key + '"';
1123					return false;
1124				}
1125			});
1126			return ret;
1127		},
1128		
1129		fontAvailable : function(fontName, teststr) {
1130			var width, height;
1131			// prepare element, and append to DOM
1132			var element = $('#_fontavailable');
1133			if (!element[0]) {
1134				element = $(document.createElement('span')).attr('id', '_fontavailable').css({
1135					'visibility': 'hidden',
1136					'position': 'absolute',
1137					'top': '-10000px',
1138					'left': '-10000px'
1139				}).html('abcdefghijklmnopqrstuvwxyz' + (teststr || '')).appendTo(document.body);
1140			}
1141
1142			// get the width/height of element after applying a fake font
1143			width = element.css('font-family', '__FAKEFONT__').width();
1144			height = element.height();
1145
1146			// set test font
1147			element.css('font-family', fontName);
1148
1149			return width !== element.width() || height !== element.height();
1150		},
1151		
1152		createOrGet : function(selector, generate_func, context) {
1153			var $ret = $(selector, context);
1154			if ($ret[0]) { return $ret; }
1155			$ret = generate_func(context);
1156			if (!$ret.is(selector)) {
1157				console.error('$.createOrGet():generate_func is not "'+selector+'"');
1158			}
1159			return $ret;
1160		},
1161		
1162		toBase : function(num, base){
1163			var chars, type = typeof base, use_chars = false;
1164			if (type == 'number') {
1165				chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
1166			} else if (type == 'string') {
1167				chars = base;
1168				base = chars.length;
1169				use_chars = true;
1170			} else {
1171				throw new Error('invalid base (number or string):' + base);
1172			}
1173			if (base <= 36 && !use_chars) {
1174				return Number(num).toString(base);
1175			}
1176			var is_negative = num < 0;
1177			for (var str='', num = Math.abs(num); num > 0; num = Math.floor(num/base)) {
1178				str = chars[num % base] + str;
1179			}
1180			return (is_negative ? '-' : '') + str;
1181		},
1182		
1183		generateUUID4 : function(base){
1184			// based on http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
1185			// version 4 (base = 16)
1186			if (base < 2 || base > 62 ) { throw new Error('invalid base (2 to 62):' + base); }
1187			base = base || 16;
1188			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1189				var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
1190				return v.toString(16)
1191			}).split('-').map(function(v){ return $.toBase(parseInt(v, 16), base); }).join('-');
1192		},
1193		
1194	});
1195	
1196	var _imgtest = $('<img>')[0];
1197	_imgtest = 'naturalWidth' in _imgtest ? 0 : 'runtimeStyle' in _imgtest ? 1 : 2;
1198	
1199	function dumpHTMLElement(v) {
1200		if (v === window) return 'Window';
1201		if (v.nodeName) return v.nodeName + (v.id ? '#'+v.id : '') + (v.className ? ('.' + v.className.split(/\s+/).join('.')) : '');
1202		return "" + v;
1203	};
1204	
1205	var _toString = $.fn.toString;
1206	$.fn.extend({
1207		
1208		events: function(callback, type){
1209			/**
1210			 * console.log $elm jquery events or callback(ev_def)
1211			 */
1212			return $(this).each(function(){
1213				var root=this, elm=root;
1214				while (elm) {
1215					var evs = $._data(elm).events;
1216					if (!evs) { elm = elm.parentNode; continue; }
1217					Object.keys(evs).forEach(function(name){
1218						if (type && type != name) { return; }
1219						evs[name].forEach(function(evd){
1220							if (elm != root) {
1221								if (!evd.selector) { return; }
1222								if (!$(root).is(evd.selector, elm)) { return; }
1223							}
1224							(callback || console.info)(elm, evd);
1225						})
1226					});
1227					elm = elm.parentNode;
1228				}
1229			});
1230		},
1231		
1232		csses: function(properties_array){
1233			/**
1234			 * $elm.cssDict(['prop1', 'prop2', ...])
1235			 * -> { 'prop1':'value', 'prop2':'value', ... }
1236			 */
1237			var $elm = this, ret = {};
1238			properties_array.forEach(function(prop){
1239				ret[prop] = $elm.css(prop);
1240			});
1241			return ret;
1242		},
1243		
1244		assureUniqId: function(prefix, context){
1245			/**
1246			 * assure all elements ids are unique.
1247			 * if target element has already have unique id in context, no effect.
1248			 * if it doesn't have id or not unique, new unique (in the world) id is assigned.
1249			 * 'unique' is based on RFC4122 version4 and base62 encoded.
1250			 */
1251			// assign prefix + generated uuid(62) as elements id when it is not have id or id is not unique in context.
1252			prefix = prefix || 'asuq-';
1253			return $(this).each(function(){
1254				var org_id = $(this).attr('id');
1255				if (org_id) {
1256					if ($('[id]', context).filter(function(){ return this.id == org_id }).length > 1) {
1257						// duplicated id 
1258						console.error('assureUniqId:duplicated id is found:' + org_id, this );
1259						$(this).attr('data-duplicated-id', org_id);
1260					} else {
1261						// already have unique id in context
1262						return;
1263					}
1264				}
1265				$(this).attr('id', prefix + $.generateUUID4(62));
1266			});
1267		},
1268		
1269		reverse : [].reverse,
1270		
1271		spaceless : function(){
1272			/**
1273			 * remove empty text nodes between child elements
1274			 */
1275			return $(this).each(function(){
1276				$(this).contents().filter(function(){
1277					if (this.nodeType == 3) {
1278						return /^\s*$/.test(this.textContent);
1279					}
1280					return false;
1281				}).remove();
1282			});
1283		},
1284		
1285		// http://jsfiddle.net/g30rg3/x8Na8/171/
1286		// http://stackoverflow.com/questions/2360655/jquery-event-handlers-always-execute-in-order-they-were-bound-any-way-around-t
1287		bindFirst : function(name, fn) {
1288			this.on(name, fn);
1289			this.each(function(){
1290				var handlers = $._data(this, 'events')[name.split('.')[0]];
1291				var handler = handlers.pop();
1292				handlers.splice(0, 0, handler);
1293			});
1294		},
1295		
1296		toString : function(){
1297			if (this[0]) {
1298				return '[object jQuery:' + this.selector +':[' + this.map(function(i, v){return dumpHTMLElement(v);}).toArray().join(',') + ']]';
1299			}
1300			return _toString.call(this) + '';
1301		},
1302		
1303		tagName : function() {
1304			return this.nodeName;
1305		},
1306
1307		outerHTML : function(s) {
1308			if (s) {
1309				this.before(s);
1310				return s.append(this);
1311			} else {
1312				return $('<div>').append(this.clone()).html();
1313			}
1314		},
1315
1316		innerHTML : function(html) {
1317			if (arguments.length == 0) {
1318				return this.html();
1319			}
1320			this[0].innerHTML = html;
1321			return this;
1322		},
1323		
1324		naturalSize : function () {
1325			/**
1326			 * @return { width:<num>, height:<num>, src:"<src>" }, null : not img or no src or error, false : not loaded yet,
1327			 */
1328			var img = this[0];
1329			if (img.nodeName !== "IMG") {
1330				return null;
1331			}
1332			//var src = this[0].attr('src');
1333			if (!img.src) {
1334				return null;
1335			}
1336			if (img.complete === undefined || img.readyState == 'uninitialized') {
1337				return false;
1338			}
1339			var w, h;
1340			if (_imgtest == 0) {
1341				w = img.naturalWidth;
1342				h = img.naturalHeight;
1343			} else if (_imgtest == 1) {
1344				var img2 = new Image;
1345				img2.src = img.src;
1346				w = img2.width;
1347				h = img2.height;
1348			} else {
1349				var ow = img.width, oh = img.height;
1350				img.removeAttribute('width');
1351				img.removeAttribute('height');
1352				w = img.width;
1353				h = img.height;
1354				img.width = ow;
1355				img.height = oh;
1356			}
1357			if (img.complete == true && w === 0) {
1358				// img.complete and error on Chrome, Firefox, Safari
1359				return null;
1360			}
1361			return (w === 0 || w === undefined) ? false : {
1362				elm: this,
1363				src: this.attr('src'),
1364				width: w,
1365				height: h
1366			};
1367		},
1368		
1369		imagesLoaded : function(func, timeout){
1370			timeout = (timeout === undefined) ? 30 : timeout;
1371			var $images = $(this).find('img[src]').add( $(this).filter('img[src]') ).addClass('img_loading');
1372			var _d = $.Deferred(function(_d){
1373				var _ds = [];
1374				$images.each(function(){
1375					var _d = $.Deferred();
1376					_ds.push(_d);
1377					var $img = $(this);
1378					if ($img.naturalSize()) {
1379						$img.removeClass('img_loading');
1380						_d.resolve($img.naturalSize());
1381					} else {
1382						$img.one('load.imagesLoaded', function(){
1383							$.poll(function(){
1384								var size = $img.naturalSize();
1385								return size === false;
1386							}, -1, 20).always(function(){
1387								$img.removeClass('img_loading');
1388								_d.resolve($img.naturalSize());
1389							});
1390						}).one('error.imagesLoaded', function(){
1391							_d.resolve({
1392								'error ' : arguments
1393							});
1394							$img.removeClass('img_loading').addClass('img_load_error');
1395						});
1396						if ($img[0].complete || ($.browser.msie && $.browser.version < 9) ) {
1397							// for cached image
1398							$img.trigger('load');
1399						}
1400					}
1401				});
1402				$.when.apply(null, _ds).always(function(){
1403					func && func.call(this, $images);
1404					_d.resolve(arguments);
1405				});
1406			});
1407			return func ? $images : _d;
1408		},
1409		
1410		redraw : function(func) {
1411			return this.hide(0, function(){$(this).show(); func && func($(this)); });
1412		},
1413		
1414		overflowedX : function() {
1415			/* -5 for chrome bug (scrollHeight+1,2) */
1416			var ret = ( this[0].clientWidth < this[0].scrollWidth );
1417			return ret;
1418		},
1419		overflowedY : function() {
1420			/* -5 for chrome bug (scrollWidth+1,2) */
1421			var ret = (this[0].clientHeight < this[0].scrollHeight - 5);
1422			return ret;
1423		},
1424		overflowed : function() {
1425			return $(this).overflowedY() || $(this).overflowedX();
1426		},
1427		
1428		getFontSize : function() {
1429			if (document && document.defaultView && document.defaultView.getComputedStyle) {
1430				return parseInt(document.defaultView.getComputedStyle(this[0], null).fontSize);
1431			}
1432			var $tmp = $('#getFontSize')[0] ? $('#getFontSize') : $('<div id="getFontSize">').css({
1433				'width':'1em',
1434				'height':'1em',
1435				'line-height':'1em',
1436				'padding':0,
1437				'position':'absolute'
1438			}).appendTo('body');
1439			$tmp.appendTo(this).show();
1440			var ret = $tmp[0].offsetWidth;
1441			$tmp.appendTo('body').hide();
1442			return ret;
1443		},
1444		
1445		adjustFontSizeNoWrap : function(){
1446			// adust font size without auto-wrap
1447			this.each(function(){
1448				var $this = $(this).wrapInner('<div></div>');
1449				var $wrapped = $this.children('div').css({
1450					'white-space': 'nowrap',
1451					'padding' : 0,
1452					'margin' : 0,
1453					'width': 'auto',
1454					'font-size': 'inherit',
1455					'letter-spacing': 'inherit'
1456				});
1457				var ratio = $wrapped[0].clientWidth / $wrapped[0].scrollWidth;
1458				var fs = Math.floor($this.getFontSize() * ratio);
1459				if (ratio < 1) {
1460					$this.css('font-size', fs + 'px' );
1461					console.log('adjustFontSize():adjusted by ratio:' + $this + ':' + fs);
1462				}
1463				while (fs > 9 && $wrapped.css('white-space', 'normal').height() != $wrapped.css('white-space', 'wrapped').height()) {
1464					fs = Math.floor(fs * 0.9);
1465					$wrapped.css('font-size', fs + 'px');
1466				}
1467				console.log('adjustFontSize():adjusted by resize:' + $this + ':' + fs);
1468				
1469				$wrapped.contents().unwrap();
1470			});
1471			return this;
1472		},
1473		
1474		scrollIntoView : function(opts) {
1475			var o = this.offset();
1476			if (!o) { return this; }
1477			opts = $.extend({
1478				margin: 15
1479			}, opts);
1480			var margin = opts.margin;
1481			var container = window;
1482			var ct = $(container).scrollTop(), ch = container.clientHeight || $(container).height(), cb = ct + ch;
1483			var t = this.offset().top, h = this.outerHeight(), b = t + h;
1484			var nt = ct;
1485			if (t > cb) {
1486				nt = b - ch + margin;
1487				ct = nt;
1488			}
1489			if (b < ct) {
1490				nt = t - margin;
1491			} else if (t < ct) {
1492				nt = t - margin;
1493			}
1494			$(container).scrollTop(nt);
1495			return this;
1496		},
1497		
1498		scrollFixInView : function(do_scroll){
1499			/**
1500			 * save and restore position in view
1501			 * usage:
1502			 *     $elm.scrollFixInView(); // save
1503			 *     :
1504			 *     $elm.scrollFixInView(true); // do scroll on saved
1505			 */
1506			var $this = $(this);
1507			if (!$this.is(':visible')) { return; }
1508			if (!do_scroll){
1509				$this.data('_fixinview', $this[0].getBoundingClientRect());
1510			} else {
1511				$(window).scrollTop($this.offset().top - $this.data('_fixinview').top);
1512			}
1513			return this;
1514		},
1515		
1516		/* いまいち。childをいじってる系で使えない
1517		captureDocumentWrite : function(script) {
1518			var $this = $(this), state = {
1519				w : document.write,
1520				wl : document.writeln,
1521				buf : ''
1522			};
1523			console.log('captureDocumentWrite:' + script);
1524			document.write = function(str){
1525				state.buf += str;
1526			};
1527			document.writeln = function(str){
1528				sate.buf += str + '\n';
1529			};
1530			var $div = $('<div id="captureDocumentWrite">').appendTo($('body'));
1531			if (script.match(/^(https?:)?\/\//)){
1532				$('<div>').appendTo($div).replaceWith('<script src="' + script + '"></'+'script>');
1533				$.doLater(function(){
1534					console.log('captureDocumentWrite:captured:' + state.buf);
1535					$this.html(state.buf + $div.html());
1536					document.write = state.w;
1537					document.writeln = state.wl;
1538					state = null;
1539				}, 100);
1540			} else if (script[0] == '<') {
1541				$('<div>').appendTo($div).replaceWith(script);
1542				$.doLater(function(){
1543					console.log('captureDocumentWrite:captured:' + state.buf);
1544					$this.html(state.buf);
1545					document.write = state.w;
1546					document.writeln = state.wl;
1547					state = null;
1548				}, 100);
1549			} else {
1550				$('<div>').appendTo($this).replaceWith('<script>' + script + '</'+'script>');
1551				$.doLater(function(){
1552					console.log('captureDocumentWrite:captured:' + state.buf);
1553					$this.html(state.buf);
1554					document.write = state.w;
1555					document.writeln = state.wl;
1556					state = null;
1557				}, 100);
1558			}
1559			return this;
1560		}
1561		*/
1562		
1563		sortByPosition: function(reverse){
1564			var arr = this.toArray();
1565			arr.sort(function(a, b){
1566				if ( a === b) { return 0; }
1567				if ( !a.compareDocumentPosition ) { return a.sourceIndex - b.sourceIndex; } // for IE8- 
1568				if ( a.compareDocumentPosition(b) & 2 ) { return 1; }
1569				return -1;
1570			});
1571			if (reverse) {
1572				arr.reverse();
1573			}
1574			return $(arr);
1575		},
1576		
1577		findSelf: function(selector){
1578			return this.filter(selector).add(this.find(selector));
1579		},
1580		
1581		closestSelf: function(selector){
1582			if (this.is(selector)) { return this; }
1583			return this.closest(selector);
1584		},
1585		
1586	});
1587	
1588	var Mask = function(elem, opts) {
1589		this.opts = opts;
1590		this.$elem = $(elem);
1591	};
1592	
1593	// $.fn.cssHooks
1594	
1595	function getMetrics($elem){
1596		var h = $elem.outerHeight();
1597		var w = $elem.outerWidth();
1598		var t = $elem.position().top;
1599		var l = $elem.position().left;
1600		var margin = $elem.css('margin');
1601		var borderRadius = $elem.css('border-radius');
1602		return {
1603			'border-radius' : borderRadius,
1604			position: $elem.css('position') == 'fixed' ? 'fixed' : 'absolute',
1605			margin: margin,
1606			top: t + 'px',
1607			left: l + 'px',
1608			height: h + 'px',
1609			width: w + 'px',
1610			zIndex: $elem.css('z-index')
1611		};
1612	}
1613	
1614	Mask.prototype = {
1615		constructor: Mask,
1616		toggle : function(){
1617			return this[!!is_shown ? 'hide' : 'show'].apply(this, arguments);
1618		},
1619		show : function(opts, proc){
1620			var $elem = this.$elem.addClass('masked');
1621			this.is_shown && this.$mask.hide();
1622			opts = $.extend(this.opts, opts);
1623			var className = opts.className;
1624			className = className.call ? className(this.$elem) : className;
1625			var mask = this.$mask || this.$elem.next('.' + className);
1626			if (!mask[0]) {
1627				mask = $('<div>').addClass(className).appendTo(this.$elem.offsetParent());
1628			}
1629			var css = getMetrics($elem);
1630			mask = mask.clone();
1631			if (opts.html) {
1632				mask.append($(opts.html));
1633			}
1634			mask.css($.extend(opts.css, { opacity:opts.opacity, background:opts.background }, css))
1635				.appendTo(this.$elem.offsetParent());
1636			
1637			$elem.on('changemetrics.mask', function(){
1638				mask.css($.extend(opts.css, { opacity:opts.opacity, background:opts.background }, css = getMetrics($(this))));
1639			});
1640			
1641			proc && proc.call && proc.call(this, mask);
1642			this._org_style = $elem.attr('style');
1643			this._org_position = $elem.css('position');
1644			if (this._org_position == 'static') {
1645				$elem.css('position', 'relative');
1646			}
1647			this._org_display = $elem.css('display');
1648			if (this._org_display == 'inline') {
1649				$elem.css('display', 'inline-block');
1650			}
1651			mask.show();
1652			this.$mask = mask;
1653			this.is_shown = true;
1654		},
1655		hide : function(opts, proc){
1656			if (!this.is_shown){
1657				return;
1658			}
1659			this.$elem.off('changemetrics.mask');
1660			opts = $.extend(this.opts, opts);
1661			this.$elem.css('position', this._org_position);
1662			this.$elem.css('display', this._org_display);
1663			if (this._org_style) {
1664				this.$elem.attr('style', this._org_style);
1665			} else {
1666				this.$elem.removeAttr('style');
1667			}
1668			this.$elem.removeClass('masked');
1669			this.$mask.hide();
1670			this.is_shown = false;
1671		},
1672		destroy : function(){
1673			this.$elem.off('changemetrics.mask');
1674			this.hide();
1675			this.$mask && this.$mask.remove();
1676			this.$elem.removeData('mask').removeClass('masked');
1677		}
1678	};
1679	
1680	$.fn.mask = function(opts, proc){
1681		/**
1682		 * mask and unmask
1683		 * $(elem).mask();
1684		 * $(elem).mask({
1685		 *   show: true,
1686		 *   className : 'customMask' or function(elem){}
1687		 * });
1688		 * $(elem).mask('hide');
1689		 */
1690		if (typeof opts == 'function') {
1691			proc = opts;
1692			opts = {};
1693		}
1694		return this.each(function(){
1695			var $this = $(this), data = $this.data('mask'), 
1696				_opts = $.extend({}, $.fn.mask.defaults, $this.data(), typeof opts == 'object' && opts);
1697			if (!data) $this.data('mask', (data = new Mask(this, _opts)));
1698			if (typeof opts == 'string') data[opts](_opts, proc);
1699			else if (_opts.show) data.show(_opts, proc);
1700		});
1701	};
1702	
1703	$.fn.mask.defaults = {
1704		show : true,
1705		className : 'mask',
1706		css : {
1707			'display' : 'block',
1708			'position' : 'absolute',
1709			'-webkit-box-sizing' : 'border-box',
1710			'-moz-box-sizing' : 'border-box',
1711			'-mz-box-sizing' : 'border-box',
1712			'-o-box-sizing' : 'border-box',
1713			'box-sizing' : 'border-box'
1714		},
1715		html:''
1716	};
1717	
1718	// workaround for safari bug 
1719	//   getComputedStyle().getPropretyValue is not support shorthand
1720	$.doLater(function(){
1721		var s = $.setStyle('#cssstest { margin:10px; }
1721'), t = $('<div id="cssstest">').appendTo($('body'));
1722		if (t.css('margin') != t.css('margin-left')) {
1723			// alert('getComputedStylle is not support shorthand');
1724			function mapSubProp(prop, repl, repls){
1725				return $.closure([prop, repl], null, function(prop, sub, elem, computed, extra){
1726					$elem = $(elem);
1727					return $.map(repls, function(v){
1728						return $elem.css(prop.replace(repl, v));
1729					}).join(' ');
1730				});
1731			}
1732			function mapDirections(prop){
1733				return mapSubProp(prop, 'Direction', ['Top', 'Right', 'Bottom', 'Left']);
1734			}
1735			$.each({
1736				'margin': mapDirections('marginDirection'),
1737				'padding': mapDirections('paddingDirection'),
1738				'borderWidth': mapDirections('borderDirectionWidth'),
1739				'borderColor': mapDirections('borderDirectionColor'),
1740				'borderStyle': mapDirections('borderDirectionStyle'),
1741				'border' : mapSubProp('borderSub', 'Sub', ['Width', 'Color', 'Style']),
1742				'borderTop': mapDirections('borderTopDirection'),
1743				'borderRight': mapDirections('borderRightDirection'),
1744				'borderBottom': mapDirections('borderBottomDirection'),
1745				'borderLeft': mapDirections('borderLeftDirection'),
1746				'borderImage': mapSubProp('borderImageSub', 'Sub', ['Source', 'Slice', 'Width', 'Outset', 'Repeat']),
1747				'outline': mapSubProp('outlineSub', 'Sub', ['Color', 'Style', 'Width']),
1748				'borderRadius': mapSubProp('borderCornerRadius', 'Corner', ['TopLeft','TopRight','BottomRight','BottomLeft']),
1749				'font': mapSubProp('fontSub', 'Sub', ['Style', 'Veriant', 'Weight', 'Size', 'Family']), // XXX: size[/lineheight]
1750				'background': mapSubProp('backgroundSub', 'Sub', ['Color', 'Image', 'Repeat', 'Attachment', 'Position']),
1751				'listStyle': mapSubProp('listStyleSub', 'Sub', ['Type', 'Position', 'Image']),
1752				'transition': mapSubProp('transitionSub', 'Sub', ['Property', 'Duration', 'TimingFunction', 'Delay'])
1753			}, function(k, v){
1754				$.cssHooks[k] = {
1755					get : v,
1756					set : $.closure([k], null, function(prop, elem, value) {
1757						elem.style[k] = value;
1758					})
1759				};
1760			});
1761		}
1762		t.remove(); s.remove();
1763	},10);
1764	if ($.browser.msie) {
1765		// XXX: outerWidth is very slow...
1766	}
1767	
1768	if ($.browser.android) {
1769		// bug workaround type="date" on Android 4.0.4 Build/IMM76D
1770		$(document).on('focus', 'input[type="date"]', function(ev){
1771			$(this).val($(this).val().replace(/^(\d+)-(\d)-(\d+)$/, '$1-0$2-$3').replace(/^(\d+)-(\d+)-(\d)$/, '$1-$2-0$3'));
1772		});
1773	}
1774	
1775	// events
1776	
1777	// see http://stackoverflow.com/questions/1449666/create-a-jquery-special-event-for-content-changed
1778	$.fn.watch = function(id, opts) {
1779		/**
1780		 * Watch some value and trigger 'change', 'start' and 'end' function.
1781		 * $(elem).watch('some id', {
1782		 *   interval: 100,
1783		 *   watch: function(){
1784		 *     return $(this).some.watching.value;
1785		 *   },
1786		 *   onchange: function(id, mode, old, cur) {
1787		 *     if (mode == 'start') {...}
1788		 *     else if (mode == 'change') {...}
1789		 *     else if (mode == 'end') {...}
1790		 *   }
1791		 * });
1792		 */
1793		opts = $.extend({
1794			interval: 1000/30,
1795			watch: function(){},
1796			onchange: function(id, mode, old, cur){}
1797		}, opts);
1798		return this.each(function(){
1799			var _self = this;
1800			var o = opts.watch.call(_self), n, m = 0, s = 0;
1801			$(_self).data('watch_t', setInterval(function(){
1802				if ((n = opts.watch.call(_self)) !== o) {
1803					if (m == 0) {
1804						m = 1;
1805						s = n;
1806						opts.onchange.call(_self, id, 'start', o, n);
1807					} else {
1808						opts.onchange.call(_self, id, 'change', o, n, s);
1809					}
1810					o = n;
1811				} else {
1812					if (m == 1) {
1813						m = 0;
1814						opts.onchange.call(_self, id, 'end', s, n);
1815					}
1816				}
1817			}, opts.interval));
1818		});
1819	};
1820	
1821	$.fn.unwatch = function(id){
1822		return this.each(function(){
1823			clearInterval($(this).data('watch_t'));
1824		});
1825	};
1826	
1827	function watchScrollTop(){ return $(this).scrollTop(); }
1828	function watchSize(){ var t = $(this); return t.width() + ',' + t.height(); }
1829	function watchOverflow() {
1830		return $(this).innerHeight() < $(this)[0].scrollHeight;
1831	}
1832	function watchMetrics(){
1833		return $.toJSON(getMetrics($(this)));
1834	}
1835	
1836	$.each([
1837		['scrolling',	'scrolling', watchScrollTop, 'change'],
1838		['scrollstart',	'scrolling', watchScrollTop, 'start'],
1839		['scrolled',	'scrolling', watchScrollTop, 'end'],
1840		['resizing',	'resizing',  watchSize, 'change'],
1841		['resizestart',	'resizing',  watchSize, 'start'],
1842		['resized',		'resizing',  watchSize, 'end'],
1843		['overflow',  'overflow', watchOverflow, 'start'],
1844		['changemetrics',  'changemetrics', watchMetrics, 'start']
1845	], function(i, v){
1846		
1847		var eventType = v[0], watchId = v[1], watchFunc = v[2], watchType = v[3];
1848		$.event.special[eventType] = {
1849			setup: function(data, namespace, eventHandle){
1850				$(this).watch(watchId + '.' + watchType, {
1851					watch: watchFunc,
1852					onchange: function(id, type, old, cur, start){
1853						if (type == watchType) {
1854							var ev = $.Event(eventType);
1855							ev[eventType] = { start: start, old:old, cur: cur };
1856							$.event.dispatch.call(this, ev);
1857						}
1858					}
1859				});
1860			},
1861			teardown: function(){
1862				$(this).unwatch(watchId);
1863			}
1864		};
1865		
1866		$.fn[eventType] = function(fn){
1867			return this.on(eventType, fn);
1868		};
1869		
1870	});
1871	
1872	// fire resized on window when resize end
1873	console.log('set resized event on window');
1874	(function(w){
1875		var t = null;
1876		$(w).off('resized').on('resize', function(ev){
1877			clearTimeout(t);
1878			t = setTimeout(function(){
1879				$(window).trigger('resized', [ev]);
1880				t = null;
1881			}, 1000/30);
1882		});
1883	})(window);
1884	
1885	/* 重くなる : jquery-mobile-touch.js に移管
1886	var touch = null, has_android_touch_bug = ($.browser.android && $.browser.android.version >= "3.0.0" && $.browser.android.version < "4.1.0");
1887	
1888	function calcTouchDelta(){
1889		var radian = Math.atan2(touch.delta.y, touch.delta.x);
1890		var angle = Math.round(radian * 180 / Math.PI);
1891		if (angle < 0) {
1892			angle = 360 - Math.abs(angle);
1893		}
1894		touch.angle = angle;
1895		if (angle <= 45 || angle >= 315) {
1896			touch.direction = 'right';
1897		} else if (angle > 45 && angle < 135) {
1898			touch.direction = 'down';
1899		} else if (angle >= 135 && angle <= 225) {
1900			touch.direction = 'left';
1901		} else {
1902			touch.direction = 'up';
1903		}
1904		touch.distance = Math.round(Math.sqrt(Math.pow(touch.delta.x, 2)+Math.pow(touch.delta.y, 2)));
1905	}
1906	
1907	$(document).on('touchstart', function(ev){
1908		var oev = ev.originalEvent, ot = oev.touches ? oev.touches[0] : oev;
1909		touch = {
1910			start: {
1911				x: ot.clientX, y: ot.clientY,
1912				px: ot.pageX, py: ot.pageY
1913			},
1914			page_start: { x: ot.pageX, y: ot.pageY },
1915			target : ot.target
1916		};
1917	}).on('touchmove', function(ev){
1918		if (!touch) { return; }
1919		var oev = ev.originalEvent, ot = oev.touches ? oev.touches[0] : oev;
1920		touch.delta = {
1921			x: ot.clientX - touch.start.x,
1922			y: ot.clientY - touch.start.y,
1923			px: ot.pageX - touch.page_start.x,
1924			py: ot.pageY - touch.page_start.y,
1925			target: ot.target
1926		};
1927		// calcTouchDelta();
1928		if (has_android_touch_bug && Math.abs(touch.delta.y) < 5) {
1929			ev.preventDefault();
1930			$(touch.target).trigger($.Event('swiping', { origialEvent:ev, swipe:touch }));
1931		}
1932	}).on('touchend', function(ev){
1933		if (!touch || !touch.delta) { return; }
1934		// var oev = ev.originalEvent, ot = oev.touches ? oev.touches[0] : oev;
1935		touch.end = {
1936			x: touch.start.x + touch.delta.x,
1937			y: touch.start.y + touch.delta.y,
1938			px: touch.start.px + touch.delta.px,
1939			py: touch.start.py + touch.delta.py
1940		};
1941		calcTouchDelta();
1942		if (touch.distance > 30) {
1943			$(touch.target)
1944				.trigger($.Event('swipe', { originalEvent:ev, swipe:touch }))
1945				.trigger($.Event('swipe' + touch.direction, { originalEvent:ev, swipe: touch }));
1946			if (ev.type == 'mouseup') {
1947				ev.preventDefault();
1948			}
1949		}
1950		touch = null;
1951	});
1952	*/
1953	
1954	
1955	/********************************
1956	 * autogrow number of rows at textrea
1957	 * usage:
1958	 *   $jqueryobj.autogrow(opts);
1959	 *   $.autogrow(selector, opts);
1960	 * opts:
1961	 *   "destroy"
1962	 *   {
1963	 *      autoShrink: <bool:false>
1964	 *      minRows: <num:4>
1965	 *      // growRows: <num:4>  : obsolete
1966	 *      maxRows: <num:40>
1967	 *    }
1968	 *  event:
1969	 *    autogrowed: fire when textarea's row is changed
1970	 */
1971	(function (){
1972		
1973		var DEBUG = false;
1974		
1975		var AUTOGROW_EVENTS = 'focus.autogrow keyup.autogrow paste.autogrow change.autogrow';
1976		
1977		// https://github.com/Codecademy/textarea-helper/blob/master/textarea-helper.js
1978		var mirrorStyles = [
1979		// appearances,
1980		'-webkit-appearance', '-moz-appearance', '-ms-appearance', 'appearance',
1981		// Box Styles.
1982		'box-sizing', 'height', 'width', 'padding-bottom', 'padding-left', 'padding-right', 'padding-top'
1983		// Font stuff.
1984		, 'font-family', 'font-size', 'font-style', 'font-variant', 'font-weight'
1985		// Spacing etc.
1986		, 'word-spacing', 'letter-spacing', 'line-height', 'text-decoration', 'text-indent', 'text-transform'
1987		// Breaks
1988		,'word-break', 'word-wrap', 'overflow-wrap', 'white-space'
1989		// The direction.
1990		, 'direction' ];
1991		
1992		function getMirror($ta) {
1993			
1994			var $mirror = $('#autogrow-ta-mirror-div')
1995			if (!$mirror[0]) {
1996				$mirror = $('<div></div>')
1997					.attr('id', 'autogrow-ta-mirror-div')
1998					.css({
1999						// border:"1px solid red", // debug */
2000						visibility:'hidden',
2001						opacity:0,
2002						position:'absolute',
2003						top:'-9999px',
2004						left:'-9999px',
2005						zIndex:-1
2006					}).appendTo('body');
2007			}
2008			
2009			// Copy styles.
2010			var styles = {};
2011			for ( var i = 0, style; style = mirrorStyles[i]; i++) {
2012				styles[style] = $ta.css(style);
2013			}
2014			$mirror.css(styles).css({
2015				'height':'auto',
2016				'overflow-y':$ta[0].clientWidth < $ta[0].scrollWidth ? 'scroll' : 'visible',
2017				'overflow-x':'hidden'
2018			});
2019			// http://blog.jquery.com/2012/08/16/jquery-1-8-box-sizing-width-csswidth-and-outerwidth/
2020			if ($mirror.outerWidth() != $ta.outerWidth()) {
2021				// seems that box-sizing = border-box
2022				$mirror.css('width', $ta.outerWidth() + 'px' );
2023			}
2024			if ($.browser.ios) {
2025				$mirror.css('padding-left', parseFloat($ta.css('padding-left'),10) + 3 + 'px' );
2026				$mirror.css('padding-right', parseFloat($ta.css('padding-right'),10) + 3 + 'px' );
2027			}
2028			
2029			return $mirror;
2030		}
2031		
2032		var t = null;
2033		function ta_autogrow($ta) {
2034			clearTimeout(t);
2035			t = setTimeout(function() {
2036				_ta_autogrow($ta);
2037				t = null;
2038			}, 100);
2039		}
2040		
2041		function _ta_autogrow($ta) {
2042			if (!$ta.is(':visible')) { return; }
2043			
2044			// console.log('_ta_autogrow()', $ta);
2045			var text = $ta.val();
2046			var old_text = $ta.data('old_text');
2047			if (text == old_text) { return; }
2048			
2049			var opts = $ta.data('autogrow') || {};
2050			
2051			var $mirror = getMirror($ta);
2052			var _hfunc = $ta.css('box-sizing') == 'border-box' ? 'outerHeight' : 'height';
2053			
2054			$mirror.css({
2055				minHeight:0,
2056				maxheight:'none'
2057			});
2058			var minHeight = $mirror.html(new Array(opts.minRows).join('A<br>'))[_hfunc]();
2059			var maxHeight = $mirror.html(new Array(opts.maxRows).join('A<br>'))[_hfunc]();
2060			
2061			$ta.css({
2062				minHeight:+'px',
2063				maxHeight:+'px'
2064			});
2065			
2066			$mirror.html(
2067					text.replace(/&/g,'&amp;')
2068						.replace(/</g,'&lt;')
2069						.replace(/(\r\n|\r|\n)/g, '<br>')
2070						.replace(/<br>$/, '<br>&nbsp;')
2071						.replace(/^$/, '&nbsp;')
2072				);
2073			
2074			if (DEBUG) {
2075				$ta.css({
2076					background:'#ccf',
2077					borderRadius:0
2078				});
2079				$mirror.css({
2080					visibility:'visible',
2081					opacity:'1',
2082					zIndex:'1000',
2083					background:'#fcc',
2084					top:($ta.offset().top + $ta.outerHeight()) + 'px',
2085					left:($ta.offset().left) + 'px',
2086				});
2087			}
2088			
2089			var new_height = $mirror[_hfunc]();
2090			var old_height = $ta[_hfunc]();
2091			
2092			var vScrollbarHeight = 0;
2093			if ($ta.css('overflow-x') == 'scroll' || ($ta.css('overflow-x') == 'auto' && $ta.overflowedX())) {
2094				vScrollbarHeight = $.getScrollbarHeight();
2095			}
2096			
2097			if (opts.autoShrink) {
2098			} else {
2099				if (new_height + vScrollbarHeight < old_height) {
2100					return;
2101				}
2102			}
2103			
2104			$ta.height(new_height + vScrollbarHeight);
2105			
2106			if (new_height != old_height) {
2107				$ta.height(new_height + vScrollbarHeight);
2108				if ($.browser.iphone){
2109					// iPhoneのみなぜか2行のときにカーソル等が動かなかったりする
2110					if ($ta.height() <= maxHeight) {
2111						$ta.scrollTop(0).trigger('focus');
2112					}
2113				}
2114				$ta.trigger('autogrowed');
2115			}
2116		}
2117		
2118		$.extend({
2119			autogrow : function(selector, opts) {
2120				$(document)
2121					.off('focus.autogrow change.autogrow', selector)
2122					.on('focus.autogrow change.autogrow', selector, function(ev) {
2123						var $this = $(this);
2124						if ($this.data('autogrow')) {
2125							return;
2126						}
2127						return $this.autogrow(opts);
2128					});
2129			}
2130		});
2131		
2132		// IEがおかしい。
2133		// 影響が大きいのでデフォルトで入れるのはやめておく。
2134		// 使うときは textarea の font-family、font-sizeをCSSで設定すること(デフォルトに任せない)。
2135		// $.setStyle('textarea,input,select{font-size:inherit;font-family:inherit;}').prependTo('head');
2136		
2137		$.fn.extend({
2138			autogrow : function(opts) {
2139				/**
2140				 * auto grow height of textareas as no scrollbar.
2141				 */
2142				
2143				
2144				if (opts == 'destroy') {
2145					this.removeData('autogrow');
2146					return;
2147				}
2148				
2149				opts = $.extend({
2150					autoShrink : false,
2151					minRows : 4,
2152					// growRows : 4,
2153					maxRows : 40
2154				}, opts);
2155				if (opts.minRows < 1) { opts.minRows = 1; }
2156				// if (opts.growRows < 1){ opts.growRows = 1; }
2157				if (opts.maxRows < 1) { opts.maxRows = 1; }
2158				
2159				var t = null;
2160				
2161				return this.each(function() {
2162					var $ta = $(this);
2163					if (!$ta.is('textarea')) {
2164						return;
2165					}
2166					var pos = $ta.css('position');
2167					var disp = $ta.css('display');
2168					$ta.css({
2169						'word-break' : 'break-all',
2170						'overflow-y' : 'hidden',
2171						'height' : 'auto',
2172						'display' : disp == 'inline' ? 'inline-block' : disp,
2173						'position' : pos == 'static' ? 'relative' : pos
2174					});
2175					$ta.off(AUTOGROW_EVENTS)
2176						.on(AUTOGROW_EVENTS, function(ev) {
2177							// console.log(ev);
2178							var $ta = $(this), opts = $ta.data('autogrow');
2179							ta_autogrow($ta);
2180						});
2181					$ta.data('autogrow', opts);
2182					ta_autogrow($ta);
2183				});
2184			}
2185			
2186		});
2187	})();
2188	
2189	(function($){
2190		/* 領域クリアボタン */
2191		/**
2192		 * $.inputclear(selector, opts)
2193		 * $elm.inputclear(opts)
2194		 * opts: {
2195		 *   clear_image_url:'<url for clear button image - recommend svg>'
2196		 * }
2197		 */
2198		
2199		/* http://stackoverflow.com/questions/6258521/clear-icon-inside-input-text */
2200		/* svg data url generated
2201		 *  from: http://marketblog.envato.com/resources/25-icon-sets-svg-format/
2202		 *  change color by inkscape
2203		 *  base64 by b64.io
2204		 */
2205		
2206		var DEFAULTS = {
2207				clear_image_url:'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjgiICAgaGVpZ2h0PSI4IiAgIHZpZXdCb3g9IjAgMCA4IDgiICAgaWQ9InN2ZzIiICAgdmVyc2lvbj0iMS4xIiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiICAgc29kaXBvZGk6ZG9jbmFtZT0ieF90cmFuczUwLnN2ZyI+ICA8bWV0YWRhdGEgICAgIGlkPSJtZXRhZGF0YTEwIj4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGRlZnMgICAgIGlkPSJkZWZzOCIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMSIgICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiICAgICBncmlkdG9sZXJhbmNlPSIxMCIgICAgIGd1aWRldG9sZXJhbmNlPSIxMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTExOCIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjY4NSIgICAgIGlkPSJuYW1lZHZpZXc2IiAgICAgc2hvd2dyaWQ9ImZhbHNlIiAgICAgaW5rc2NhcGU6em9vbT0iMjkuNSIgICAgIGlua3NjYXBlOmN4PSI0IiAgICAgaW5rc2NhcGU6Y3k9IjQiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iNzMwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjM0OSIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmcyIiAvPiAgPHBhdGggICAgIGQ9Ik0xLjQxIDBsLTEuNDEgMS40MS43Mi43MiAxLjc4IDEuODEtMS43OCAxLjc4LS43Mi42OSAxLjQxIDEuNDQuNzItLjcyIDEuODEtMS44MSAxLjc4IDEuODEuNjkuNzIgMS40NC0xLjQ0LS43Mi0uNjktMS44MS0xLjc4IDEuODEtMS44MS43Mi0uNzItMS40NC0xLjQxLS42OS43Mi0xLjc4IDEuNzgtMS44MS0xLjc4LS43Mi0uNzJ6IiAgICAgaWQ9InBhdGg0IiAgICAgc3R5bGU9ImZpbGw6IzgwODA4MDtmaWxsLW9wYWNpdHk6MSIgLz48L3N2Zz4='
2208			};
2209		
2210		function setInputClearStyle(clear_image_url){
2211			// console.log('setInputClearStyle():' + clear_image_url);
2212			var style = [
2213					'.inputclear_shown {',
2214						'background-repeat:no-repeat;',
2215						'background-size:1em auto;',
2216						'background-position:right .1em top .2em;',
2217						'padding-right:1.4em!important;',
2218						
2219						'background-image:url(__IMG_URL__);',
2220					'}',
2221					'.inputclear_shown::-ms-clear { display:none; }',
2222					'.oninputclear { cursor:pointer; }'
2223				].join('')
2224				.replace('__IMG_URL__', clear_image_url||DEFAULTS.clear_image_url);
2225			$.setStyle(style, 'style-input-clear');
2226		}
2227		
2228		setInputClearStyle();
2229		
2230		function setInputClearToggle($input){
2231			// console.log('setInputClearToggle()', $input[0]);
2232			var shown = !!$input.val();
2233			$input.toggleClass('inputclear_shown', shown);
2234			var image_url = ($input.data('inputclear_opts')||{}).clear_image_url;
2235			if (image_url) {
2236				$input.css('background-image', shown?'url('+image_url+')':'none');
2237			}
2238		}
2239		
2240		function setInputClearOffsets($input){
2241			// console.log('setInputClearOffsets()', $input[0]);
2242			var offset = $input.offset(), w = $input.outerWidth(), h = $input.outerHeight();
2243			var ret = {
2244				'top':offset.top,
2245				'left':offset.left,
2246				'width':w,
2247				'height':h,
2248				'fs':parseFloat($input.css('font-size')) /* fontsize in pixel */
2249			}
2250			$input.data('offsets', ret);
2251			return ret;
2252		}
2253		
2254		function setInputClearCursor($input, ev){
2255			// console.log('setInputClearCursor()', $input[0]);
2256			var offsets = $input.data('offsets')||setInputClearOffsets($input);
2257			var oninputclear =
2258				ev.clientX > offsets.left + offsets.width - 1.3 * offsets.fs
2259				&& ev.clientY < offsets.top + 1.3 * offsets.fs;
2260			$input.toggleClass('oninputclear', oninputclear);
2261		}
2262		
2263		function doInputClear($input, ev) {
2264			if ($input.is('.oninputclear')) {
2265				// console.log('doInputClear()');
2266				ev.preventDefault();
2267				$input.removeClass('oninputclear').val('').trigger('change');
2268			}
2269		}
2270		
2271		function setEventsAll(target_selector) {
2272			$(document)
2273				.off('input.ic focus.ic change.ic', target_selector)
2274				.on('input.ic focus.ic change.ic', target_selector, function(ev){
2275					setInputClearToggle($(this));
2276				})
2277				.off('mouseenter.ic', target_selector)
2278				.on('mouseenter.ic', target_selector, function(ev){
2279					setInputClearOffsets($(this));
2280				})
2281				.off('mouseenter.ic', target_selector)
2282				.on('mousemove.ic', target_selector, function(ev){
2283					setInputClearCursor($(this), ev);
2284				})
2285				.off('touchstart.ic click.ic', target_selector)
2286				.on('touchstart.ic click.ic', target_selector, function(ev){
2287					doInputClear($(this), ev);
2288				});
2289		}
2290		
2291		function setEventsToElm($elm) {
2292			$elm
2293				.off('input.ic focus.ic change.ic')
2294				.on('input.ic focus.ic change.ic', function(ev){
2295					setInputClearToggle($(this));
2296				})
2297				.off('mouseenter.ic')
2298				.on('mouseenter.ic', function(ev){
2299					setInputClearOffsets($(this));
2300				})
2301				.off('mouseenter.ic')
2302				.on('mousemove.ic', function(ev){
2303					setInputClearCursor($(this), ev);
2304				})
2305				.off('touchstart.ic click.ic')
2306				.on('touchstart.ic click.ic', function(ev){
2307					doInputClear($(this), ev);
2308				});
2309		}
2310		
2311		var opts = {};
2312		$.extend({
2313			'inputclear':function(selector, opts){
2314				selector = selector === undefined ? 'input.clearable' : selector;
2315				var opts = $.extend({}, DEFAULTS, opts);
2316				setInputClearStyle(opts.clear_image_url);
2317				setEventsAll(selector);
2318			}
2319		});
2320		$.fn.extend({
2321			'inputclear':function(opts){
2322				return this.each(function(){
2323					var $input = $(this);
2324					var opts = $.extend({}, DEFAULTS, opts);
2325					$input.data('inputclear_ots', opts);
2326					setEventsToElm($input);
2327				});
2328			}
2329		});
2330		
2331	})($);
2332	
2333	// for-select toggle
2334	// <select name="xxx">..</select>
2335	// <div data-for-select="xxx" data-for-selected="val1">...</div>
2336	// <div data-for-select="xxx" data-for-selected="val2">...</div>
2337	// <div data-for-select="xxx" data-for-selected="val3">...</div>
2338	$(function(){
2339		function toggleForSelected($select){
2340			$select.each(function(){
2341				var $select = $(this), name=$select.attr('name'), selected = $select.val();
2342				$select.closest('form').find('[data-for-select][data-for-selected]').each(function(){
2343					var $t = $(this);
2344					if ($t.attr('data-for-select') == name){
2345						var hide = $t.attr('data-for-selected') != selected;
2346						$t.css('display', hide ? 'none' : '');
2347					}
2348				});
2349			});
2350		}
2351		$(document).on('change.forselect', 'select[name]', function(ev){
2352			toggleForSelected($(this));
2353		});
2354		toggleForSelected($('select[name]'));
2355	})
2356	
2357	// Deferred Queue
2358	// http://samarskyy.blogspot.jp/2011/10/jquery-deferred-queues.html
2359	function DeferredQueue(){
2360		this.promise = $(this).promise();
2361	}
2362	DeferredQueue.prototype.add = function(func, arg){
2363		/**
2364		 * var q = $.DeferredQueue();
2365		 * q.add(function(arg){ this.resolve() or this.reject() }, arg1, arg2, ...)
2366		 * q.add(function(arg){ this.resolve() or this.reject() }, arg1, arg2, ...)
2367		 */
2368		var _this = this;
2369		var args = Array.prototype.slice.call(arguments, 1);
2370		return this.promise = this.promise.then(function(){
2371			return $.Deferred(function(){
2372				try {
2373					return func.apply(this, args);
2374				} catch (ex) {
2375					this.reject(ex);
2376					return _this.promise = $(_this).promise();
2377				}
2378			}).promise();
2379		})
2380	};
2381	DeferredQueue.prototype.wait = function(wait_ms){
2382		this.add(function(){
2383			var _this = this;
2384			setTimeout(function(){
2385				_this.resolve();
2386			}, wait_ms);
2387		});
2388	};
2389	$.DeferredQueue = DeferredQueue;
2390	
2391	// LocalDate : for input[type="datetime-local"]
2392	$.toLocalDate = function(date){
2393		date = (date instanceof Date) ? date : new Date(date);
2394		return (new Date(date.getTime() - date.getTimezoneOffset() * 60000))
2395			.toISOString()
2396			.replace(/(Z|[+-]\d{2}(:?\d{2})?)$/, '');
2397	}
2398	$.fromLocalDate = function(localdate){
2399		var offset = new Date().getTimezoneOffset() * 60000;
2400		return new Date(new Date(localdate + 'Z').getTime() + offset);
2401	}
2402	
2403	function ajax_cached(opts, force_clear){
2404		// console.log('ajax_cached:\t' + opts.url);
2405		
2406		var cache_key = opts.url + ':' + JSON.stringify(opts.data || {}),
2407			cached = ajax_cached._cache[cache_key];
2408		if (!opts.cache || !cached || cached.state == 'error'){
2409			console.log('ajax_cached:regist\t' + cache_key);
2410			var _d = $.ajax(opts);
2411			_d.then(function(res){
2412				console.log('ajax_cached:success\t' + cache_key);
2413				ajax_cached._cache[cache_key] = {
2414					state: 'success',
2415					args: Array.from(arguments),
2416				};
2417			}).fail(function(){
2418				console.log('ajax_cached:error\t' + cache_key);
2419				ajax_cached._cache[cache_key] = {
2420					state: 'error',
2421					args: Array.from(arguments),
2422				};
2423			}).always(function(){
2424				ajax_cached._cache[cache_key]._expire_t = 
2425					setTimeout(function(cache_key){
2426						console.log('ajax_cached:expire\t' + cache_key);
2427						delete ajax_cached._cache[cache_key];
2428					}.bind(null, cache_key), ajax_cached._expire_ms);
2429			});
2430			var cache = {
2431				state: 'loading',
2432				_d: _d,
2433			};
2434			ajax_cached._cache[cache_key] = cache;
2435			return cache._d;
2436		} else if (cached.state == 'loading') {
2437			console.log('ajax_cached:wait\t' + cache_key);
2438			return cached._d;
2439		} else {
2440			console.log('ajax_cached:cached\t' + cache_key);
2441			var _d = $.Deferred();
2442			if (cached.state == 'success') {
2443				_d.resolve.apply(_d, cached.args);
2444			} else {
2445				_d.reject.apply(_d, cached.args);
2446			}
2447			return _d.promise();
2448		}
2449	}
2450	
2451	ajax_cached._cache = {};
2452	ajax_cached._expire_ms = 10 * 60 * 1000;
2453	
2454	$.extend({
2455		ajax_cached: ajax_cached,
2456	});	
2457})(jQuery);
2458(function ($) {
2459	// イベントの実行状態を保持するマップ(要素ごとに記憶)
2460	const loadedFlag = new WeakMap();
2461
2462	/**
2463	 * jQuery special event: 'windowonload'
2464	 * 
2465	 * 目的:
2466	 * - $(window).on('load') の代替として、jQuery 3 移行後でも警告なしで使える
2467	 * - ページが既に load 済みであっても確実にハンドラが1回だけ呼ばれる
2468	 * - $(function () { $(window).on('windowonload', fn); }) のような順序でも fn が必ず後から実行される
2469	 * - load 済み判定後の即時実行は setTimeout(..., 0) で defer され、順序保証される
2470	 * 
2471	 * 使用方法:
2472	 * $(window).on('windowonload', function (e) { ... });
2473	 * $(window).one('windowonload', function (e) { ... }); // 推奨:1回だけ実行される
2474	 * 
2475	 * 移行パターン:
2476	 * $(window).on('load', fn);              // 従来コード(警告あり)
2477	 * $(window).on('load windowonload', fn); // 移行期(警告出るが安全)
2478	 * $(window).on('windowonload', fn);      // 最終形(警告なし、順序保証あり)
2479	 */
2480	$.event.special.windowonload = {
2481		setup() {
2482			const el = this;
2483
2484			// このイベントは window 専用。それ以外では何もしない
2485			if (el !== window) return false;
2486
2487			// すでに登録済みであれば何もしない
2488			if (loadedFlag.get(el)) return false;
2489
2490			// 実行処理:一度だけ、setTimeout で defer して実行
2491			const runOnce = () => {
2492				if (!loadedFlag.get(el)) {
2493					loadedFlag.set(el, true);
2494					// defer により $(fn) より後に確実に発火する
2495					setTimeout(() => {
2496						$(el).triggerHandler('windowonload');
2497					}, 0);
2498				}
2499			};
2500
2501			// すでにページが load 済みなら即時実行
2502			if (document.readyState === 'complete') {
2503				runOnce();
2504				return false; // イベント登録は不要
2505			}
2506
2507			// まだ load 済みでなければ、ネイティブ load を一度だけ監視
2508			$(el).one('load', runOnce);
2509			return true;
2510		},
2511
2512		teardown() {
2513			// クリーンアップ処理(load イベントを解除)
2514			$(this).off('load');
2515		}
2516	};
2517})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.