Mukho

Add IP address in log

...@@ -122,6 +122,7 @@ io.sockets.on('connection', function(socket) { ...@@ -122,6 +122,7 @@ io.sockets.on('connection', function(socket) {
122 }) 122 })
123 }) 123 })
124 124
125 -server.listen(PORT, function(){ 125 +// 서버 가동(IPv4 형식으로 express 설정)
126 +server.listen(PORT, '127.0.0.1', function(){
126 console.log(logString+"서버가 시작되었습니다.(Port: "+PORT+")"); 127 console.log(logString+"서버가 시작되었습니다.(Port: "+PORT+")");
127 }); 128 });
...\ No newline at end of file ...\ No newline at end of file
......
1 +The MIT License (MIT)
2 +
3 +Copyright (c) 2014-2016 Aras Atasaygin
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 +is.js
2 +=====
3 +
4 +[![JS.ORG](https://img.shields.io/badge/js.org-is-ffb400.svg?style=flat-square)](http://js.org)
5 +
6 +####This is a general-purpose check library.
7 +- No dependencies
8 +- AMD, Node & browser ready
9 +
10 +####Usage:
11 +
12 +Node.js:
13 +```
14 +npm install is_js
15 +```
16 +
17 +Bower:
18 +```
19 +bower install is_js
20 +```
21 +
22 +Build:
23 +```
24 +npm run build
25 +```
26 +
27 +Test:
28 +```
29 +npm test
30 +```
31 +
32 +####Contributing:
33 +Thanks for considering to contribute. Check [here](CONTRIBUTING.md)
34 +
35 +####Contributors:
36 +Many thanks to our contributors: https://github.com/arasatasaygin/is.js/graphs/contributors
37 +
38 +Type checks
39 +===========
40 +
41 +is.arguments(value:any)
42 +-----------------------
43 +####Checks if the given value type is arguments.
44 +interfaces: not, all, any
45 +
46 +```javascript
47 +var getArguments = function() {
48 + return arguments;
49 +};
50 +var arguments = getArguments();
51 +
52 +is.arguments(arguments);
53 +=> true
54 +
55 +is.not.arguments({foo: 'bar'});
56 +=> true
57 +
58 +is.all.arguments(arguments, 'bar');
59 +=> false
60 +
61 +is.any.arguments(['foo'], arguments);
62 +=> true
63 +
64 +// 'all' and 'any' interfaces can also take array parameter
65 +is.all.arguments([arguments, 'foo', 'bar']);
66 +=> false
67 +```
68 +
69 +is.array(value:any)
70 +-------------------
71 +####Checks if the given value type is array.
72 +interfaces: not, all, any
73 +
74 +```javascript
75 +is.array(['foo', 'bar', 'baz']);
76 +=> true
77 +
78 +is.not.array({foo: 'bar'});
79 +=> true
80 +
81 +is.all.array(['foo'], 'bar');
82 +=> false
83 +
84 +is.any.array(['foo'], 'bar');
85 +=> true
86 +
87 +// 'all' and 'any' interfaces can also take array parameter
88 +is.all.array([[1, 2], 'foo', 'bar']);
89 +=> false
90 +```
91 +
92 +is.boolean(value:any)
93 +---------------------
94 +####Checks if the given value type is boolean.
95 +interfaces: not, all, any
96 +
97 +```javascript
98 +is.boolean(true);
99 +=> true
100 +
101 +is.not.boolean({foo: 'bar'});
102 +=> true
103 +
104 +is.all.boolean(true, 'bar');
105 +=> false
106 +
107 +is.any.boolean(true, 'bar');
108 +=> true
109 +
110 +// 'all' and 'any' interfaces can also take array parameter
111 +is.all.boolean([true, 'foo', 'bar']);
112 +=> false
113 +```
114 +
115 +is.date(value:any)
116 +------------------
117 +####Checks if the given value type is date.
118 +interfaces: not, all, any
119 +
120 +```javascript
121 +is.date(new Date());
122 +=> true
123 +
124 +is.not.date({foo: 'bar'});
125 +=> true
126 +
127 +is.all.date(new Date(), 'bar');
128 +=> false
129 +
130 +is.any.date(new Date(), 'bar');
131 +=> true
132 +
133 +// 'all' and 'any' interfaces can also take array parameter
134 +is.all.date([new Date(), 'foo', 'bar']);
135 +=> false
136 +```
137 +
138 +is.domNode(value:any)
139 +-----------------------------
140 +####Checks if the given object is a dom node.
141 +interfaces: not, all, any
142 +
143 +```javascript
144 +var obj = document.createElement('div');
145 +is.domNode(obj);
146 +=> true
147 +
148 +is.domNode({nope: 'nope'});
149 +=> false
150 +
151 +is.not.domNode({});
152 +=> true
153 +
154 +is.all.domNode(obj, obj);
155 +=> true
156 +
157 +is.any.domNode(obj, {nope: 'nope'});
158 +=> true
159 +
160 +// 'all' and 'any' interfaces can also take array parameter
161 +is.all.domNode([obj, {nope: 'nope'}]);
162 +=> false
163 +```
164 +
165 +is.error(value:any)
166 +-------------------
167 +####Checks if the given value type is error.
168 +interfaces: not, all, any
169 +
170 +```javascript
171 +is.error(new Error());
172 +=> true
173 +
174 +is.not.error({foo: 'bar'});
175 +=> true
176 +
177 +is.all.error(new Error(), 'bar');
178 +=> false
179 +
180 +is.any.error(new Error(), 'bar');
181 +=> true
182 +
183 +// 'all' and 'any' interfaces can also take array parameter
184 +is.all.error([new Error(), 'foo', 'bar']);
185 +=> false
186 +```
187 +
188 +is.function(value:any)
189 +----------------------
190 +####Checks if the given value type is function.
191 +interfaces: not, all, any
192 +
193 +```javascript
194 +is.function(toString);
195 +=> true
196 +
197 +is.not.function({foo: 'bar'});
198 +=> true
199 +
200 +is.all.function(toString, 'bar');
201 +=> false
202 +
203 +is.any.function(toString, 'bar');
204 +=> true
205 +
206 +// 'all' and 'any' interfaces can also take array parameter
207 +is.all.function([toString, 'foo', 'bar']);
208 +=> false
209 +```
210 +
211 +is.nan(value:any)
212 +-----------------
213 +####Checks if the given value type is NaN.
214 +interfaces: not, all, any
215 +
216 +```javascript
217 +is.nan(NaN);
218 +=> true
219 +
220 +is.not.nan(42);
221 +=> true
222 +
223 +is.all.nan(NaN, 1);
224 +=> false
225 +
226 +is.any.nan(NaN, 2);
227 +=> true
228 +
229 +// 'all' and 'any' interfaces can also take array parameter
230 +is.all.nan([NaN, 'foo', 1]);
231 +=> false
232 +```
233 +
234 +is.null(value:any)
235 +------------------
236 +####Checks if the given value type is null.
237 +interfaces: not, all, any
238 +
239 +```javascript
240 +is.null(null);
241 +=> true
242 +
243 +is.not.null(42);
244 +=> true
245 +
246 +is.all.null(null, 1);
247 +=> false
248 +
249 +is.any.null(null, 2);
250 +=> true
251 +
252 +// 'all' and 'any' interfaces can also take array parameter
253 +is.all.null([null, 'foo', 1]);
254 +=> false
255 +```
256 +
257 +is.number(value:any)
258 +--------------------
259 +####Checks if the given value type is number.
260 +interfaces: not, all, any
261 +
262 +```javascript
263 +is.number(42);
264 +=> true
265 +
266 +is.number(NaN);
267 +=> false
268 +
269 +is.not.number('42');
270 +=> true
271 +
272 +is.all.number('foo', 1);
273 +=> false
274 +
275 +is.any.number({}, 2);
276 +=> true
277 +
278 +// 'all' and 'any' interfaces can also take array parameter
279 +is.all.number([42, 'foo', 1]);
280 +=> false
281 +```
282 +
283 +is.object(value:any)
284 +--------------------
285 +####Checks if the given value type is object.
286 +interfaces: not, all, any
287 +
288 +```javascript
289 +is.object({foo: 'bar'});
290 +=> true
291 +
292 +// functions are also returning as true
293 +is.object(toString);
294 +=> true
295 +
296 +is.not.object('foo');
297 +=> true
298 +
299 +is.all.object({}, 1);
300 +=> false
301 +
302 +is.any.object({}, 2);
303 +=> true
304 +
305 +// 'all' and 'any' interfaces can also take array parameter
306 +is.all.object([{}, new Object()]);
307 +=> true
308 +```
309 +
310 +is.json(value:any)
311 +--------------------
312 +####Checks if the given value type is pure json object.
313 +interfaces: not, all, any
314 +
315 +```javascript
316 +is.json({foo: 'bar'});
317 +=> true
318 +
319 +// functions are returning as false
320 +is.json(toString);
321 +=> false
322 +
323 +is.not.json([]);
324 +=> true
325 +
326 +is.all.json({}, 1);
327 +=> false
328 +
329 +is.any.json({}, 2);
330 +=> true
331 +
332 +// 'all' and 'any' interfaces can also take array parameter
333 +is.all.json([{}, {foo: 'bar'}]);
334 +=> true
335 +```
336 +
337 +is.regexp(value:any)
338 +--------------------
339 +####Checks if the given value type is RegExp.
340 +interfaces: not, all, any
341 +
342 +```javascript
343 +is.regexp(/test/);
344 +=> true
345 +
346 +is.not.regexp(['foo']);
347 +=> true
348 +
349 +is.all.regexp(/test/, 1);
350 +=> false
351 +
352 +is.any.regexp(new RegExp('ab+c'), 2);
353 +=> true
354 +
355 +// 'all' and 'any' interfaces can also take array parameter
356 +is.all.regexp([{}, /test/]);
357 +=> false
358 +```
359 +
360 +is.string(value:any)
361 +--------------------
362 +####Checks if the given value type is string.
363 +interfaces: not, all, any
364 +
365 +```javascript
366 +is.string('foo');
367 +=> true
368 +
369 +is.not.string(['foo']);
370 +=> true
371 +
372 +is.all.string('foo', 1);
373 +=> false
374 +
375 +is.any.string('foo', 2);
376 +=> true
377 +
378 +// 'all' and 'any' interfaces can also take array parameter
379 +is.all.string([{}, 'foo']);
380 +=> false
381 +```
382 +
383 +is.char(value:any)
384 +--------------------
385 +####Checks if the given value type is char.
386 +interfaces: not, all, any
387 +
388 +```javascript
389 +is.char('f');
390 +=> true
391 +
392 +is.not.char(['foo']);
393 +=> true
394 +
395 +is.all.char('f', 1);
396 +=> false
397 +
398 +is.any.char('f', 2);
399 +=> true
400 +
401 +// 'all' and 'any' interfaces can also take array parameter
402 +is.all.char(['f', 'o', 'o']);
403 +=> true
404 +```
405 +
406 +is.undefined(value:any)
407 +-----------------------
408 +####Checks if the given value type is undefined.
409 +interfaces: not, all, any
410 +
411 +```javascript
412 +is.undefined(undefined);
413 +=> true
414 +
415 +is.not.undefined(null);
416 +=> true
417 +
418 +is.all.undefined(undefined, 1);
419 +=> false
420 +
421 +is.any.undefined(undefined, 2);
422 +=> true
423 +
424 +// 'all' and 'any' interfaces can also take array parameter
425 +is.all.undefined([{}, undefined]);
426 +=> false
427 +```
428 +
429 +is.sameType(value:any, other:any)
430 +---------------------------------
431 +####Checks if the given value types are same type.
432 +interface: not
433 +
434 +```javascript
435 +is.sameType(42, 7);
436 +=> true
437 +
438 +is.sameType(42, '7');
439 +=> false
440 +
441 +is.not.sameType(42, 7);
442 +=> false
443 +```
444 +
445 +is.windowObject(value:any)
446 +-----------------------------
447 +####Checks if the given object is window object.
448 +interfaces: not, all, any
449 +
450 +```javascript
451 +is.windowObject(window);
452 +=> true
453 +
454 +is.windowObject({nope: 'nope'});
455 +=> false
456 +
457 +is.not.windowObject({});
458 +=> true
459 +
460 +is.all.windowObject(window, {nope: 'nope'});
461 +=> false
462 +
463 +is.any.windowObject(window, {nope: 'nope'});
464 +=> true
465 +
466 +// 'all' and 'any' interfaces can also take array parameter
467 +is.all.windowObject([window, {nope: 'nope'}]);
468 +=> false
469 +```
470 +
471 +Presence checks
472 +===============
473 +
474 +is.empty(value:array|object|string)
475 +-----------------------------------
476 +####Checks if the given value is empty.
477 +interfaces: not, all, any
478 +
479 +```javascript
480 +is.empty({});
481 +=> true
482 +
483 +is.empty([]);
484 +=> true
485 +
486 +is.empty('');
487 +=> true
488 +
489 +is.not.empty(['foo']);
490 +=> true
491 +
492 +is.all.empty('', {}, ['foo']);
493 +=> false
494 +
495 +is.any.empty([], 42);
496 +=> true
497 +
498 +// 'all' and 'any' interfaces can also take array parameter
499 +is.all.empty([{}, 'foo']);
500 +=> false
501 +```
502 +
503 +is.existy(value:any)
504 +--------------------
505 +####Checks if the given value is existy. (not null or undefined)
506 +interfaces: not, all, any
507 +
508 +```javascript
509 +is.existy({});
510 +=> true
511 +
512 +is.existy(null);
513 +=> false
514 +
515 +is.not.existy(undefined);
516 +=> true
517 +
518 +is.all.existy(null, ['foo']);
519 +=> false
520 +
521 +is.any.existy(undefined, 42);
522 +=> true
523 +
524 +// 'all' and 'any' interfaces can also take array parameter
525 +is.all.existy([{}, 'foo']);
526 +=> true
527 +```
528 +
529 +is.truthy(value:any)
530 +--------------------
531 +####Checks if the given value is truthy. (existy and not false)
532 +interfaces: not, all, any
533 +
534 +```javascript
535 +is.truthy(true);
536 +=> true
537 +
538 +is.truthy(null);
539 +=> false
540 +
541 +is.not.truthy(false);
542 +=> true
543 +
544 +is.all.truthy(null, true);
545 +=> false
546 +
547 +is.any.truthy(undefined, true);
548 +=> true
549 +
550 +// 'all' and 'any' interfaces can also take array parameter
551 +is.all.truthy([{}, true]);
552 +=> true
553 +```
554 +
555 +is.falsy(value:any)
556 +-------------------
557 +####Checks if the given value is falsy.
558 +interfaces: not, all, any
559 +
560 +```javascript
561 +is.falsy(false);
562 +=> true
563 +
564 +is.falsy(null);
565 +=> true
566 +
567 +is.not.falsy(true);
568 +=> true
569 +
570 +is.all.falsy(null, false);
571 +=> true
572 +
573 +is.any.falsy(undefined, true);
574 +=> true
575 +
576 +// 'all' and 'any' interfaces can also take array parameter
577 +is.all.falsy([false, true, undefined]);
578 +=> false
579 +```
580 +
581 +is.space(value:any)
582 +----------------------
583 +####Checks if the given value is space.
584 +interfaces: not, all, any
585 +
586 +```javascript
587 +is.space(' ');
588 +=> true
589 +
590 +is.space('foo');
591 +=> false
592 +
593 +is.not.space(true);
594 +=> true
595 +
596 +is.all.space(' ', 'foo');
597 +=> false
598 +
599 +is.any.space(' ', true);
600 +=> true
601 +
602 +// 'all' and 'any' interfaces can also take array parameter
603 +is.all.space([' ', 'foo', undefined]);
604 +=> false
605 +```
606 +
607 +RegExp checks
608 +=============
609 +
610 +is.url(value:any)
611 +-----------------
612 +####Checks if the given value matches url regexp.
613 +interfaces: not, all, any
614 +
615 +```javascript
616 +is.url('http://www.test.com');
617 +=> true
618 +
619 +is.url('foo');
620 +=> false
621 +
622 +is.not.url(true);
623 +=> true
624 +
625 +is.all.url('http://www.test.com', 'foo');
626 +=> false
627 +
628 +is.any.url('http://www.test.com', true);
629 +=> true
630 +
631 +// 'all' and 'any' interfaces can also take array parameter
632 +is.all.url(['http://www.test.com', 'foo', undefined]);
633 +=> false
634 +```
635 +
636 +is.email(value:any)
637 +-------------------
638 +####Checks if the given value matches email regexp.
639 +interfaces: not, all, any
640 +
641 +```javascript
642 +is.email('test@test.com');
643 +=> true
644 +
645 +is.email('foo');
646 +=> false
647 +
648 +is.not.email('foo');
649 +=> true
650 +
651 +is.all.email('test@test.com', 'foo');
652 +=> false
653 +
654 +is.any.email('test@test.com', 'foo');
655 +=> true
656 +
657 +// 'all' and 'any' interfaces can also take array parameter
658 +is.all.email(['test@test.com', 'foo', undefined]);
659 +=> false
660 +```
661 +
662 +is.creditCard(value:any)
663 +------------------------
664 +####Checks if the given value matches credit card regexp.
665 +interfaces: not, all, any
666 +
667 +```javascript
668 +is.creditCard(378282246310005);
669 +=> true
670 +
671 +is.creditCard(123);
672 +=> false
673 +
674 +is.not.creditCard(123);
675 +=> true
676 +
677 +is.all.creditCard(378282246310005, 123);
678 +=> false
679 +
680 +is.any.creditCard(378282246310005, 123);
681 +=> true
682 +
683 +// 'all' and 'any' interfaces can also take array parameter
684 +is.all.creditCard([378282246310005, 123, undefined]);
685 +=> false
686 +```
687 +
688 +is.alphaNumeric(value:any)
689 +--------------------------
690 +####Checks if the given value matches alpha numeric regexp.
691 +interfaces: not, all, any
692 +
693 +```javascript
694 +is.alphaNumeric('alphaNu3er1k');
695 +=> true
696 +
697 +is.alphaNumeric('*?');
698 +=> false
699 +
700 +is.not.alphaNumeric('*?');
701 +=> true
702 +
703 +is.all.alphaNumeric('alphaNu3er1k', '*?');
704 +=> false
705 +
706 +is.any.alphaNumeric('alphaNu3er1k', '*?');
707 +=> true
708 +
709 +// 'all' and 'any' interfaces can also take array parameter
710 +is.all.alphaNumeric(['alphaNu3er1k', '*?']);
711 +=> false
712 +```
713 +
714 +is.timeString(value:any)
715 +------------------------
716 +####Checks if the given value matches time string regexp.
717 +interfaces: not, all, any
718 +
719 +```javascript
720 +is.timeString('13:45:30');
721 +=> true
722 +
723 +is.timeString('90:90:90');
724 +=> false
725 +
726 +is.not.timeString('90:90:90');
727 +=> true
728 +
729 +is.all.timeString('13:45:30', '90:90:90');
730 +=> false
731 +
732 +is.any.timeString('13:45:30', '90:90:90');
733 +=> true
734 +
735 +// 'all' and 'any' interfaces can also take array parameter
736 +is.all.timeString(['13:45:30', '90:90:90']);
737 +=> false
738 +```
739 +
740 +is.dateString(value:any)
741 +------------------------
742 +####Checks if the given value matches date string regexp.
743 +interfaces: not, all, any
744 +
745 +```javascript
746 +is.dateString('11/11/2011');
747 +=> true
748 +
749 +is.dateString('10-21-2012');
750 +=> true
751 +
752 +is.dateString('90/11/2011');
753 +=> false
754 +
755 +is.not.dateString('90/11/2011');
756 +=> true
757 +
758 +is.all.dateString('11/11/2011', '90/11/2011');
759 +=> false
760 +
761 +is.any.dateString('11-11-2011', '90/11/2011');
762 +=> true
763 +
764 +// 'all' and 'any' interfaces can also take array parameter
765 +is.all.dateString(['11/11/2011', '90/11/2011']);
766 +=> false
767 +```
768 +
769 +is.usZipCode(value:any)
770 +-----------------------
771 +####Checks if the given value matches US zip code regexp.
772 +interfaces: not, all, any
773 +
774 +```javascript
775 +is.usZipCode('02201-1020');
776 +=> true
777 +
778 +is.usZipCode('123');
779 +=> false
780 +
781 +is.not.usZipCode('123');
782 +=> true
783 +
784 +is.all.usZipCode('02201-1020', '123');
785 +=> false
786 +
787 +is.any.usZipCode('02201-1020', '123');
788 +=> true
789 +
790 +// 'all' and 'any' interfaces can also take array parameter
791 +is.all.usZipCode(['02201-1020', '123']);
792 +=> false
793 +```
794 +
795 +is.caPostalCode(value:any)
796 +--------------------------
797 +####Checks if the given value matches Canada postal code regexp.
798 +interfaces: not, all, any
799 +
800 +```javascript
801 +is.caPostalCode('L8V3Y1');
802 +=> true
803 +
804 +is.caPostalCode('L8V 3Y1');
805 +=> true
806 +
807 +is.caPostalCode('123');
808 +=> false
809 +
810 +is.not.caPostalCode('123');
811 +=> true
812 +
813 +is.all.caPostalCode('L8V3Y1', '123');
814 +=> false
815 +
816 +is.any.caPostalCode('L8V3Y1', '123');
817 +=> true
818 +
819 +// 'all' and 'any' interfaces can also take array parameter
820 +is.all.caPostalCode(['L8V3Y1', '123']);
821 +=> false
822 +```
823 +
824 +is.ukPostCode(value:any)
825 +------------------------
826 +####Checks if the given value matches UK post code regexp.
827 +interfaces: not, all, any
828 +
829 +```javascript
830 +is.ukPostCode('B184BJ');
831 +=> true
832 +
833 +is.ukPostCode('123');
834 +=> false
835 +
836 +is.not.ukPostCode('123');
837 +=> true
838 +
839 +is.all.ukPostCode('B184BJ', '123');
840 +=> false
841 +
842 +is.any.ukPostCode('B184BJ', '123');
843 +=> true
844 +
845 +// 'all' and 'any' interfaces can also take array parameter
846 +is.all.ukPostCode(['B184BJ', '123']);
847 +=> false
848 +```
849 +
850 +is.nanpPhone(value:any)
851 +-----------------------
852 +####Checks if the given value matches North American numbering plan phone regexp.
853 +interfaces: not, all, any
854 +
855 +```javascript
856 +is.nanpPhone('609-555-0175');
857 +=> true
858 +
859 +is.nanpPhone('123');
860 +=> false
861 +
862 +is.not.nanpPhone('123');
863 +=> true
864 +
865 +is.all.nanpPhone('609-555-0175', '123');
866 +=> false
867 +
868 +is.any.nanpPhone('609-555-0175', '123');
869 +=> true
870 +
871 +// 'all' and 'any' interfaces can also take array parameter
872 +is.all.nanpPhone(['609-555-0175', '123']);
873 +=> false
874 +```
875 +
876 +is.eppPhone(value:any)
877 +----------------------
878 +####Checks if the given value matches extensible provisioning protocol phone regexp.
879 +interfaces: not, all, any
880 +
881 +```javascript
882 +is.eppPhone('+90.2322456789');
883 +=> true
884 +
885 +is.eppPhone('123');
886 +=> false
887 +
888 +is.not.eppPhone('123');
889 +=> true
890 +
891 +is.all.eppPhone('+90.2322456789', '123');
892 +=> false
893 +
894 +is.any.eppPhone('+90.2322456789', '123');
895 +=> true
896 +
897 +// 'all' and 'any' interfaces can also take array parameter
898 +is.all.eppPhone(['+90.2322456789', '123']);
899 +=> false
900 +```
901 +
902 +is.socialSecurityNumber(value:any)
903 +----------------------------------
904 +####Checks if the given value matches social security number regexp.
905 +interfaces: not, all, any
906 +
907 +```javascript
908 +is.socialSecurityNumber('017-90-7890');
909 +=> true
910 +
911 +is.socialSecurityNumber('017907890');
912 +=> true
913 +
914 +is.socialSecurityNumber('123');
915 +=> false
916 +
917 +is.not.socialSecurityNumber('123');
918 +=> true
919 +
920 +is.all.socialSecurityNumber('017-90-7890', '123');
921 +=> false
922 +
923 +is.any.socialSecurityNumber('017907890', '123');
924 +=> true
925 +
926 +// 'all' and 'any' interfaces can also take array parameter
927 +is.all.socialSecurityNumber(['017-90-7890', '123']);
928 +=> false
929 +```
930 +
931 +is.affirmative(value:any)
932 +-------------------------
933 +####Checks if the given value matches affirmative regexp.
934 +interfaces: not, all, any
935 +
936 +```javascript
937 +is.affirmative('yes');
938 +=> true
939 +
940 +is.affirmative('no');
941 +=> false
942 +
943 +is.not.affirmative('no');
944 +=> true
945 +
946 +is.all.affirmative('yes', 'no');
947 +=> false
948 +
949 +is.any.affirmative('yes', 'no');
950 +=> true
951 +
952 +// 'all' and 'any' interfaces can also take array parameter
953 +is.all.affirmative(['yes', 'y', 'true', 't', 'ok', 'okay']);
954 +=> true
955 +```
956 +
957 +is.hexadecimal(value:any)
958 +-------------------------
959 +####Checks if the given value matches hexadecimal regexp.
960 +interfaces: not, all, any
961 +
962 +```javascript
963 +is.hexadecimal('f0f0f0');
964 +=> true
965 +
966 +is.hexadecimal('0xf0f0f0');
967 +=> true
968 +
969 +is.hexadecimal(2.5);
970 +=> false
971 +
972 +is.not.hexadecimal('string');
973 +=> true
974 +
975 +is.all.hexadecimal('ff', 'f50');
976 +=> true
977 +
978 +is.any.hexadecimal('0xff5500', true);
979 +=> true
980 +
981 +// 'all' and 'any' interfaces can also take array parameter
982 +is.all.hexadecimal(['fff', '333', 'f50']);
983 +=> true
984 +```
985 +
986 +is.hexColor(value:any)
987 +-------------------------
988 +####Checks if the given value matches hexcolor regexp.
989 +interfaces: not, all, any
990 +
991 +```javascript
992 +is.hexColor('#333');
993 +=> true
994 +
995 +is.hexColor('#3333');
996 +=> false
997 +
998 +is.not.hexColor(0.5);
999 +=> true
1000 +
1001 +is.all.hexColor('fff', 'f50');
1002 +=> true
1003 +
1004 +is.any.hexColor('ff5500', 0.5);
1005 +=> false
1006 +
1007 +// 'all' and 'any' interfaces can also take array parameter
1008 +is.all.hexColor(['fff', '333', 'f50']);
1009 +=> true
1010 +```
1011 +
1012 +is.ip(value:any)
1013 +-------------------------
1014 +####Checks if the given value matches ip regexp
1015 +interfaces: not, all, any
1016 +
1017 +```javascript
1018 +is.ip('198.156.23.5');
1019 +=> true
1020 +
1021 +is.ip('1.2..5');
1022 +=> false
1023 +
1024 +is.not.ip('8:::::::7');
1025 +=> true
1026 +
1027 +is.all.ip('0:1::4:ff5:54:987:C', '123.123.123.123');
1028 +=> true
1029 +
1030 +is.any.ip('123.8.4.3', '0.0.0.0');
1031 +=> true
1032 +
1033 +// 'all' and 'any' interfaces can also take array parameter
1034 +is.all.ip(['123.123.23.12', 'A:B:C:D:E:F:0:0']);
1035 +=> true
1036 +```
1037 +
1038 +is.ipv4(value:any)
1039 +-------------------------
1040 +####Checks if the given value matches ipv4 regexp
1041 +interfaces: not, all, any
1042 +
1043 +```javascript
1044 +is.ipv4('198.12.3.142');
1045 +=> true
1046 +
1047 +is.ipv4('1.2..5');
1048 +=> false
1049 +
1050 +is.not.ipv4('8:::::::7');
1051 +=> true
1052 +
1053 +is.all.ipv4('198.12.3.142', '123.123.123.123');
1054 +=> true
1055 +
1056 +is.any.ipv4('255.255.255.255', '850..1.4');
1057 +=> true
1058 +
1059 +// 'all' and 'any' interfaces can also take array parameter
1060 +is.all.ipv4(['198.12.3.142', '1.2.3']);
1061 +=> false
1062 +
1063 +```
1064 +
1065 +is.ipv6(value:any)
1066 +-------------------------
1067 +####Checks if the given value matches ipv6 regexp
1068 +interfaces: not, all, any
1069 +
1070 +```javascript
1071 +is.ipv6('2001:DB8:0:0:1::1');
1072 +=> true
1073 +
1074 +is.ipv6('985.12.3.4');
1075 +=> true
1076 +
1077 +is.not.ipv6('8:::::::7');
1078 +=> true
1079 +
1080 +is.all.ipv6('2001:DB8:0:0:1::1', '1:50:198:2::1:2:8');
1081 +=> true
1082 +
1083 +is.any.ipv6('255.255.255.255', '2001:DB8:0:0:1::1');
1084 +=> true
1085 +
1086 +// 'all' and 'any' interfaces can also take array parameter
1087 +is.all.ipv6(['2001:DB8:0:0:1::1', '1.2.3']);
1088 +=> false
1089 +```
1090 +
1091 +String checks
1092 +=============
1093 +
1094 +is.include(value:string, target:string)
1095 +-----------------------------------------
1096 +####Checks if the given string contains a substring.
1097 +interface: not
1098 +
1099 +```javascript
1100 +is.include('Some text goes here', 'text');
1101 +=> true
1102 +
1103 +is.include('test', 'text');
1104 +=> false
1105 +
1106 +is.not.include('test', 'text');
1107 +=> true
1108 +```
1109 +
1110 +is.upperCase(value:string)
1111 +--------------------------
1112 +####Checks if the given string is UPPERCASE.
1113 +interfaces: not, all, any
1114 +
1115 +```javascript
1116 +is.upperCase('YEAP');
1117 +=> true
1118 +
1119 +is.upperCase('nope');
1120 +=> false
1121 +
1122 +is.not.upperCase('Nope');
1123 +=> true
1124 +
1125 +is.all.upperCase('YEAP', 'nope');
1126 +=> false
1127 +
1128 +is.any.upperCase('YEAP', 'nope');
1129 +=> true
1130 +
1131 +// 'all' and 'any' interfaces can also take array parameter
1132 +is.all.upperCase(['YEAP', 'ALL UPPERCASE']);
1133 +=> true
1134 +```
1135 +
1136 +
1137 +is.lowerCase(value:string)
1138 +--------------------------
1139 +####Checks if the given string is lowercase.
1140 +interfaces: not, all, any
1141 +
1142 +```javascript
1143 +is.lowerCase('yeap');
1144 +=> true
1145 +
1146 +is.lowerCase('NOPE');
1147 +=> false
1148 +
1149 +is.not.lowerCase('Nope');
1150 +=> true
1151 +
1152 +is.all.lowerCase('yeap', 'NOPE');
1153 +=> false
1154 +
1155 +is.any.lowerCase('yeap', 'NOPE');
1156 +=> true
1157 +
1158 +// 'all' and 'any' interfaces can also take array parameter
1159 +is.all.lowerCase(['yeap', 'all lowercase']);
1160 +=> true
1161 +```
1162 +
1163 +is.startWith(value:string, target:string)
1164 +-------------------------------------------
1165 +####Checks if the given string starts with substring.
1166 +interface: not
1167 +
1168 +```javascript
1169 +is.startWith('yeap', 'ye');
1170 +=> true
1171 +
1172 +is.startWith('nope', 'ye');
1173 +=> false
1174 +
1175 +is.not.startWith('nope not that', 'not');
1176 +=> true
1177 +```
1178 +
1179 +is.endWith(value:string, target:string)
1180 +-----------------------------------------
1181 +####Checks if the given string ends with substring.
1182 +interfaces: not
1183 +
1184 +```javascript
1185 +is.endWith('yeap', 'ap');
1186 +=> true
1187 +
1188 +is.endWith('nope', 'no');
1189 +=> false
1190 +
1191 +is.not.endWith('nope not that', 'not');
1192 +=> true
1193 +
1194 +is.endWith('yeap that one', 'one');
1195 +=> true
1196 +```
1197 +
1198 +is.capitalized(value:string)
1199 +---------------------------------------------
1200 +####Checks if the given string is capitalized.
1201 +interfaces: not, all, any
1202 +
1203 +```javascript
1204 +is.capitalized('Yeap');
1205 +=> true
1206 +
1207 +is.capitalized('nope');
1208 +=> false
1209 +
1210 +is.not.capitalized('nope not capitalized');
1211 +=> true
1212 +
1213 +is.not.capitalized('nope Capitalized');
1214 +=> true
1215 +
1216 +is.all.capitalized('Yeap', 'All', 'Capitalized');
1217 +=> true
1218 +
1219 +is.any.capitalized('Yeap', 'some', 'Capitalized');
1220 +=> true
1221 +
1222 +// 'all' and 'any' interfaces can also take array parameter
1223 +is.all.capitalized(['Nope', 'not']);
1224 +=> false
1225 +```
1226 +
1227 +is.palindrome(value:string)
1228 +---------------------------------------------
1229 +####Checks if the given string is palindrome.
1230 +interfaces: not, all, any
1231 +
1232 +```javascript
1233 +is.palindrome('testset');
1234 +=> true
1235 +
1236 +is.palindrome('A man, a plan, a canal - Panama!');
1237 +=> true
1238 +
1239 +is.palindrome('nope');
1240 +=> false
1241 +
1242 +is.not.palindrome('nope not palindrome');
1243 +=> true
1244 +
1245 +is.not.palindrome('tt');
1246 +=> false
1247 +
1248 +is.all.palindrome('testset', 'tt');
1249 +=> true
1250 +
1251 +is.any.palindrome('Yeap', 'some', 'testset');
1252 +=> true
1253 +
1254 +// 'all' and 'any' interfaces can also take array parameter
1255 +is.all.palindrome(['Nope', 'testset']);
1256 +=> false
1257 +```
1258 +
1259 +Arithmetic checks
1260 +=================
1261 +
1262 +is.equal(value:any, other:any)
1263 +------------------------------
1264 +####Checks if the given values are equal.
1265 +interfaces: not
1266 +
1267 +```javascript
1268 +is.equal(42, 40 + 2);
1269 +=> true
1270 +
1271 +is.equal('yeap', 'yeap');
1272 +=> true
1273 +
1274 +is.equal(true, true);
1275 +=> true
1276 +
1277 +is.not.equal('yeap', 'nope');
1278 +=> true
1279 +```
1280 +
1281 +is.even(value:number)
1282 +---------------------
1283 +####Checks if the given value is even.
1284 +interfaces: not, all, any
1285 +
1286 +```javascript
1287 +is.even(42);
1288 +=> true
1289 +
1290 +is.not.even(41);
1291 +=> true
1292 +
1293 +is.all.even(40, 42, 44);
1294 +=> true
1295 +
1296 +is.any.even(39, 42, 43);
1297 +=> true
1298 +
1299 +// 'all' and 'any' interfaces can also take array parameter
1300 +is.all.even([40, 42, 43]);
1301 +=> false
1302 +```
1303 +
1304 +is.odd(value:number)
1305 +--------------------
1306 +####Checks if the given value is odd.
1307 +interfaces: not, all, any
1308 +
1309 +```javascript
1310 +is.odd(41);
1311 +=> true
1312 +
1313 +is.not.odd(42);
1314 +=> true
1315 +
1316 +is.all.odd(39, 41, 43);
1317 +=> true
1318 +
1319 +is.any.odd(39, 42, 44);
1320 +=> true
1321 +
1322 +// 'all' and 'any' interfaces can also take array parameter
1323 +is.all.odd([40, 42, 43]);
1324 +=> false
1325 +```
1326 +
1327 +is.positive(value:number)
1328 +-------------------------
1329 +####Checks if the given value is positive.
1330 +interfaces: not, all, any
1331 +
1332 +```javascript
1333 +is.positive(41);
1334 +=> true
1335 +
1336 +is.not.positive(-42);
1337 +=> true
1338 +
1339 +is.all.positive(39, 41, 43);
1340 +=> true
1341 +
1342 +is.any.positive(-39, 42, -44);
1343 +=> true
1344 +
1345 +// 'all' and 'any' interfaces can also take array parameter
1346 +is.all.positive([40, 42, -43]);
1347 +=> false
1348 +```
1349 +
1350 +is.negative(value:number)
1351 +-------------------------
1352 +####Checks if the given value is negative.
1353 +interfaces: not, all, any
1354 +
1355 +```javascript
1356 +is.negative(-41);
1357 +=> true
1358 +
1359 +is.not.negative(42);
1360 +=> true
1361 +
1362 +is.all.negative(-39, -41, -43);
1363 +=> true
1364 +
1365 +is.any.negative(-39, 42, 44);
1366 +=> true
1367 +
1368 +// 'all' and 'any' interfaces can also take array parameter
1369 +is.all.negative([40, 42, -43]);
1370 +=> false
1371 +```
1372 +
1373 +is.above(value:number, min:number)
1374 +---------------------------
1375 +####Checks if the given value is above minimum value.
1376 +interface: not
1377 +
1378 +```javascript
1379 +is.above(41, 30);
1380 +=> true
1381 +
1382 +is.not.above(42, 50);
1383 +=> true
1384 +```
1385 +
1386 +is.under(value:number, max:number)
1387 +---------------------------
1388 +####Checks if the given value is under maximum value.
1389 +interface: not
1390 +
1391 +```javascript
1392 +is.under(30, 35);
1393 +=> true
1394 +
1395 +is.not.under(42, 30);
1396 +=> true
1397 +```
1398 +
1399 +is.within(value:number, min:number, max:number)
1400 +---------------------------------
1401 +####Checks if the given value is within minimum and maximum values.
1402 +interface: not
1403 +
1404 +```javascript
1405 +is.within(30, 20, 40);
1406 +=> true
1407 +
1408 +is.not.within(40, 30, 35);
1409 +=> true
1410 +```
1411 +
1412 +is.decimal(value:number)
1413 +------------------------
1414 +####Checks if the given value is decimal.
1415 +interfaces: not, all, any
1416 +
1417 +```javascript
1418 +is.decimal(41.5);
1419 +=> true
1420 +
1421 +is.not.decimal(42);
1422 +=> true
1423 +
1424 +is.all.decimal(39.5, 41.5, -43.5);
1425 +=> true
1426 +
1427 +is.any.decimal(-39, 42.5, 44);
1428 +=> true
1429 +
1430 +// 'all' and 'any' interfaces can also take array parameter
1431 +is.all.decimal([40, 42.5, -43]);
1432 +=> false
1433 +```
1434 +
1435 +is.integer(value:number)
1436 +------------------------
1437 +####Checks if the given value is integer.
1438 +interfaces: not, all, any
1439 +
1440 +```javascript
1441 +is.integer(41);
1442 +=> true
1443 +
1444 +is.not.integer(42.5);
1445 +=> true
1446 +
1447 +is.all.integer(39, 41, -43);
1448 +=> true
1449 +
1450 +is.any.integer(-39, 42.5, 44);
1451 +=> true
1452 +
1453 +// 'all' and 'any' interfaces can also take array parameter
1454 +is.all.integer([40, 42.5, -43]);
1455 +=> false
1456 +```
1457 +
1458 +is.finite(value:number)
1459 +-----------------------
1460 +####Checks if the given value is finite.
1461 +interfaces: not, all, any
1462 +
1463 +```javascript
1464 +is.finite(41);
1465 +=> true
1466 +
1467 +is.not.finite(42 / 0);
1468 +=> true
1469 +
1470 +is.all.finite(39, 41, -43);
1471 +=> true
1472 +
1473 +is.any.finite(-39, Infinity, 44);
1474 +=> true
1475 +
1476 +// 'all' and 'any' interfaces can also take array parameter
1477 +is.all.finite([Infinity, -Infinity, 42.5]);
1478 +=> false
1479 +```
1480 +
1481 +is.infinite(value:number)
1482 +-------------------------
1483 +####Checks if the given value is infinite.
1484 +interfaces: not, all, any
1485 +
1486 +```javascript
1487 +is.infinite(Infinity);
1488 +=> true
1489 +
1490 +is.not.infinite(42);
1491 +=> true
1492 +
1493 +is.all.infinite(Infinity, -Infinity, -43 / 0);
1494 +=> true
1495 +
1496 +is.any.infinite(-39, Infinity, 44);
1497 +=> true
1498 +
1499 +// 'all' and 'any' interfaces can also take array parameter
1500 +is.all.infinite([Infinity, -Infinity, 42.5]);
1501 +=> false
1502 +```
1503 +
1504 +Object checks
1505 +=============
1506 +
1507 +is.propertyCount(value:object, count:number)
1508 +-------------------------------------
1509 +####Checks if objects' property count is equal to given count.
1510 +interface: not
1511 +
1512 +```javascript
1513 +is.propertyCount({this: 'is', 'sample': object}, 2);
1514 +=> true
1515 +
1516 +is.propertyCount({this: 'is', 'sample': object}, 3);
1517 +=> false
1518 +
1519 +is.not.propertyCount({}, 2);
1520 +=> true
1521 +```
1522 +
1523 +is.propertyDefined(value:object, property:string)
1524 +------------------------------------------
1525 +####Checks if the given property is defined on object.
1526 +interface: not
1527 +
1528 +```javascript
1529 +is.propertyDefined({yeap: 'yeap'}, 'yeap');
1530 +=> true
1531 +
1532 +is.propertyDefined({yeap: 'yeap'}, 'nope');
1533 +=> false
1534 +
1535 +is.not.propertyDefined({}, 'nope');
1536 +=> true
1537 +```
1538 +
1539 +Array checks
1540 +============
1541 +
1542 +is.inArray(value:any, array)
1543 +---------------------
1544 +####Checks if the given item is in array?
1545 +interface: not
1546 +```javascript
1547 +is.inArray(2, [1, 2, 3]);
1548 +=> true
1549 +
1550 +is.inArray(4, [1, 2, 3]);
1551 +=> false
1552 +
1553 +is.not.inArray(4, [1, 2, 3]);
1554 +=> true
1555 +```
1556 +
1557 +is.sorted(value:array, sign:string)
1558 +----------------------
1559 +####Checks if the given array is sorted. Sign is optional parameter.
1560 +interfaces: not, all, any
1561 +
1562 +```javascript
1563 +is.sorted([1, 2, 3]);
1564 +=> true
1565 +
1566 +is.sorted([1, 2, 4, 3]);
1567 +=> false
1568 +
1569 +is.sorted([1, 1, 2, 2], '>=');
1570 +=> true
1571 +
1572 +is.sorted([1, 2, 3, 4], '>');
1573 +=> true
1574 +
1575 +is.sorted([4, 3, 3, 1], '<=');
1576 +=> true
1577 +
1578 +is.sorted([4, 3, 2, 1], '<');
1579 +=> true
1580 +
1581 +is.sorted([1, 2, 3, 3], '>');
1582 +=> false
1583 +
1584 +is.not.sorted([5, 4, 3]);
1585 +=> true
1586 +
1587 +is.not.sorted([5, 4, 3], '<');
1588 +=> false
1589 +
1590 +is.all.sorted([1, 2], [3, 4]);
1591 +=> true
1592 +
1593 +is.any.sorted([1, 2], [5, 4]);
1594 +=> true
1595 +
1596 +// 'all' and 'any' interfaces can also take array parameter
1597 +is.all.sorted([[1, 2], [5, 4]]);
1598 +=> false
1599 +```
1600 +
1601 +Environment checks
1602 +==================
1603 +####Environment checks are not available as node module.
1604 +
1605 +is.ie(range:number|string)
1606 +-------------------
1607 +####Checks if current browser is ie. Parameter is optional version range (or number) of browser.
1608 +interface: not
1609 +
1610 +```javascript
1611 +is.ie();
1612 +=> true if current browser is ie
1613 +
1614 +is.not.ie();
1615 +=> false if current browser is ie
1616 +
1617 +// also supports version number
1618 +is.ie(10);
1619 +=> true if current version of ie is 10
1620 +
1621 +is.ie('>=10');
1622 +=> true if current version of ie is greater than or equal to 10
1623 +
1624 +is.not.ie('<9');
1625 +=> true if current version of ie is not less than 9
1626 +```
1627 +
1628 +is.chrome(range:number|string)
1629 +-----------
1630 +####Checks if current browser is chrome. Parameter is optional version range (or number) of browser.
1631 +interface: not
1632 +
1633 +```javascript
1634 +is.chrome();
1635 +=> true if current browser is chrome
1636 +
1637 +is.not.chrome();
1638 +=> false if current browser is chrome
1639 +
1640 +// also supports version number
1641 +is.chrome(50);
1642 +=> true if current version of chrome is 50
1643 +
1644 +is.chrome('>=40');
1645 +=> true if current version of chrome is greater than or equal to 40
1646 +
1647 +is.not.chrome('<30');
1648 +=> true if current version of chrome is not less than 30
1649 +```
1650 +
1651 +is.firefox(range:number|string)
1652 +------------
1653 +####Checks if current browser is firefox. Parameter is optional version range (or number) of browser.
1654 +interface: not
1655 +
1656 +```javascript
1657 +is.firefox();
1658 +=> true if current browser is firefox
1659 +
1660 +is.not.firefox();
1661 +=> false if current browser is firefox
1662 +
1663 +// also supports version number
1664 +is.firefox(41);
1665 +=> true if current version of firefox is 41
1666 +
1667 +is.firefox('>=40');
1668 +=> true if current version of firefox is greater than or equal to 40
1669 +
1670 +is.not.firefox('<30');
1671 +=> true if current version of firefox is not less than 30
1672 +```
1673 +
1674 +is.edge(range:number|string)
1675 +------------
1676 +####Checks if current browser is edge. Parameter is optional version range (or number) of browser.
1677 +interface: not
1678 +
1679 +```javascript
1680 +is.edge();
1681 +=> true if current browser is edge
1682 +
1683 +is.not.edge();
1684 +=> false if current browser is edge
1685 +
1686 +// also supports version number
1687 +is.edge(13);
1688 +=> true if current version of edge is 13
1689 +
1690 +is.edge('>=12');
1691 +=> true if current version of edge is greater than or equal to 12
1692 +
1693 +is.not.edge('<13');
1694 +=> true if current version of edge is not less than 13
1695 +```
1696 +
1697 +is.opera(range:number|string)
1698 +----------
1699 +####Checks if current browser is opera. Parameter is optional version range (or number) of browser.
1700 +interface: not
1701 +
1702 +```javascript
1703 +is.opera();
1704 +=> true if current browser is opera
1705 +
1706 +is.not.opera();
1707 +=> false if current browser is opera
1708 +
1709 +// also supports version number
1710 +is.opera(36);
1711 +=> true if current version of opera is 36
1712 +
1713 +is.opera('>=35');
1714 +=> true if current version of opera is greater than or equal to 35
1715 +
1716 +is.not.opera('<20');
1717 +=> true if current version of opera is not less than 20
1718 +```
1719 +
1720 +is.safari(range:number|string)
1721 +-----------
1722 +####Checks if current browser is safari. Parameter is optional version range (or number) of browser.
1723 +interface: not
1724 +
1725 +```javascript
1726 +is.safari();
1727 +=> true if current browser is safari
1728 +
1729 +is.not.safari();
1730 +=> false if current browser is safari
1731 +
1732 +// also supports version number
1733 +is.safari(9);
1734 +=> true if current version of safari is 9
1735 +
1736 +is.safari('>=8');
1737 +=> true if current version of safari is greater than or equal to 8
1738 +
1739 +is.not.safari('<7');
1740 +=> true if current version of safari is not less than 7
1741 +```
1742 +
1743 +is.phantom(range:number|string)
1744 +-----------
1745 +####Checks if current browser is phantomjs. Parameter is optional version range (or number) of browser.
1746 +interface: not
1747 +
1748 +```javascript
1749 +is.phantom();
1750 +=> true if current browser is phantomjs
1751 +
1752 +is.not.phantom();
1753 +=> false if current browser is phantomjs
1754 +
1755 +// also supports version number
1756 +is.phantom(2);
1757 +=> true if current version of phantom is 2
1758 +
1759 +is.phantom('>=1');
1760 +=> true if current version of phantomjs is greater than or equal to 1
1761 +
1762 +is.not.phantom('<2');
1763 +=> true if current version of phantomjs is not less than 2
1764 +```
1765 +
1766 +is.ios()
1767 +--------
1768 +####Checks if current device has ios.
1769 +interface: not
1770 +
1771 +```javascript
1772 +is.ios();
1773 +=> true if current device is iPhone, iPad or iPod
1774 +
1775 +is.not.ios();
1776 +=> true if current device is not iPhone, iPad or iPod
1777 +```
1778 +
1779 +is.iphone(range:number|string)
1780 +-----------
1781 +####Checks if current device is iPhone. Parameter is optional version range (or number) of browser.
1782 +interface: not
1783 +
1784 +```javascript
1785 +is.iphone();
1786 +=> true if current device is iPhone
1787 +
1788 +is.not.iphone();
1789 +=> true if current device is not iPhone
1790 +
1791 +// also supports version number
1792 +is.iphone(9);
1793 +=> true if current version of iPhone is 9
1794 +
1795 +is.iphone('>=7');
1796 +=> true if current version of iPhone is greater than or equal to 7
1797 +
1798 +is.not.iphone('<8');
1799 +=> true if current version of iPhone is not less than 8
1800 +```
1801 +
1802 +is.ipad(range:number|string)
1803 +---------
1804 +####Checks if current device is iPad.
1805 +interface: not
1806 +
1807 +```javascript
1808 +is.ipad();
1809 +=> true if current device is iPad
1810 +
1811 +is.not.ipad();
1812 +=> true if current device is not iPad
1813 +
1814 +// also supports version number
1815 +is.ipad(9);
1816 +=> true if current version of iPad is 9
1817 +
1818 +is.ipad('>=7');
1819 +=> true if current version of iPad is greater than or equal to 7
1820 +
1821 +is.not.ipad('<8');
1822 +=> true if current version of iPad is not less than 8
1823 +```
1824 +
1825 +is.ipod(range:number|string)
1826 +---------
1827 +####Checks if current device is iPod.
1828 +interface: not
1829 +
1830 +```javascript
1831 +is.ipod();
1832 +=> true if current device is iPod
1833 +
1834 +is.not.ipod();
1835 +=> true if current device is not iPod
1836 +
1837 +// also supports version number
1838 +is.ipod(7);
1839 +=> true if current version of iPod is 7
1840 +
1841 +is.ipod('>=5');
1842 +=> true if current version of iPod is greater than or equal to 5
1843 +
1844 +is.not.ipod('<5');
1845 +=> true if current version of iPod is not less than 5
1846 +```
1847 +
1848 +is.android()
1849 +------------
1850 +####Checks if current device has Android.
1851 +interface: not
1852 +
1853 +```javascript
1854 +is.android();
1855 +=> true if current device has Android OS
1856 +
1857 +is.not.android();
1858 +=> true if current device has not Android OS
1859 +```
1860 +
1861 +is.androidPhone()
1862 +-----------------
1863 +####Checks if current device is Android phone.
1864 +interface: not
1865 +
1866 +```javascript
1867 +is.androidPhone();
1868 +=> true if current device is Android phone
1869 +
1870 +is.not.androidPhone();
1871 +=> true if current device is not Android phone
1872 +```
1873 +
1874 +is.androidTablet()
1875 +------------------
1876 +####Checks if current device is Android tablet.
1877 +interface: not
1878 +
1879 +```javascript
1880 +is.androidTablet();
1881 +=> true if current device is Android tablet
1882 +
1883 +is.not.androidTablet();
1884 +=> true if current device is not Android tablet
1885 +```
1886 +
1887 +is.blackberry()
1888 +---------------
1889 +####Checks if current device is Blackberry.
1890 +interface: not
1891 +
1892 +```javascript
1893 +is.blackberry();
1894 +=> true if current device is Blackberry
1895 +
1896 +is.not.blackberry();
1897 +=> true if current device is not Blackberry
1898 +```
1899 +
1900 +is.windowsPhone()
1901 +-----------------
1902 +####Checks if current device is Windows phone.
1903 +interface: not
1904 +
1905 +```javascript
1906 +is.windowsPhone();
1907 +=> true if current device is Windows phone
1908 +
1909 +is.not.windowsPhone();
1910 +=> true if current device is not Windows Phone
1911 +```
1912 +
1913 +is.windowsTablet()
1914 +------------------
1915 +####Checks if current device is Windows tablet.
1916 +interface: not
1917 +
1918 +```javascript
1919 +is.windowsTablet();
1920 +=> true if current device is Windows tablet
1921 +
1922 +is.not.windowsTablet();
1923 +=> true if current device is not Windows tablet
1924 +```
1925 +
1926 +is.windows()
1927 +------------
1928 +####Checks if current OS is Windows.
1929 +interface: not
1930 +
1931 +```javascript
1932 +is.windows();
1933 +=> true if current OS is Windows
1934 +
1935 +is.not.windows();
1936 +=> true if current OS is not Windows
1937 +```
1938 +
1939 +is.mac()
1940 +--------
1941 +####Checks if current OS is Mac OS X.
1942 +interface: not
1943 +
1944 +```javascript
1945 +is.mac();
1946 +=> true if current OS is Mac OS X
1947 +
1948 +is.not.mac();
1949 +=> true if current OS is not Mac OS X
1950 +```
1951 +
1952 +is.linux()
1953 +----------
1954 +####Checks if current OS is linux.
1955 +interface: not
1956 +
1957 +```javascript
1958 +is.linux();
1959 +=> true if current OS is linux
1960 +
1961 +is.not.linux();
1962 +=> true if current OS is not linux
1963 +```
1964 +
1965 +is.desktop()
1966 +------------
1967 +####Checks if current device is desktop.
1968 +interface: not
1969 +
1970 +```javascript
1971 +is.desktop();
1972 +=> true if current device is desktop
1973 +
1974 +is.not.desktop();
1975 +=> true if current device is not desktop
1976 +```
1977 +
1978 +is.mobile()
1979 +-----------
1980 +####Checks if current device is mobile.
1981 +interface: not
1982 +iPhone, iPod, Android Phone, Windows Phone, Blackberry.
1983 +```javascript
1984 +
1985 +is.mobile();
1986 +=> true if current device is mobile
1987 +
1988 +is.not.mobile();
1989 +=> true if current device is not mobile
1990 +```
1991 +
1992 +is.tablet()
1993 +-----------
1994 +####Checks if current device is tablet.
1995 +interface: not
1996 +iPad, Android Tablet, Windows Tablet
1997 +```javascript
1998 +
1999 +is.tablet();
2000 +=> true if current device is tablet
2001 +
2002 +is.not.tablet();
2003 +=> true if current device is not tablet
2004 +```
2005 +
2006 +is.online()
2007 +-----------
2008 +####Checks if current device is online.
2009 +interface: not
2010 +
2011 +```javascript
2012 +is.online();
2013 +=> true if current device is online
2014 +
2015 +is.not.online();
2016 +=> true if current device is not online
2017 +```
2018 +
2019 +is.offline()
2020 +------------
2021 +####Checks if current device is offline.
2022 +interface: not
2023 +
2024 +```javascript
2025 +is.offline();
2026 +=> true if current device is offline
2027 +
2028 +is.not.offline();
2029 +=> true if current device is not offline
2030 +```
2031 +
2032 +is.touchDevice()
2033 +------------
2034 +####Checks if current device supports touch.
2035 +interface: not
2036 +
2037 +```javascript
2038 +is.touchDevice();
2039 +=> true if current device supports touch
2040 +
2041 +is.not.touchDevice();
2042 +=> true if current device does not support touch
2043 +```
2044 +
2045 +Time checks
2046 +===========
2047 +
2048 +is.today(value:date)
2049 +----------------------
2050 +####Checks if the given date object indicate today.
2051 +interfaces: not, all, any
2052 +
2053 +```javascript
2054 +var today = new Date();
2055 +is.today(today);
2056 +=> true
2057 +
2058 +var yesterday = new Date(new Date().setDate(new Date().getDate() - 1));
2059 +is.today(yesterday);
2060 +=> false
2061 +
2062 +is.not.today(yesterday);
2063 +=> true
2064 +
2065 +is.all.today(today, today);
2066 +=> true
2067 +
2068 +is.any.today(today, yesterday);
2069 +=> true
2070 +
2071 +// 'all' and 'any' interfaces can also take array parameter
2072 +is.all.today([today, yesterday]);
2073 +=> false
2074 +```
2075 +
2076 +is.yesterday(value:date)
2077 +--------------------------
2078 +####Checks if the given date object indicate yesterday.
2079 +interfaces: not, all, any
2080 +
2081 +```javascript
2082 +var today = new Date();
2083 +is.yesterday(today);
2084 +=> false
2085 +
2086 +var yesterday = new Date(new Date().setDate(new Date().getDate() - 1));
2087 +is.yesterday(yesterday);
2088 +=> true
2089 +
2090 +is.not.yesterday(today);
2091 +=> true
2092 +
2093 +is.all.yesterday(yesterday, today);
2094 +=> false
2095 +
2096 +is.any.yesterday(today, yesterday);
2097 +=> true
2098 +
2099 +// 'all' and 'any' interfaces can also take array parameter
2100 +is.all.yesterday([today, yesterday]);
2101 +=> false
2102 +```
2103 +
2104 +is.tomorrow(value:date)
2105 +-------------------------
2106 +####Checks if the given date object indicate tomorrow.
2107 +interfaces: not, all, any
2108 +
2109 +```javascript
2110 +var today = new Date();
2111 +is.tomorrow(today);
2112 +=> false
2113 +
2114 +var tomorrow = new Date(new Date().setDate(new Date().getDate() + 1));
2115 +is.tomorrow(tomorrow);
2116 +=> true
2117 +
2118 +is.not.tomorrow(today);
2119 +=> true
2120 +
2121 +is.all.tomorrow(tomorrow, today);
2122 +=> false
2123 +
2124 +is.any.tomorrow(today, tomorrow);
2125 +=> true
2126 +
2127 +// 'all' and 'any' interfaces can also take array parameter
2128 +is.all.tomorrow([today, tomorrow]);
2129 +=> false
2130 +```
2131 +
2132 +is.past(value:date)
2133 +---------------------
2134 +####Checks if the given date object indicate past.
2135 +interfaces: not, all, any
2136 +
2137 +```javascript
2138 +var yesterday = new Date(new Date().setDate(new Date().getDate() - 1));
2139 +var tomorrow = new Date(new Date().setDate(new Date().getDate() + 1));
2140 +
2141 +is.past(yesterday);
2142 +=> true
2143 +
2144 +is.past(tomorrow);
2145 +=> false
2146 +
2147 +is.not.past(tomorrow);
2148 +=> true
2149 +
2150 +is.all.past(tomorrow, yesterday);
2151 +=> false
2152 +
2153 +is.any.past(yesterday, tomorrow);
2154 +=> true
2155 +
2156 +// 'all' and 'any' interfaces can also take array parameter
2157 +is.all.past([yesterday, tomorrow]);
2158 +=> false
2159 +```
2160 +
2161 +is.future(value:date)
2162 +-----------------------
2163 +####Checks if the given date object indicate future.
2164 +interfaces: not, all, any
2165 +
2166 +```javascript
2167 +var yesterday = new Date(new Date().setDate(new Date().getDate() - 1));
2168 +var tomorrow = new Date(new Date().setDate(new Date().getDate() + 1));
2169 +
2170 +is.future(yesterday);
2171 +=> false
2172 +
2173 +is.future(tomorrow);
2174 +=> true
2175 +
2176 +is.not.future(yesterday);
2177 +=> true
2178 +
2179 +is.all.future(tomorrow, yesterday);
2180 +=> false
2181 +
2182 +is.any.future(yesterday, tomorrow);
2183 +=> true
2184 +
2185 +// 'all' and 'any' interfaces can also take array parameter
2186 +is.all.future([yesterday, tomorrow]);
2187 +=> false
2188 +```
2189 +
2190 +is.day(value:date, day:string)
2191 +-------------------------------
2192 +####Checks if the given date objects' day equal given dayString parameter.
2193 +interface: not
2194 +
2195 +```javascript
2196 +var mondayObj = new Date('01/26/2015');
2197 +var tuesdayObj = new Date('01/27/2015');
2198 +is.day(mondayObj, 'monday');
2199 +=> true
2200 +
2201 +is.day(mondayObj, 'tuesday');
2202 +=> false
2203 +
2204 +is.not.day(mondayObj, 'tuesday');
2205 +=> true
2206 +```
2207 +
2208 +is.month(value:date, month:string)
2209 +-----------------------------------
2210 +####Checks if the given date objects' month equal given monthString parameter.
2211 +interface: not
2212 +
2213 +```javascript
2214 +var januaryObj = new Date('01/26/2015');
2215 +var februaryObj = new Date('02/26/2015');
2216 +is.month(januaryObj, 'january');
2217 +=> true
2218 +
2219 +is.month(februaryObj, 'january');
2220 +=> false
2221 +
2222 +is.not.month(februaryObj, 'january');
2223 +=> true
2224 +```
2225 +
2226 +is.year(value:date, year:number)
2227 +---------------------------------
2228 +####Checks if the given date objects' year equal given yearNumber parameter.
2229 +interface: not
2230 +
2231 +```javascript
2232 +var year2015 = new Date('01/26/2015');
2233 +var year2016 = new Date('01/26/2016');
2234 +is.year(year2015, 2015);
2235 +=> true
2236 +
2237 +is.year(year2016, 2015);
2238 +=> false
2239 +
2240 +is.not.year(year2016, 2015);
2241 +=> true
2242 +```
2243 +
2244 +is.leapYear(value:number)
2245 +---------------------------------
2246 +####Checks if the given year number is a leap year
2247 +interfaces: not, all, any
2248 +
2249 +```javascript
2250 +is.leapYear(2016);
2251 +=> true
2252 +
2253 +is.leapYear(2015);
2254 +=> false
2255 +
2256 +is.not.leapYear(2015);
2257 +=> true
2258 +
2259 +is.all.leapYear(2015, 2016);
2260 +=> false
2261 +
2262 +is.any.leapYear(2015, 2016);
2263 +=> true
2264 +
2265 +// 'all' and 'any' interfaces can also take array parameter
2266 +is.all.leapYear([2016, 2080]);
2267 +=> true
2268 +```
2269 +
2270 +is.weekend(value:date)
2271 +------------------------
2272 +####Checks if the given date objects' day is weekend.
2273 +interfaces: not, all, any
2274 +
2275 +```javascript
2276 +var monday = new Date('01/26/2015');
2277 +var sunday = new Date('01/25/2015');
2278 +var saturday = new Date('01/24/2015');
2279 +is.weekend(sunday);
2280 +=> true
2281 +
2282 +is.weekend(monday);
2283 +=> false
2284 +
2285 +is.not.weekend(monday);
2286 +=> true
2287 +
2288 +is.all.weekend(sunday, saturday);
2289 +=> true
2290 +
2291 +is.any.weekend(sunday, saturday, monday);
2292 +=> true
2293 +
2294 +// 'all' and 'any' interfaces can also take array parameter
2295 +is.all.weekend([sunday, saturday, monday]);
2296 +=> false
2297 +```
2298 +
2299 +is.weekday(value:date)
2300 +------------------------
2301 +####Checks if the given date objects' day is weekday.
2302 +interfaces: not, all, any
2303 +
2304 +```javascript
2305 +var monday = new Date('01/26/2015');
2306 +var sunday = new Date('01/25/2015');
2307 +var saturday = new Date('01/24/2015');
2308 +is.weekday(monday);
2309 +=> true
2310 +
2311 +is.weekday(sunday);
2312 +=> false
2313 +
2314 +is.not.weekday(sunday);
2315 +=> true
2316 +
2317 +is.all.weekday(monday, saturday);
2318 +=> false
2319 +
2320 +is.any.weekday(sunday, saturday, monday);
2321 +=> true
2322 +
2323 +// 'all' and 'any' interfaces can also take array parameter
2324 +is.all.weekday([sunday, saturday, monday]);
2325 +=> false
2326 +```
2327 +
2328 +is.inDateRange(value:date, start:date, end:date)
2329 +----------------------------------------------------
2330 +####Checks if date is within given range.
2331 +interface: not
2332 +
2333 +```javascript
2334 +var saturday = new Date('01/24/2015');
2335 +var sunday = new Date('01/25/2015');
2336 +var monday = new Date('01/26/2015');
2337 +is.inDateRange(sunday, saturday, monday);
2338 +=> true
2339 +
2340 +is.inDateRange(saturday, sunday, monday);
2341 +=> false
2342 +
2343 +is.not.inDateRange(saturday, sunday, monday);
2344 +=> true
2345 +```
2346 +
2347 +is.inLastWeek(value:date)
2348 +---------------------------
2349 +####Checks if the given date is between now and 7 days ago.
2350 +interface: not
2351 +
2352 +```javascript
2353 +var twoDaysAgo = new Date(new Date().setDate(new Date().getDate() - 2));
2354 +var nineDaysAgo = new Date(new Date().setDate(new Date().getDate() - 9));
2355 +is.inLastWeek(twoDaysAgo);
2356 +=> true
2357 +
2358 +is.inLastWeek(nineDaysAgo);
2359 +=> false
2360 +
2361 +is.not.inLastWeek(nineDaysAgo);
2362 +=> true
2363 +```
2364 +
2365 +is.inLastMonth(value:date)
2366 +----------------------------
2367 +####Checks if the given date is between now and a month ago.
2368 +interface: not
2369 +
2370 +```javascript
2371 +var tenDaysAgo = new Date(new Date().setDate(new Date().getDate() - 10));
2372 +var fortyDaysAgo = new Date(new Date().setDate(new Date().getDate() - 40));
2373 +is.inLastMonth(tenDaysAgo);
2374 +=> true
2375 +
2376 +is.inLastMonth(fortyDaysAgo);
2377 +=> false
2378 +
2379 +is.not.inLastMonth(fortyDaysAgo);
2380 +=> true
2381 +```
2382 +
2383 +is.inLastYear(value:date)
2384 +---------------------------
2385 +####Checks if the given date is between now and a year ago.
2386 +interface: not
2387 +
2388 +```javascript
2389 +var twoMonthsAgo = new Date(new Date().setMonth(new Date().getMonth() - 2));
2390 +var thirteenMonthsAgo = new Date(new Date().setMonth(new Date().getMonth() - 13));
2391 +is.inLastYear(twoMonthsAgo);
2392 +=> true
2393 +
2394 +is.inLastYear(thirteenMonthsAgo);
2395 +=> false
2396 +
2397 +is.not.inLastYear(thirteenMonthsAgo);
2398 +=> true
2399 +```
2400 +
2401 +is.inNextWeek(value:date)
2402 +---------------------------
2403 +####Checks if the given date is between now and 7 days later.
2404 +interface: not
2405 +
2406 +```javascript
2407 +var twoDaysLater = new Date(new Date().setDate(new Date().getDate() + 2));
2408 +var nineDaysLater = new Date(new Date().setDate(new Date().getDate() + 9));
2409 +is.inNextWeek(twoDaysLater);
2410 +=> true
2411 +
2412 +is.inNextWeek(nineDaysLater);
2413 +=> false
2414 +
2415 +is.not.inNextWeek(nineDaysLater);
2416 +=> true
2417 +```
2418 +
2419 +is.inNextMonth(value:date)
2420 +----------------------------
2421 +####Checks if the given date is between now and a month later.
2422 +interface: not
2423 +
2424 +```javascript
2425 +var tenDaysLater = new Date(new Date().setDate(new Date().getDate() + 10));
2426 +var fortyDaysLater = new Date(new Date().setDate(new Date().getDate() + 40));
2427 +is.inNextMonth(tenDaysLater);
2428 +=> true
2429 +
2430 +is.inNextMonth(fortyDaysLater);
2431 +=> false
2432 +
2433 +is.not.inNextMonth(fortyDaysLater);
2434 +=> true
2435 +```
2436 +
2437 +is.inNextYear(value:date)
2438 +---------------------------
2439 +####Checks if the given date is between now and a year later.
2440 +interface: not
2441 +
2442 +```javascript
2443 +var twoMonthsLater = new Date(new Date().setMonth(new Date().getMonth() + 2));
2444 +var thirteenMonthsLater = new Date(new Date().setMonth(new Date().getMonth() + 13));
2445 +is.inNextYear(twoMonthsLater);
2446 +=> true
2447 +
2448 +is.inNextYear(thirteenMonthsLater);
2449 +=> false
2450 +
2451 +is.not.inNextYear(thirteenMonthsLater);
2452 +=> true
2453 +```
2454 +
2455 +is.quarterOfYear(value:date, quarter:number)
2456 +---------------------------------------------
2457 +####Checks if the given date is in the parameter quarter.
2458 +interface: not
2459 +
2460 +```javascript
2461 +var firstQuarter = new Date('01/26/2015');
2462 +var secondQuarter = new Date('05/26/2015');
2463 +is.quarterOfYear(firstQuarter, 1);
2464 +=> true
2465 +
2466 +is.quarterOfYear(secondQuarter, 1);
2467 +=> false
2468 +
2469 +is.not.quarterOfYear(secondQuarter, 1);
2470 +=> true
2471 +```
2472 +
2473 +is.dayLightSavingTime(value:date)
2474 +--------------------------------------------------
2475 +####Checks if the given date is in daylight saving time.
2476 +interface: not
2477 +
2478 +```javascript
2479 +// For Turkey Time Zone
2480 +var january1 = new Date('01/01/2015');
2481 +var june1 = new Date('06/01/2015');
2482 +
2483 +is.dayLightSavingTime(june1);
2484 +=> true
2485 +
2486 +is.dayLightSavingTime(january1);
2487 +=> false
2488 +
2489 +is.not.dayLightSavingTime(january1);
2490 +=> true
2491 +```
2492 +
2493 +Configuration methods
2494 +=====================
2495 +
2496 +is.setNamespace()
2497 +-----------------
2498 +Change namespace of library to prevent name collisions.
2499 +
2500 +```javascript
2501 +var customName = is.setNamespace();
2502 +customName.odd(3);
2503 +=> true
2504 +```
2505 +
2506 +is.setRegexp(value:regexp, name:string)
2507 +----------------------------------------
2508 +Override RegExps if you think they suck.
2509 +
2510 +```javascript
2511 +is.url('https://www.duckduckgo.com');
2512 +=> true
2513 +
2514 +is.setRegexp(/quack/, 'url');
2515 +is.url('quack');
2516 +=> true
2517 +```
1 +/*!
2 + * is.js 0.8.0
3 + * Author: Aras Atasaygin
4 + */
5 +
6 +// AMD with global, Node, or global
7 +;(function(root, factory) { // eslint-disable-line no-extra-semi
8 + if (typeof define === 'function' && define.amd) {
9 + // AMD. Register as an anonymous module.
10 + define(function() {
11 + // Also create a global in case some scripts
12 + // that are loaded still are looking for
13 + // a global even when an AMD loader is in use.
14 + return (root.is = factory());
15 + });
16 + } else if (typeof exports === 'object') {
17 + // Node. Does not work with strict CommonJS, but
18 + // only CommonJS-like enviroments that support module.exports,
19 + // like Node.
20 + module.exports = factory();
21 + } else {
22 + // Browser globals (root is self)
23 + root.is = factory();
24 + }
25 +}(this, function() {
26 +
27 + // Baseline
28 + /* -------------------------------------------------------------------------- */
29 +
30 + // define 'is' object and current version
31 + var is = {};
32 + is.VERSION = '0.8.0';
33 +
34 + // define interfaces
35 + is.not = {};
36 + is.all = {};
37 + is.any = {};
38 +
39 + // cache some methods to call later on
40 + var toString = Object.prototype.toString;
41 + var slice = Array.prototype.slice;
42 + var hasOwnProperty = Object.prototype.hasOwnProperty;
43 +
44 + // helper function which reverses the sense of predicate result
45 + function not(func) {
46 + return function() {
47 + return !func.apply(null, slice.call(arguments));
48 + };
49 + }
50 +
51 + // helper function which call predicate function per parameter and return true if all pass
52 + function all(func) {
53 + return function() {
54 + var params = getParams(arguments);
55 + var length = params.length;
56 + for (var i = 0; i < length; i++) {
57 + if (!func.call(null, params[i])) {
58 + return false;
59 + }
60 + }
61 + return true;
62 + };
63 + }
64 +
65 + // helper function which call predicate function per parameter and return true if any pass
66 + function any(func) {
67 + return function() {
68 + var params = getParams(arguments);
69 + var length = params.length;
70 + for (var i = 0; i < length; i++) {
71 + if (func.call(null, params[i])) {
72 + return true;
73 + }
74 + }
75 + return false;
76 + };
77 + }
78 +
79 + // build a 'comparator' object for various comparison checks
80 + var comparator = {
81 + '<': function(a, b) { return a < b; },
82 + '<=': function(a, b) { return a <= b; },
83 + '>': function(a, b) { return a > b; },
84 + '>=': function(a, b) { return a >= b; }
85 + }
86 +
87 + // helper function which compares a version to a range
88 + function compareVersion(version, range) {
89 + var string = (range + '');
90 + var n = +(string.match(/\d+/) || NaN);
91 + var op = string.match(/^[<>]=?|/)[0];
92 + return comparator[op] ? comparator[op](version, n) : (version == n || n !== n);
93 + }
94 +
95 + // helper function which extracts params from arguments
96 + function getParams(args) {
97 + var params = slice.call(args);
98 + var length = params.length;
99 + if (length === 1 && is.array(params[0])) { // support array
100 + params = params[0];
101 + }
102 + return params;
103 + }
104 +
105 + // Type checks
106 + /* -------------------------------------------------------------------------- */
107 +
108 + // is a given value Arguments?
109 + is.arguments = function(value) { // fallback check is for IE
110 + return toString.call(value) === '[object Arguments]' ||
111 + (value != null && typeof value === 'object' && 'callee' in value);
112 + };
113 +
114 + // is a given value Array?
115 + is.array = Array.isArray || function(value) { // check native isArray first
116 + return toString.call(value) === '[object Array]';
117 + };
118 +
119 + // is a given value Boolean?
120 + is.boolean = function(value) {
121 + return value === true || value === false || toString.call(value) === '[object Boolean]';
122 + };
123 +
124 + // is a given value Char?
125 + is.char = function(value) {
126 + return is.string(value) && value.length === 1;
127 + };
128 +
129 + // is a given value Date Object?
130 + is.date = function(value) {
131 + return toString.call(value) === '[object Date]';
132 + };
133 +
134 + // is a given object a DOM node?
135 + is.domNode = function(object) {
136 + return is.object(object) && object.nodeType > 0;
137 + };
138 +
139 + // is a given value Error object?
140 + is.error = function(value) {
141 + return toString.call(value) === '[object Error]';
142 + };
143 +
144 + // is a given value function?
145 + is['function'] = function(value) { // fallback check is for IE
146 + return toString.call(value) === '[object Function]' || typeof value === 'function';
147 + };
148 +
149 + // is given value a pure JSON object?
150 + is.json = function(value) {
151 + return toString.call(value) === '[object Object]';
152 + };
153 +
154 + // is a given value NaN?
155 + is.nan = function(value) { // NaN is number :) Also it is the only value which does not equal itself
156 + return value !== value;
157 + };
158 +
159 + // is a given value null?
160 + is['null'] = function(value) {
161 + return value === null;
162 + };
163 +
164 + // is a given value number?
165 + is.number = function(value) {
166 + return is.not.nan(value) && toString.call(value) === '[object Number]';
167 + };
168 +
169 + // is a given value object?
170 + is.object = function(value) {
171 + return Object(value) === value;
172 + };
173 +
174 + // is a given value RegExp?
175 + is.regexp = function(value) {
176 + return toString.call(value) === '[object RegExp]';
177 + };
178 +
179 + // are given values same type?
180 + // prevent NaN, Number same type check
181 + is.sameType = function(value, other) {
182 + var tag = toString.call(value);
183 + if (tag !== toString.call(other)) {
184 + return false;
185 + }
186 + if (tag === '[object Number]') {
187 + return !is.any.nan(value, other) || is.all.nan(value, other);
188 + }
189 + return true;
190 + };
191 + // sameType method does not support 'all' and 'any' interfaces
192 + is.sameType.api = ['not'];
193 +
194 + // is a given value String?
195 + is.string = function(value) {
196 + return toString.call(value) === '[object String]';
197 + };
198 +
199 + // is a given value undefined?
200 + is.undefined = function(value) {
201 + return value === void 0;
202 + };
203 +
204 + // is a given value window?
205 + // setInterval method is only available for window object
206 + is.windowObject = function(value) {
207 + return value != null && typeof value === 'object' && 'setInterval' in value;
208 + };
209 +
210 + // Presence checks
211 + /* -------------------------------------------------------------------------- */
212 +
213 + //is a given value empty? Objects, arrays, strings
214 + is.empty = function(value) {
215 + if (is.object(value)) {
216 + var length = Object.getOwnPropertyNames(value).length;
217 + if (length === 0 || (length === 1 && is.array(value)) ||
218 + (length === 2 && is.arguments(value))) {
219 + return true;
220 + }
221 + return false;
222 + }
223 + return value === '';
224 + };
225 +
226 + // is a given value existy?
227 + is.existy = function(value) {
228 + return value != null;
229 + };
230 +
231 + // is a given value falsy?
232 + is.falsy = function(value) {
233 + return !value;
234 + };
235 +
236 + // is a given value truthy?
237 + is.truthy = not(is.falsy);
238 +
239 + // Arithmetic checks
240 + /* -------------------------------------------------------------------------- */
241 +
242 + // is a given number above minimum parameter?
243 + is.above = function(n, min) {
244 + return is.all.number(n, min) && n > min;
245 + };
246 + // above method does not support 'all' and 'any' interfaces
247 + is.above.api = ['not'];
248 +
249 + // is a given number decimal?
250 + is.decimal = function(n) {
251 + return is.number(n) && n % 1 !== 0;
252 + };
253 +
254 + // are given values equal? supports numbers, strings, regexes, booleans
255 + // TODO: Add object and array support
256 + is.equal = function(value, other) {
257 + // check 0 and -0 equity with Infinity and -Infinity
258 + if (is.all.number(value, other)) {
259 + return value === other && 1 / value === 1 / other;
260 + }
261 + // check regexes as strings too
262 + if (is.all.string(value, other) || is.all.regexp(value, other)) {
263 + return '' + value === '' + other;
264 + }
265 + if (is.all.boolean(value, other)) {
266 + return value === other;
267 + }
268 + return false;
269 + };
270 + // equal method does not support 'all' and 'any' interfaces
271 + is.equal.api = ['not'];
272 +
273 + // is a given number even?
274 + is.even = function(n) {
275 + return is.number(n) && n % 2 === 0;
276 + };
277 +
278 + // is a given number finite?
279 + is.finite = isFinite || function(n) {
280 + return is.not.infinite(n) && is.not.nan(n);
281 + };
282 +
283 + // is a given number infinite?
284 + is.infinite = function(n) {
285 + return n === Infinity || n === -Infinity;
286 + };
287 +
288 + // is a given number integer?
289 + is.integer = function(n) {
290 + return is.number(n) && n % 1 === 0;
291 + };
292 +
293 + // is a given number negative?
294 + is.negative = function(n) {
295 + return is.number(n) && n < 0;
296 + };
297 +
298 + // is a given number odd?
299 + is.odd = function(n) {
300 + return is.number(n) && n % 2 === 1;
301 + };
302 +
303 + // is a given number positive?
304 + is.positive = function(n) {
305 + return is.number(n) && n > 0;
306 + };
307 +
308 + // is a given number above maximum parameter?
309 + is.under = function(n, max) {
310 + return is.all.number(n, max) && n < max;
311 + };
312 + // least method does not support 'all' and 'any' interfaces
313 + is.under.api = ['not'];
314 +
315 + // is a given number within minimum and maximum parameters?
316 + is.within = function(n, min, max) {
317 + return is.all.number(n, min, max) && n > min && n < max;
318 + };
319 + // within method does not support 'all' and 'any' interfaces
320 + is.within.api = ['not'];
321 +
322 + // Regexp checks
323 + /* -------------------------------------------------------------------------- */
324 + // Steven Levithan, Jan Goyvaerts: Regular Expressions Cookbook
325 + // Scott Gonzalez: Email address validation
326 +
327 + // dateString match m/d/yy and mm/dd/yyyy, allowing any combination of one or two digits for the day and month, and two or four digits for the year
328 + // eppPhone match extensible provisioning protocol format
329 + // nanpPhone match north american number plan format
330 + // time match hours, minutes, and seconds, 24-hour clock
331 + var regexes = {
332 + affirmative: /^(?:1|t(?:rue)?|y(?:es)?|ok(?:ay)?)$/,
333 + alphaNumeric: /^[A-Za-z0-9]+$/,
334 + caPostalCode: /^(?!.*[DFIOQU])[A-VXY][0-9][A-Z]\s?[0-9][A-Z][0-9]$/,
335 + creditCard: /^(?:(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11}))$/,
336 + dateString: /^(1[0-2]|0?[1-9])([\/-])(3[01]|[12][0-9]|0?[1-9])(?:\2)(?:[0-9]{2})?[0-9]{2}$/,
337 + email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i, // eslint-disable-line no-control-regex
338 + eppPhone: /^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/,
339 + hexadecimal: /^(?:0x)?[0-9a-fA-F]+$/,
340 + hexColor: /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/,
341 + ipv4: /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/,
342 + ipv6: /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i,
343 + nanpPhone: /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/,
344 + socialSecurityNumber: /^(?!000|666)[0-8][0-9]{2}-?(?!00)[0-9]{2}-?(?!0000)[0-9]{4}$/,
345 + timeString: /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9]):([0-5]?[0-9])$/,
346 + ukPostCode: /^[A-Z]{1,2}[0-9RCHNQ][0-9A-Z]?\s?[0-9][ABD-HJLNP-UW-Z]{2}$|^[A-Z]{2}-?[0-9]{4}$/,
347 + url: /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/i,
348 + usZipCode: /^[0-9]{5}(?:-[0-9]{4})?$/
349 + };
350 +
351 + function regexpCheck(regexp, regexes) {
352 + is[regexp] = function(value) {
353 + return regexes[regexp].test(value);
354 + };
355 + }
356 +
357 + // create regexp checks methods from 'regexes' object
358 + for (var regexp in regexes) {
359 + if (regexes.hasOwnProperty(regexp)) {
360 + regexpCheck(regexp, regexes);
361 + }
362 + }
363 +
364 + // simplify IP checks by calling the regex helpers for IPv4 and IPv6
365 + is.ip = function(value) {
366 + return is.ipv4(value) || is.ipv6(value);
367 + };
368 +
369 + // String checks
370 + /* -------------------------------------------------------------------------- */
371 +
372 + // is a given string or sentence capitalized?
373 + is.capitalized = function(string) {
374 + if (is.not.string(string)) {
375 + return false;
376 + }
377 + var words = string.split(' ');
378 + for (var i = 0; i < words.length; i++) {
379 + var word = words[i];
380 + if (word.length) {
381 + var chr = word.charAt(0);
382 + if (chr !== chr.toUpperCase()) {
383 + return false;
384 + }
385 + }
386 + }
387 + return true;
388 + };
389 +
390 + // is string end with a given target parameter?
391 + is.endWith = function(string, target) {
392 + if (is.not.string(string)) {
393 + return false;
394 + }
395 + target += '';
396 + var position = string.length - target.length;
397 + return position >= 0 && string.indexOf(target, position) === position;
398 + };
399 + // endWith method does not support 'all' and 'any' interfaces
400 + is.endWith.api = ['not'];
401 +
402 + // is a given string include parameter target?
403 + is.include = function(string, target) {
404 + return string.indexOf(target) > -1;
405 + };
406 + // include method does not support 'all' and 'any' interfaces
407 + is.include.api = ['not'];
408 +
409 + // is a given string all lowercase?
410 + is.lowerCase = function(string) {
411 + return is.string(string) && string === string.toLowerCase();
412 + };
413 +
414 + // is a given string palindrome?
415 + is.palindrome = function(string) {
416 + if (is.not.string(string)) {
417 + return false;
418 + }
419 + string = string.replace(/[^a-zA-Z0-9]+/g, '').toLowerCase();
420 + var length = string.length - 1;
421 + for (var i = 0, half = Math.floor(length / 2); i <= half; i++) {
422 + if (string.charAt(i) !== string.charAt(length - i)) {
423 + return false;
424 + }
425 + }
426 + return true;
427 + };
428 +
429 + // is a given value space?
430 + // horizantal tab: 9, line feed: 10, vertical tab: 11, form feed: 12, carriage return: 13, space: 32
431 + is.space = function(value) {
432 + if (is.not.char(value)) {
433 + return false;
434 + }
435 + var charCode = value.charCodeAt(0);
436 + return (charCode > 8 && charCode < 14) || charCode === 32;
437 + };
438 +
439 + // is string start with a given target parameter?
440 + is.startWith = function(string, target) {
441 + return is.string(string) && string.indexOf(target) === 0;
442 + };
443 + // startWith method does not support 'all' and 'any' interfaces
444 + is.startWith.api = ['not'];
445 +
446 + // is a given string all uppercase?
447 + is.upperCase = function(string) {
448 + return is.string(string) && string === string.toUpperCase();
449 + };
450 +
451 + // Time checks
452 + /* -------------------------------------------------------------------------- */
453 +
454 + var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
455 + var months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
456 +
457 + // is a given dates day equal given day parameter?
458 + is.day = function(date, day) {
459 + return is.date(date) && day.toLowerCase() === days[date.getDay()];
460 + };
461 + // day method does not support 'all' and 'any' interfaces
462 + is.day.api = ['not'];
463 +
464 + // is a given date in daylight saving time?
465 + is.dayLightSavingTime = function(date) {
466 + var january = new Date(date.getFullYear(), 0, 1);
467 + var july = new Date(date.getFullYear(), 6, 1);
468 + var stdTimezoneOffset = Math.max(january.getTimezoneOffset(), july.getTimezoneOffset());
469 + return date.getTimezoneOffset() < stdTimezoneOffset;
470 + };
471 +
472 + // is a given date future?
473 + is.future = function(date) {
474 + var now = new Date();
475 + return is.date(date) && date.getTime() > now.getTime();
476 + };
477 +
478 + // is date within given range?
479 + is.inDateRange = function(date, start, end) {
480 + if (is.not.date(date) || is.not.date(start) || is.not.date(end)) {
481 + return false;
482 + }
483 + var stamp = date.getTime();
484 + return stamp > start.getTime() && stamp < end.getTime();
485 + };
486 + // inDateRange method does not support 'all' and 'any' interfaces
487 + is.inDateRange.api = ['not'];
488 +
489 + // is a given date in last month range?
490 + is.inLastMonth = function(date) {
491 + return is.inDateRange(date, new Date(new Date().setMonth(new Date().getMonth() - 1)), new Date());
492 + };
493 +
494 + // is a given date in last week range?
495 + is.inLastWeek = function(date) {
496 + return is.inDateRange(date, new Date(new Date().setDate(new Date().getDate() - 7)), new Date());
497 + };
498 +
499 + // is a given date in last year range?
500 + is.inLastYear = function(date) {
501 + return is.inDateRange(date, new Date(new Date().setFullYear(new Date().getFullYear() - 1)), new Date());
502 + };
503 +
504 + // is a given date in next month range?
505 + is.inNextMonth = function(date) {
506 + return is.inDateRange(date, new Date(), new Date(new Date().setMonth(new Date().getMonth() + 1)));
507 + };
508 +
509 + // is a given date in next week range?
510 + is.inNextWeek = function(date) {
511 + return is.inDateRange(date, new Date(), new Date(new Date().setDate(new Date().getDate() + 7)));
512 + };
513 +
514 + // is a given date in next year range?
515 + is.inNextYear = function(date) {
516 + return is.inDateRange(date, new Date(), new Date(new Date().setFullYear(new Date().getFullYear() + 1)));
517 + };
518 +
519 + // is the given year a leap year?
520 + is.leapYear = function(year) {
521 + return is.number(year) && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
522 + };
523 +
524 + // is a given dates month equal given month parameter?
525 + is.month = function(date, month) {
526 + return is.date(date) && month.toLowerCase() === months[date.getMonth()];
527 + };
528 + // month method does not support 'all' and 'any' interfaces
529 + is.month.api = ['not'];
530 +
531 + // is a given date past?
532 + is.past = function(date) {
533 + var now = new Date();
534 + return is.date(date) && date.getTime() < now.getTime();
535 + };
536 +
537 + // is a given date in the parameter quarter?
538 + is.quarterOfYear = function(date, quarter) {
539 + return is.date(date) && is.number(quarter) && quarter === Math.floor((date.getMonth() + 3) / 3);
540 + };
541 + // quarterOfYear method does not support 'all' and 'any' interfaces
542 + is.quarterOfYear.api = ['not'];
543 +
544 + // is a given date indicate today?
545 + is.today = function(date) {
546 + var now = new Date();
547 + var todayString = now.toDateString();
548 + return is.date(date) && date.toDateString() === todayString;
549 + };
550 +
551 + // is a given date indicate tomorrow?
552 + is.tomorrow = function(date) {
553 + var now = new Date();
554 + var tomorrowString = new Date(now.setDate(now.getDate() + 1)).toDateString();
555 + return is.date(date) && date.toDateString() === tomorrowString;
556 + };
557 +
558 + // is a given date weekend?
559 + // 6: Saturday, 0: Sunday
560 + is.weekend = function(date) {
561 + return is.date(date) && (date.getDay() === 6 || date.getDay() === 0);
562 + };
563 +
564 + // is a given date weekday?
565 + is.weekday = not(is.weekend);
566 +
567 + // is a given dates year equal given year parameter?
568 + is.year = function(date, year) {
569 + return is.date(date) && is.number(year) && year === date.getFullYear();
570 + };
571 + // year method does not support 'all' and 'any' interfaces
572 + is.year.api = ['not'];
573 +
574 + // is a given date indicate yesterday?
575 + is.yesterday = function(date) {
576 + var now = new Date();
577 + var yesterdayString = new Date(now.setDate(now.getDate() - 1)).toDateString();
578 + return is.date(date) && date.toDateString() === yesterdayString;
579 + };
580 +
581 + // Environment checks
582 + /* -------------------------------------------------------------------------- */
583 +
584 + var freeGlobal = is.windowObject(typeof global == 'object' && global) && global;
585 + var freeSelf = is.windowObject(typeof self == 'object' && self) && self;
586 + var thisGlobal = is.windowObject(typeof this == 'object' && this) && this;
587 + var root = freeGlobal || freeSelf || thisGlobal || Function('return this')();
588 +
589 + var document = freeSelf && freeSelf.document;
590 + var previousIs = root.is;
591 +
592 + // store navigator properties to use later
593 + var navigator = freeSelf && freeSelf.navigator;
594 + var appVersion = (navigator && navigator.appVersion || '').toLowerCase();
595 + var userAgent = (navigator && navigator.userAgent || '').toLowerCase();
596 + var vendor = (navigator && navigator.vendor || '').toLowerCase();
597 +
598 + // is current device android?
599 + is.android = function() {
600 + return /android/.test(userAgent);
601 + };
602 + // android method does not support 'all' and 'any' interfaces
603 + is.android.api = ['not'];
604 +
605 + // is current device android phone?
606 + is.androidPhone = function() {
607 + return /android/.test(userAgent) && /mobile/.test(userAgent);
608 + };
609 + // androidPhone method does not support 'all' and 'any' interfaces
610 + is.androidPhone.api = ['not'];
611 +
612 + // is current device android tablet?
613 + is.androidTablet = function() {
614 + return /android/.test(userAgent) && !/mobile/.test(userAgent);
615 + };
616 + // androidTablet method does not support 'all' and 'any' interfaces
617 + is.androidTablet.api = ['not'];
618 +
619 + // is current device blackberry?
620 + is.blackberry = function() {
621 + return /blackberry/.test(userAgent) || /bb10/.test(userAgent);
622 + };
623 + // blackberry method does not support 'all' and 'any' interfaces
624 + is.blackberry.api = ['not'];
625 +
626 + // is current browser chrome?
627 + // parameter is optional
628 + is.chrome = function(range) {
629 + var match = /google inc/.test(vendor) ? userAgent.match(/(?:chrome|crios)\/(\d+)/) : null;
630 + return match !== null && compareVersion(match[1], range);
631 + };
632 + // chrome method does not support 'all' and 'any' interfaces
633 + is.chrome.api = ['not'];
634 +
635 + // is current device desktop?
636 + is.desktop = function() {
637 + return is.not.mobile() && is.not.tablet();
638 + };
639 + // desktop method does not support 'all' and 'any' interfaces
640 + is.desktop.api = ['not'];
641 +
642 + // is current browser edge?
643 + // parameter is optional
644 + is.edge = function(range) {
645 + var match = userAgent.match(/edge\/(\d+)/);
646 + return match !== null && compareVersion(match[1], range);
647 + };
648 + // edge method does not support 'all' and 'any' interfaces
649 + is.edge.api = ['not'];
650 +
651 + // is current browser firefox?
652 + // parameter is optional
653 + is.firefox = function(range) {
654 + var match = userAgent.match(/(?:firefox|fxios)\/(\d+)/);
655 + return match !== null && compareVersion(match[1], range);
656 + };
657 + // firefox method does not support 'all' and 'any' interfaces
658 + is.firefox.api = ['not'];
659 +
660 + // is current browser internet explorer?
661 + // parameter is optional
662 + is.ie = function(range) {
663 + var match = userAgent.match(/(?:msie |trident.+?; rv:)(\d+)/);
664 + return match !== null && compareVersion(match[1], range);
665 + };
666 + // ie method does not support 'all' and 'any' interfaces
667 + is.ie.api = ['not'];
668 +
669 + // is current device ios?
670 + is.ios = function() {
671 + return is.iphone() || is.ipad() || is.ipod();
672 + };
673 + // ios method does not support 'all' and 'any' interfaces
674 + is.ios.api = ['not'];
675 +
676 + // is current device ipad?
677 + // parameter is optional
678 + is.ipad = function(range) {
679 + var match = userAgent.match(/ipad.+?os (\d+)/);
680 + return match !== null && compareVersion(match[1], range);
681 + };
682 + // ipad method does not support 'all' and 'any' interfaces
683 + is.ipad.api = ['not'];
684 +
685 + // is current device iphone?
686 + // parameter is optional
687 + is.iphone = function(range) {
688 + // original iPhone doesn't have the os portion of the UA
689 + var match = userAgent.match(/iphone(?:.+?os (\d+))?/);
690 + return match !== null && compareVersion(match[1] || 1, range);
691 + };
692 + // iphone method does not support 'all' and 'any' interfaces
693 + is.iphone.api = ['not'];
694 +
695 + // is current device ipod?
696 + // parameter is optional
697 + is.ipod = function(range) {
698 + var match = userAgent.match(/ipod.+?os (\d+)/);
699 + return match !== null && compareVersion(match[1], range);
700 + };
701 + // ipod method does not support 'all' and 'any' interfaces
702 + is.ipod.api = ['not'];
703 +
704 + // is current operating system linux?
705 + is.linux = function() {
706 + return /linux/.test(appVersion);
707 + };
708 + // linux method does not support 'all' and 'any' interfaces
709 + is.linux.api = ['not'];
710 +
711 + // is current operating system mac?
712 + is.mac = function() {
713 + return /mac/.test(appVersion);
714 + };
715 + // mac method does not support 'all' and 'any' interfaces
716 + is.mac.api = ['not'];
717 +
718 + // is current device mobile?
719 + is.mobile = function() {
720 + return is.iphone() || is.ipod() || is.androidPhone() || is.blackberry() || is.windowsPhone();
721 + };
722 + // mobile method does not support 'all' and 'any' interfaces
723 + is.mobile.api = ['not'];
724 +
725 + // is current state offline?
726 + is.offline = not(is.online);
727 + // offline method does not support 'all' and 'any' interfaces
728 + is.offline.api = ['not'];
729 +
730 + // is current state online?
731 + is.online = function() {
732 + return !navigator || navigator.onLine === true;
733 + };
734 + // online method does not support 'all' and 'any' interfaces
735 + is.online.api = ['not'];
736 +
737 + // is current browser opera?
738 + // parameter is optional
739 + is.opera = function(range) {
740 + var match = userAgent.match(/(?:^opera.+?version|opr)\/(\d+)/);
741 + return match !== null && compareVersion(match[1], range);
742 + };
743 + // opera method does not support 'all' and 'any' interfaces
744 + is.opera.api = ['not'];
745 +
746 + // is current browser phantomjs?
747 + // parameter is optional
748 + is.phantom = function(range) {
749 + var match = userAgent.match(/phantomjs\/(\d+)/);
750 + return match !== null && compareVersion(match[1], range);
751 + };
752 + // phantom method does not support 'all' and 'any' interfaces
753 + is.phantom.api = ['not'];
754 +
755 + // is current browser safari?
756 + // parameter is optional
757 + is.safari = function(range) {
758 + var match = userAgent.match(/version\/(\d+).+?safari/);
759 + return match !== null && compareVersion(match[1], range);
760 + };
761 + // safari method does not support 'all' and 'any' interfaces
762 + is.safari.api = ['not'];
763 +
764 + // is current device tablet?
765 + is.tablet = function() {
766 + return is.ipad() || is.androidTablet() || is.windowsTablet();
767 + };
768 + // tablet method does not support 'all' and 'any' interfaces
769 + is.tablet.api = ['not'];
770 +
771 + // is current device supports touch?
772 + is.touchDevice = function() {
773 + return !!document && ('ontouchstart' in freeSelf ||
774 + ('DocumentTouch' in freeSelf && document instanceof DocumentTouch));
775 + };
776 + // touchDevice method does not support 'all' and 'any' interfaces
777 + is.touchDevice.api = ['not'];
778 +
779 + // is current operating system windows?
780 + is.windows = function() {
781 + return /win/.test(appVersion);
782 + };
783 + // windows method does not support 'all' and 'any' interfaces
784 + is.windows.api = ['not'];
785 +
786 + // is current device windows phone?
787 + is.windowsPhone = function() {
788 + return is.windows() && /phone/.test(userAgent);
789 + };
790 + // windowsPhone method does not support 'all' and 'any' interfaces
791 + is.windowsPhone.api = ['not'];
792 +
793 + // is current device windows tablet?
794 + is.windowsTablet = function() {
795 + return is.windows() && is.not.windowsPhone() && /touch/.test(userAgent);
796 + };
797 + // windowsTablet method does not support 'all' and 'any' interfaces
798 + is.windowsTablet.api = ['not'];
799 +
800 + // Object checks
801 + /* -------------------------------------------------------------------------- */
802 +
803 + // has a given object got parameterized count property?
804 + is.propertyCount = function(object, count) {
805 + if (is.not.object(object) || is.not.number(count)) {
806 + return false;
807 + }
808 + var n = 0;
809 + for (var property in object) {
810 + if (hasOwnProperty.call(object, property) && ++n > count) {
811 + return false;
812 + }
813 + }
814 + return n === count;
815 + };
816 + // propertyCount method does not support 'all' and 'any' interfaces
817 + is.propertyCount.api = ['not'];
818 +
819 + // is given object has parameterized property?
820 + is.propertyDefined = function(object, property) {
821 + return is.object(object) && is.string(property) && property in object;
822 + };
823 + // propertyDefined method does not support 'all' and 'any' interfaces
824 + is.propertyDefined.api = ['not'];
825 +
826 + // Array checks
827 + /* -------------------------------------------------------------------------- */
828 +
829 + // is a given item in an array?
830 + is.inArray = function(value, array) {
831 + if (is.not.array(array)) {
832 + return false;
833 + }
834 + for (var i = 0; i < array.length; i++) {
835 + if (array[i] === value) {
836 + return true;
837 + }
838 + }
839 + return false;
840 + };
841 + // inArray method does not support 'all' and 'any' interfaces
842 + is.inArray.api = ['not'];
843 +
844 + // is a given array sorted?
845 + is.sorted = function(array, sign) {
846 + if (is.not.array(array)) {
847 + return false;
848 + }
849 + var predicate = comparator[sign] || comparator['>='];
850 + for (var i = 1; i < array.length; i++) {
851 + if (!predicate(array[i], array[i - 1])) {
852 + return false;
853 + }
854 + }
855 + return true;
856 + };
857 +
858 + // API
859 + // Set 'not', 'all' and 'any' interfaces to methods based on their api property
860 + /* -------------------------------------------------------------------------- */
861 +
862 + function setInterfaces() {
863 + var options = is;
864 + for (var option in options) {
865 + if (hasOwnProperty.call(options, option) && is['function'](options[option])) {
866 + var interfaces = options[option].api || ['not', 'all', 'any'];
867 + for (var i = 0; i < interfaces.length; i++) {
868 + if (interfaces[i] === 'not') {
869 + is.not[option] = not(is[option]);
870 + }
871 + if (interfaces[i] === 'all') {
872 + is.all[option] = all(is[option]);
873 + }
874 + if (interfaces[i] === 'any') {
875 + is.any[option] = any(is[option]);
876 + }
877 + }
878 + }
879 + }
880 + }
881 + setInterfaces();
882 +
883 + // Configuration methods
884 + // Intentionally added after setInterfaces function
885 + /* -------------------------------------------------------------------------- */
886 +
887 + // change namespace of library to prevent name collisions
888 + // var preferredName = is.setNamespace();
889 + // preferredName.odd(3);
890 + // => true
891 + is.setNamespace = function() {
892 + root.is = previousIs;
893 + return this;
894 + };
895 +
896 + // set optional regexes to methods
897 + is.setRegexp = function(regexp, name) {
898 + for (var r in regexes) {
899 + if (hasOwnProperty.call(regexes, r) && (name === r)) {
900 + regexes[r] = regexp;
901 + }
902 + }
903 + };
904 +
905 + return is;
906 +}));
1 +/*!
2 + * is.js 0.8.0
3 + * Author: Aras Atasaygin
4 + */
5 +(function(n,t){if(typeof define==="function"&&define.amd){define(function(){return n.is=t()})}else if(typeof exports==="object"){module.exports=t()}else{n.is=t()}})(this,function(){var n={};n.VERSION="0.8.0";n.not={};n.all={};n.any={};var t=Object.prototype.toString;var e=Array.prototype.slice;var r=Object.prototype.hasOwnProperty;function a(n){return function(){return!n.apply(null,e.call(arguments))}}function u(n){return function(){var t=c(arguments);var e=t.length;for(var r=0;r<e;r++){if(!n.call(null,t[r])){return false}}return true}}function o(n){return function(){var t=c(arguments);var e=t.length;for(var r=0;r<e;r++){if(n.call(null,t[r])){return true}}return false}}var i={"<":function(n,t){return n<t},"<=":function(n,t){return n<=t},">":function(n,t){return n>t},">=":function(n,t){return n>=t}};function f(n,t){var e=t+"";var r=+(e.match(/\d+/)||NaN);var a=e.match(/^[<>]=?|/)[0];return i[a]?i[a](n,r):n==r||r!==r}function c(t){var r=e.call(t);var a=r.length;if(a===1&&n.array(r[0])){r=r[0]}return r}n.arguments=function(n){return t.call(n)==="[object Arguments]"||n!=null&&typeof n==="object"&&"callee"in n};n.array=Array.isArray||function(n){return t.call(n)==="[object Array]"};n.boolean=function(n){return n===true||n===false||t.call(n)==="[object Boolean]"};n.char=function(t){return n.string(t)&&t.length===1};n.date=function(n){return t.call(n)==="[object Date]"};n.domNode=function(t){return n.object(t)&&t.nodeType>0};n.error=function(n){return t.call(n)==="[object Error]"};n["function"]=function(n){return t.call(n)==="[object Function]"||typeof n==="function"};n.json=function(n){return t.call(n)==="[object Object]"};n.nan=function(n){return n!==n};n["null"]=function(n){return n===null};n.number=function(e){return n.not.nan(e)&&t.call(e)==="[object Number]"};n.object=function(n){return Object(n)===n};n.regexp=function(n){return t.call(n)==="[object RegExp]"};n.sameType=function(e,r){var a=t.call(e);if(a!==t.call(r)){return false}if(a==="[object Number]"){return!n.any.nan(e,r)||n.all.nan(e,r)}return true};n.sameType.api=["not"];n.string=function(n){return t.call(n)==="[object String]"};n.undefined=function(n){return n===void 0};n.windowObject=function(n){return n!=null&&typeof n==="object"&&"setInterval"in n};n.empty=function(t){if(n.object(t)){var e=Object.getOwnPropertyNames(t).length;if(e===0||e===1&&n.array(t)||e===2&&n.arguments(t)){return true}return false}return t===""};n.existy=function(n){return n!=null};n.falsy=function(n){return!n};n.truthy=a(n.falsy);n.above=function(t,e){return n.all.number(t,e)&&t>e};n.above.api=["not"];n.decimal=function(t){return n.number(t)&&t%1!==0};n.equal=function(t,e){if(n.all.number(t,e)){return t===e&&1/t===1/e}if(n.all.string(t,e)||n.all.regexp(t,e)){return""+t===""+e}if(n.all.boolean(t,e)){return t===e}return false};n.equal.api=["not"];n.even=function(t){return n.number(t)&&t%2===0};n.finite=isFinite||function(t){return n.not.infinite(t)&&n.not.nan(t)};n.infinite=function(n){return n===Infinity||n===-Infinity};n.integer=function(t){return n.number(t)&&t%1===0};n.negative=function(t){return n.number(t)&&t<0};n.odd=function(t){return n.number(t)&&t%2===1};n.positive=function(t){return n.number(t)&&t>0};n.under=function(t,e){return n.all.number(t,e)&&t<e};n.under.api=["not"];n.within=function(t,e,r){return n.all.number(t,e,r)&&t>e&&t<r};n.within.api=["not"];var l={affirmative:/^(?:1|t(?:rue)?|y(?:es)?|ok(?:ay)?)$/,alphaNumeric:/^[A-Za-z0-9]+$/,caPostalCode:/^(?!.*[DFIOQU])[A-VXY][0-9][A-Z]\s?[0-9][A-Z][0-9]$/,creditCard:/^(?:(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11}))$/,dateString:/^(1[0-2]|0?[1-9])([\/-])(3[01]|[12][0-9]|0?[1-9])(?:\2)(?:[0-9]{2})?[0-9]{2}$/,email:/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,eppPhone:/^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/,hexadecimal:/^(?:0x)?[0-9a-fA-F]+$/,hexColor:/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/,ipv4:/^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/,ipv6:/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i,nanpPhone:/^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/,socialSecurityNumber:/^(?!000|666)[0-8][0-9]{2}-?(?!00)[0-9]{2}-?(?!0000)[0-9]{4}$/,timeString:/^(2[0-3]|[01]?[0-9]):([0-5]?[0-9]):([0-5]?[0-9])$/,ukPostCode:/^[A-Z]{1,2}[0-9RCHNQ][0-9A-Z]?\s?[0-9][ABD-HJLNP-UW-Z]{2}$|^[A-Z]{2}-?[0-9]{4}$/,url:/^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/i,usZipCode:/^[0-9]{5}(?:-[0-9]{4})?$/};function d(t,e){n[t]=function(n){return e[t].test(n)}}for(var s in l){if(l.hasOwnProperty(s)){d(s,l)}}n.ip=function(t){return n.ipv4(t)||n.ipv6(t)};n.capitalized=function(t){if(n.not.string(t)){return false}var e=t.split(" ");for(var r=0;r<e.length;r++){var a=e[r];if(a.length){var u=a.charAt(0);if(u!==u.toUpperCase()){return false}}}return true};n.endWith=function(t,e){if(n.not.string(t)){return false}e+="";var r=t.length-e.length;return r>=0&&t.indexOf(e,r)===r};n.endWith.api=["not"];n.include=function(n,t){return n.indexOf(t)>-1};n.include.api=["not"];n.lowerCase=function(t){return n.string(t)&&t===t.toLowerCase()};n.palindrome=function(t){if(n.not.string(t)){return false}t=t.replace(/[^a-zA-Z0-9]+/g,"").toLowerCase();var e=t.length-1;for(var r=0,a=Math.floor(e/2);r<=a;r++){if(t.charAt(r)!==t.charAt(e-r)){return false}}return true};n.space=function(t){if(n.not.char(t)){return false}var e=t.charCodeAt(0);return e>8&&e<14||e===32};n.startWith=function(t,e){return n.string(t)&&t.indexOf(e)===0};n.startWith.api=["not"];n.upperCase=function(t){return n.string(t)&&t===t.toUpperCase()};var F=["sunday","monday","tuesday","wednesday","thursday","friday","saturday"];var p=["january","february","march","april","may","june","july","august","september","october","november","december"];n.day=function(t,e){return n.date(t)&&e.toLowerCase()===F[t.getDay()]};n.day.api=["not"];n.dayLightSavingTime=function(n){var t=new Date(n.getFullYear(),0,1);var e=new Date(n.getFullYear(),6,1);var r=Math.max(t.getTimezoneOffset(),e.getTimezoneOffset());return n.getTimezoneOffset()<r};n.future=function(t){var e=new Date;return n.date(t)&&t.getTime()>e.getTime()};n.inDateRange=function(t,e,r){if(n.not.date(t)||n.not.date(e)||n.not.date(r)){return false}var a=t.getTime();return a>e.getTime()&&a<r.getTime()};n.inDateRange.api=["not"];n.inLastMonth=function(t){return n.inDateRange(t,new Date((new Date).setMonth((new Date).getMonth()-1)),new Date)};n.inLastWeek=function(t){return n.inDateRange(t,new Date((new Date).setDate((new Date).getDate()-7)),new Date)};n.inLastYear=function(t){return n.inDateRange(t,new Date((new Date).setFullYear((new Date).getFullYear()-1)),new Date)};n.inNextMonth=function(t){return n.inDateRange(t,new Date,new Date((new Date).setMonth((new Date).getMonth()+1)))};n.inNextWeek=function(t){return n.inDateRange(t,new Date,new Date((new Date).setDate((new Date).getDate()+7)))};n.inNextYear=function(t){return n.inDateRange(t,new Date,new Date((new Date).setFullYear((new Date).getFullYear()+1)))};n.leapYear=function(t){return n.number(t)&&(t%4===0&&t%100!==0||t%400===0)};n.month=function(t,e){return n.date(t)&&e.toLowerCase()===p[t.getMonth()]};n.month.api=["not"];n.past=function(t){var e=new Date;return n.date(t)&&t.getTime()<e.getTime()};n.quarterOfYear=function(t,e){return n.date(t)&&n.number(e)&&e===Math.floor((t.getMonth()+3)/3)};n.quarterOfYear.api=["not"];n.today=function(t){var e=new Date;var r=e.toDateString();return n.date(t)&&t.toDateString()===r};n.tomorrow=function(t){var e=new Date;var r=new Date(e.setDate(e.getDate()+1)).toDateString();return n.date(t)&&t.toDateString()===r};n.weekend=function(t){return n.date(t)&&(t.getDay()===6||t.getDay()===0)};n.weekday=a(n.weekend);n.year=function(t,e){return n.date(t)&&n.number(e)&&e===t.getFullYear()};n.year.api=["not"];n.yesterday=function(t){var e=new Date;var r=new Date(e.setDate(e.getDate()-1)).toDateString();return n.date(t)&&t.toDateString()===r};var D=n.windowObject(typeof global=="object"&&global)&&global;var h=n.windowObject(typeof self=="object"&&self)&&self;var v=n.windowObject(typeof this=="object"&&this)&&this;var b=D||h||v||Function("return this")();var g=h&&h.document;var m=b.is;var w=h&&h.navigator;var y=(w&&w.appVersion||"").toLowerCase();var x=(w&&w.userAgent||"").toLowerCase();var A=(w&&w.vendor||"").toLowerCase();n.android=function(){return/android/.test(x)};n.android.api=["not"];n.androidPhone=function(){return/android/.test(x)&&/mobile/.test(x)};n.androidPhone.api=["not"];n.androidTablet=function(){return/android/.test(x)&&!/mobile/.test(x)};n.androidTablet.api=["not"];n.blackberry=function(){return/blackberry/.test(x)||/bb10/.test(x)};n.blackberry.api=["not"];n.chrome=function(n){var t=/google inc/.test(A)?x.match(/(?:chrome|crios)\/(\d+)/):null;return t!==null&&f(t[1],n)};n.chrome.api=["not"];n.desktop=function(){return n.not.mobile()&&n.not.tablet()};n.desktop.api=["not"];n.edge=function(n){var t=x.match(/edge\/(\d+)/);return t!==null&&f(t[1],n)};n.edge.api=["not"];n.firefox=function(n){var t=x.match(/(?:firefox|fxios)\/(\d+)/);return t!==null&&f(t[1],n)};n.firefox.api=["not"];n.ie=function(n){var t=x.match(/(?:msie |trident.+?; rv:)(\d+)/);return t!==null&&f(t[1],n)};n.ie.api=["not"];n.ios=function(){return n.iphone()||n.ipad()||n.ipod()};n.ios.api=["not"];n.ipad=function(n){var t=x.match(/ipad.+?os (\d+)/);return t!==null&&f(t[1],n)};n.ipad.api=["not"];n.iphone=function(n){var t=x.match(/iphone(?:.+?os (\d+))?/);return t!==null&&f(t[1]||1,n)};n.iphone.api=["not"];n.ipod=function(n){var t=x.match(/ipod.+?os (\d+)/);return t!==null&&f(t[1],n)};n.ipod.api=["not"];n.linux=function(){return/linux/.test(y)};n.linux.api=["not"];n.mac=function(){return/mac/.test(y)};n.mac.api=["not"];n.mobile=function(){return n.iphone()||n.ipod()||n.androidPhone()||n.blackberry()||n.windowsPhone()};n.mobile.api=["not"];n.offline=a(n.online);n.offline.api=["not"];n.online=function(){return!w||w.onLine===true};n.online.api=["not"];n.opera=function(n){var t=x.match(/(?:^opera.+?version|opr)\/(\d+)/);return t!==null&&f(t[1],n)};n.opera.api=["not"];n.phantom=function(n){var t=x.match(/phantomjs\/(\d+)/);return t!==null&&f(t[1],n)};n.phantom.api=["not"];n.safari=function(n){var t=x.match(/version\/(\d+).+?safari/);return t!==null&&f(t[1],n)};n.safari.api=["not"];n.tablet=function(){return n.ipad()||n.androidTablet()||n.windowsTablet()};n.tablet.api=["not"];n.touchDevice=function(){return!!g&&("ontouchstart"in h||"DocumentTouch"in h&&g instanceof DocumentTouch)};n.touchDevice.api=["not"];n.windows=function(){return/win/.test(y)};n.windows.api=["not"];n.windowsPhone=function(){return n.windows()&&/phone/.test(x)};n.windowsPhone.api=["not"];n.windowsTablet=function(){return n.windows()&&n.not.windowsPhone()&&/touch/.test(x)};n.windowsTablet.api=["not"];n.propertyCount=function(t,e){if(n.not.object(t)||n.not.number(e)){return false}var a=0;for(var u in t){if(r.call(t,u)&&++a>e){return false}}return a===e};n.propertyCount.api=["not"];n.propertyDefined=function(t,e){return n.object(t)&&n.string(e)&&e in t};n.propertyDefined.api=["not"];n.inArray=function(t,e){if(n.not.array(e)){return false}for(var r=0;r<e.length;r++){if(e[r]===t){return true}}return false};n.inArray.api=["not"];n.sorted=function(t,e){if(n.not.array(t)){return false}var r=i[e]||i[">="];for(var a=1;a<t.length;a++){if(!r(t[a],t[a-1])){return false}}return true};function j(){var t=n;for(var e in t){if(r.call(t,e)&&n["function"](t[e])){var i=t[e].api||["not","all","any"];for(var f=0;f<i.length;f++){if(i[f]==="not"){n.not[e]=a(n[e])}if(i[f]==="all"){n.all[e]=u(n[e])}if(i[f]==="any"){n.any[e]=o(n[e])}}}}}j();n.setNamespace=function(){b.is=m;return this};n.setRegexp=function(n,t){for(var e in l){if(r.call(l,e)&&t===e){l[e]=n}}};return n});
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "_from": "is_js@^0.9.0",
3 + "_id": "is_js@0.9.0",
4 + "_inBundle": false,
5 + "_integrity": "sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0=",
6 + "_location": "/is_js",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "is_js@^0.9.0",
12 + "name": "is_js",
13 + "escapedName": "is_js",
14 + "rawSpec": "^0.9.0",
15 + "saveSpec": null,
16 + "fetchSpec": "^0.9.0"
17 + },
18 + "_requiredBy": [
19 + "/request-ip"
20 + ],
21 + "_resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz",
22 + "_shasum": "0ab94540502ba7afa24c856aa985561669e9c52d",
23 + "_spec": "is_js@^0.9.0",
24 + "_where": "C:\\Users\\KoMoGoon\\Desktop\\oss_project\\Singer-Composer\\node_modules\\request-ip",
25 + "bugs": {
26 + "url": "https://github.com/arasatasaygin/is.js/issues"
27 + },
28 + "bundleDependencies": false,
29 + "deprecated": false,
30 + "description": "micro check library",
31 + "devDependencies": {
32 + "chai": "^3.4.0",
33 + "eslint": "^2.13.1",
34 + "lodash": "^4.15.0",
35 + "mocha": "^2.2.1",
36 + "mocha-phantomjs": "^4.1.0",
37 + "pre-commit": "^1.1.3",
38 + "uglify-js": "^2.7.3"
39 + },
40 + "files": [
41 + "is.js",
42 + "is.min.js"
43 + ],
44 + "homepage": "http://is.js.org/",
45 + "license": "MIT",
46 + "main": "is.js",
47 + "name": "is_js",
48 + "pre-commit": [
49 + "lint"
50 + ],
51 + "repository": {
52 + "type": "git",
53 + "url": "git+https://github.com/arasatasaygin/is.js.git"
54 + },
55 + "scripts": {
56 + "build": "npm run lint && npm run min",
57 + "lint": "eslint .",
58 + "min": "uglifyjs is.js -m --comments \"/^!/\" -o is.min.js",
59 + "test": "mocha --check-leaks -R dot",
60 + "test:phantom": "mocha-phantomjs -R dot test/index.html"
61 + },
62 + "version": "0.9.0"
63 +}
1 +# Change Log
2 +
3 +## [2.1.2](https://github.com/pbojinov/request-ip/tree/2.1.2) (2018-10-29)
4 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/2.1.1...2.1.2)
5 +
6 +**Closed issues:**
7 +
8 +- Handle Firebase hosting header fastly-client-ip [\#37](https://github.com/pbojinov/request-ip/issues/37)
9 +
10 +**Merged pull requests:**
11 +
12 +- chore: improve packaging [\#40](https://github.com/pbojinov/request-ip/pull/40) ([pi0](https://github.com/pi0))
13 +- fixed Cannot redefine property: clientIp error [\#39](https://github.com/pbojinov/request-ip/pull/39) ([karankohli13](https://github.com/karankohli13))
14 +- Add firebase hosting header [\#38](https://github.com/pbojinov/request-ip/pull/38) ([vishalvijay](https://github.com/vishalvijay))
15 +
16 +## [2.1.1](https://github.com/pbojinov/request-ip/tree/2.1.1) (2018-07-03)
17 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/2.1.0...2.1.1)
18 +
19 +## [2.1.0](https://github.com/pbojinov/request-ip/tree/2.1.0) (2018-07-03)
20 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/2.0.2...2.1.0)
21 +
22 +**Closed issues:**
23 +
24 +- Not getting the right ip first time [\#28](https://github.com/pbojinov/request-ip/issues/28)
25 +- Allow using node \> 6 [\#27](https://github.com/pbojinov/request-ip/issues/27)
26 +
27 +**Merged pull requests:**
28 +
29 +- Get client ip when using AWS Api Gateway + Lambda. [\#35](https://github.com/pbojinov/request-ip/pull/35) ([rafaelthemendes](https://github.com/rafaelthemendes))
30 +- redefine attribute getter [\#34](https://github.com/pbojinov/request-ip/pull/34) ([isayme](https://github.com/isayme))
31 +
32 +## [2.0.2](https://github.com/pbojinov/request-ip/tree/2.0.2) (2017-06-26)
33 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/2.0.1...2.0.2)
34 +
35 +**Closed issues:**
36 +
37 +- azure web app adds port to x-forwarded-for [\#29](https://github.com/pbojinov/request-ip/issues/29)
38 +
39 +**Merged pull requests:**
40 +
41 +- handling x-forwarded-for with ip:port [\#30](https://github.com/pbojinov/request-ip/pull/30) ([luisrudge](https://github.com/luisrudge))
42 +
43 +## [2.0.1](https://github.com/pbojinov/request-ip/tree/2.0.1) (2017-03-09)
44 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/2.0.0...2.0.1)
45 +
46 +**Implemented enhancements:**
47 +
48 +- ES2015 Support [\#22](https://github.com/pbojinov/request-ip/issues/22)
49 +
50 +## [2.0.0](https://github.com/pbojinov/request-ip/tree/2.0.0) (2017-03-07)
51 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.3.0...2.0.0)
52 +
53 +**Closed issues:**
54 +
55 +- optimized your code a bit \(no need to evalutate every option before choosing first one that matches. just evaluate then return on first match\) [\#15](https://github.com/pbojinov/request-ip/issues/15)
56 +
57 +**Merged pull requests:**
58 +
59 +- Refactor to ES6 [\#23](https://github.com/pbojinov/request-ip/pull/23) ([fluxsauce](https://github.com/fluxsauce))
60 +
61 +## [1.3.0](https://github.com/pbojinov/request-ip/tree/1.3.0) (2017-03-03)
62 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.2.3...1.3.0)
63 +
64 +**Closed issues:**
65 +
66 +- Support Cloudflare? [\#20](https://github.com/pbojinov/request-ip/issues/20)
67 +- How to receive IP in client [\#17](https://github.com/pbojinov/request-ip/issues/17)
68 +
69 +**Merged pull requests:**
70 +
71 +- Adding support for CF-Connecting-IP and True-Client-IP [\#21](https://github.com/pbojinov/request-ip/pull/21) ([fluxsauce](https://github.com/fluxsauce))
72 +- Return once we find something and don't crash if req.headers is undefined [\#19](https://github.com/pbojinov/request-ip/pull/19) ([rokob](https://github.com/rokob))
73 +- Ignore 'unknown' ip addresses in X-Forwarded-For header [\#18](https://github.com/pbojinov/request-ip/pull/18) ([raunc](https://github.com/raunc))
74 +
75 +## [1.2.3](https://github.com/pbojinov/request-ip/tree/1.2.3) (2016-11-02)
76 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.2.2...1.2.3)
77 +
78 +**Closed issues:**
79 +
80 +- Are there any security concerns when saving the IP directly to a database? [\#16](https://github.com/pbojinov/request-ip/issues/16)
81 +- I'm not getting local host ip address 127.0.0.1 [\#14](https://github.com/pbojinov/request-ip/issues/14)
82 +
83 +## [1.2.2](https://github.com/pbojinov/request-ip/tree/1.2.2) (2016-01-27)
84 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.2.1...1.2.2)
85 +
86 +## [1.2.1](https://github.com/pbojinov/request-ip/tree/1.2.1) (2016-01-27)
87 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.2.0...1.2.1)
88 +
89 +**Merged pull requests:**
90 +
91 +- introduce a built-in default implementation for a connect-middleware [\#12](https://github.com/pbojinov/request-ip/pull/12) ([osherx](https://github.com/osherx))
92 +
93 +## [1.2.0](https://github.com/pbojinov/request-ip/tree/1.2.0) (2016-01-27)
94 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.1.4...1.2.0)
95 +
96 +**Merged pull requests:**
97 +
98 +- Cleanup [\#13](https://github.com/pbojinov/request-ip/pull/13) ([minecrawler](https://github.com/minecrawler))
99 +- Got it working in a case that was returning null [\#11](https://github.com/pbojinov/request-ip/pull/11) ([andfaulkner](https://github.com/andfaulkner))
100 +
101 +## [1.1.4](https://github.com/pbojinov/request-ip/tree/1.1.4) (2015-07-23)
102 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.1.3...1.1.4)
103 +
104 +**Merged pull requests:**
105 +
106 +- Add case management where you can not find the IP address [\#10](https://github.com/pbojinov/request-ip/pull/10) ([sitexw](https://github.com/sitexw))
107 +
108 +## [1.1.3](https://github.com/pbojinov/request-ip/tree/1.1.3) (2015-04-20)
109 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.1.2...1.1.3)
110 +
111 +## [1.1.2](https://github.com/pbojinov/request-ip/tree/1.1.2) (2015-04-04)
112 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.1.1...1.1.2)
113 +
114 +## [1.1.1](https://github.com/pbojinov/request-ip/tree/1.1.1) (2015-04-04)
115 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/1.1.0...1.1.1)
116 +
117 +**Closed issues:**
118 +
119 +- needs semver [\#7](https://github.com/pbojinov/request-ip/issues/7)
120 +
121 +## [1.1.0](https://github.com/pbojinov/request-ip/tree/1.1.0) (2015-04-04)
122 +[Full Changelog](https://github.com/pbojinov/request-ip/compare/v0.0.4...1.1.0)
123 +
124 +**Merged pull requests:**
125 +
126 +- Update README.md [\#9](https://github.com/pbojinov/request-ip/pull/9) ([coolaj86](https://github.com/coolaj86))
127 +- This deserves a production version number. [\#8](https://github.com/pbojinov/request-ip/pull/8) ([coolaj86](https://github.com/coolaj86))
128 +
129 +## [v0.0.4](https://github.com/pbojinov/request-ip/tree/v0.0.4) (2015-01-16)
130 +**Closed issues:**
131 +
132 +- Invalid header [\#5](https://github.com/pbojinov/request-ip/issues/5)
133 +- replace req.header\('X-Forwarded-For'\) for req.header\('X-Forwarder-For'\)\); [\#3](https://github.com/pbojinov/request-ip/issues/3)
134 +- Nginx problems [\#2](https://github.com/pbojinov/request-ip/issues/2)
135 +
136 +**Merged pull requests:**
137 +
138 +- Add support for X-Real-IP Header [\#6](https://github.com/pbojinov/request-ip/pull/6) ([pmarques](https://github.com/pmarques))
139 +- fix bug X-Forwarder-For [\#4](https://github.com/pbojinov/request-ip/pull/4) ([morello-cl](https://github.com/morello-cl))
140 +- Add a Bitdeli Badge to README [\#1](https://github.com/pbojinov/request-ip/pull/1) ([bitdeli-chef](https://github.com/bitdeli-chef))
141 +
142 +
143 +
144 +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
...\ No newline at end of file ...\ No newline at end of file
1 +The MIT License (MIT)
2 +
3 +Copyright (c) 2018 Petar Bojinov - petarbojinov@gmail.com
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy of
6 +this software and associated documentation files (the "Software"), to deal in
7 +the Software without restriction, including without limitation the rights to
8 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 +the Software, and to permit persons to whom the Software is furnished to do so,
10 +subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +# request-ip
2 +
3 +A tiny Node.js module for retrieving a request's IP address.
4 +
5 +![](https://nodei.co/npm/request-ip.png?downloads=true&cacheBust=2)
6 +
7 +![](https://travis-ci.org/pbojinov/request-ip.svg?branch=master)
8 +[![Coverage Status](https://coveralls.io/repos/pbojinov/request-ip/badge.svg)](https://coveralls.io/r/pbojinov/request-ip)
9 +![](https://img.shields.io/npm/l/express.svg)
10 +[![npm version](https://badge.fury.io/js/request-ip.svg)](https://badge.fury.io/js/request-ip)
11 +
12 +## Installation
13 +
14 +```bash
15 +npm install request-ip --save
16 +```
17 +
18 +## Getting Started
19 +
20 +```javascript
21 +const requestIp = require('request-ip');
22 +
23 +// inside middleware handler
24 +const ipMiddleware = function(req, res, next) {
25 + const clientIp = requestIp.getClientIp(req);
26 + next();
27 +};
28 +
29 +// on localhost you'll see 127.0.0.1 if you're using IPv4
30 +// or ::1, ::ffff:127.0.0.1 if you're using IPv6
31 +```
32 +
33 +### As Connect Middleware
34 +
35 +```javascript
36 +const requestIp = require('request-ip');
37 +app.use(requestIp.mw())
38 +
39 +app.use(function(req, res) {
40 + const ip = req.clientIp;
41 + res.end(ip);
42 +});
43 +```
44 +
45 +To see a full working code for the middleware, check out the [examples](https://github.com/pbojinov/request-ip/tree/master/examples) folder.
46 +
47 +The connect-middleware also supports retrieving the ip address under a custom attribute name, which also works as a container for any future settings.
48 +
49 +## How It Works
50 +
51 +It looks for specific headers in the request and falls back to some defaults if they do not exist.
52 +
53 +The user ip is determined by the following order:
54 +
55 +1. `X-Client-IP`
56 +2. `X-Forwarded-For` (Header may return multiple IP addresses in the format: "client IP, proxy 1 IP, proxy 2 IP", so we take the the first one.)
57 +3. `CF-Connecting-IP` (Cloudflare)
58 +4. `Fastly-Client-Ip` (Fastly CDN and Firebase hosting header when forwared to a cloud function)
59 +5. `True-Client-Ip` (Akamai and Cloudflare)
60 +6. `X-Real-IP` (Nginx proxy/FastCGI)
61 +7. `X-Cluster-Client-IP` (Rackspace LB, Riverbed Stingray)
62 +8. `X-Forwarded`, `Forwarded-For` and `Forwarded` (Variations of #2)
63 +9. `req.connection.remoteAddress`
64 +10. `req.socket.remoteAddress`
65 +11. `req.connection.socket.remoteAddress`
66 +12. `req.info.remoteAddress`
67 +
68 +If an IP address cannot be found, it will return `null`.
69 +
70 +## Samples Use Cases
71 +
72 +* Getting a user's IP for geolocation.
73 +
74 +
75 +## Running the Tests
76 +
77 +Make sure you have the necessary dev dependencies needed to run the tests:
78 +
79 +```
80 +npm install
81 +```
82 +
83 +Run the integration tests
84 +
85 +```
86 +npm test
87 +```
88 +
89 +## Release Notes
90 +
91 +See the wonderful [changelog](https://github.com/pbojinov/request-ip/blob/master/CHANGELOG.md)
92 +
93 +To easily generate a new changelog, install [github-changelog-generator](https://github.com/skywinder/github-changelog-generator) then run `npm run changelog`.
94 +
95 +## Contributors
96 +
97 +* Thanks to [@osherx](https://github.com/osherx) for adding the connect-middleware.
98 +* Thanks to [@raunc](https://github.com/raunc) for adding Squid proxy support.
99 +* Thanks to [@fluxsauce](https://github.com/fluxsauce) for adding `CF-Connecting-IP`, `True-Client-IP`, and ES6 support.
100 +* Thanks to [@vishalvijay](https://github.com/vishalvijay) for adding Fastly/Firebase hosting support.
101 +
102 +## License
103 +
104 +The MIT License (MIT) - 2018
No preview for this file type
1 +"use strict";
2 +
3 +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4 +
5 +var is = require('is_js');
6 +/**
7 + * Parse x-forwarded-for headers.
8 + *
9 + * @param {string} value - The value to be parsed.
10 + * @return {string|null} First known IP address, if any.
11 + */
12 +
13 +
14 +function getClientIpFromXForwardedFor(value) {
15 + if (!is.existy(value)) {
16 + return null;
17 + }
18 +
19 + if (is.not.string(value)) {
20 + throw new TypeError("Expected a string, got \"".concat(_typeof(value), "\""));
21 + } // x-forwarded-for may return multiple IP addresses in the format:
22 + // "client IP, proxy 1 IP, proxy 2 IP"
23 + // Therefore, the right-most IP address is the IP address of the most recent proxy
24 + // and the left-most IP address is the IP address of the originating client.
25 + // source: http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
26 + // Azure Web App's also adds a port for some reason, so we'll only use the first part (the IP)
27 +
28 +
29 + var forwardedIps = value.split(',').map(function (e) {
30 + var ip = e.trim();
31 +
32 + if (ip.includes(':')) {
33 + var splitted = ip.split(':'); // make sure we only use this if it's ipv4 (ip:port)
34 +
35 + if (splitted.length === 2) {
36 + return splitted[0];
37 + }
38 + }
39 +
40 + return ip;
41 + }); // Sometimes IP addresses in this header can be 'unknown' (http://stackoverflow.com/a/11285650).
42 + // Therefore taking the left-most IP address that is not unknown
43 + // A Squid configuration directive can also set the value to "unknown" (http://www.squid-cache.org/Doc/config/forwarded_for/)
44 +
45 + return forwardedIps.find(is.ip);
46 +}
47 +/**
48 + * Determine client IP address.
49 + *
50 + * @param req
51 + * @returns {string} ip - The IP address if known, defaulting to empty string if unknown.
52 + */
53 +
54 +
55 +function getClientIp(req) {
56 + // Server is probably behind a proxy.
57 + if (req.headers) {
58 + // Standard headers used by Amazon EC2, Heroku, and others.
59 + if (is.ip(req.headers['x-client-ip'])) {
60 + return req.headers['x-client-ip'];
61 + } // Load-balancers (AWS ELB) or proxies.
62 +
63 +
64 + var xForwardedFor = getClientIpFromXForwardedFor(req.headers['x-forwarded-for']);
65 +
66 + if (is.ip(xForwardedFor)) {
67 + return xForwardedFor;
68 + } // Cloudflare.
69 + // @see https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
70 + // CF-Connecting-IP - applied to every request to the origin.
71 +
72 +
73 + if (is.ip(req.headers['cf-connecting-ip'])) {
74 + return req.headers['cf-connecting-ip'];
75 + } // Fastly and Firebase hosting header (When forwared to cloud function)
76 +
77 +
78 + if (is.ip(req.headers['fastly-client-ip'])) {
79 + return req.headers['fastly-client-ip'];
80 + } // Akamai and Cloudflare: True-Client-IP.
81 +
82 +
83 + if (is.ip(req.headers['true-client-ip'])) {
84 + return req.headers['true-client-ip'];
85 + } // Default nginx proxy/fcgi; alternative to x-forwarded-for, used by some proxies.
86 +
87 +
88 + if (is.ip(req.headers['x-real-ip'])) {
89 + return req.headers['x-real-ip'];
90 + } // (Rackspace LB and Riverbed's Stingray)
91 + // http://www.rackspace.com/knowledge_center/article/controlling-access-to-linux-cloud-sites-based-on-the-client-ip-address
92 + // https://splash.riverbed.com/docs/DOC-1926
93 +
94 +
95 + if (is.ip(req.headers['x-cluster-client-ip'])) {
96 + return req.headers['x-cluster-client-ip'];
97 + }
98 +
99 + if (is.ip(req.headers['x-forwarded'])) {
100 + return req.headers['x-forwarded'];
101 + }
102 +
103 + if (is.ip(req.headers['forwarded-for'])) {
104 + return req.headers['forwarded-for'];
105 + }
106 +
107 + if (is.ip(req.headers.forwarded)) {
108 + return req.headers.forwarded;
109 + }
110 + } // Remote address checks.
111 +
112 +
113 + if (is.existy(req.connection)) {
114 + if (is.ip(req.connection.remoteAddress)) {
115 + return req.connection.remoteAddress;
116 + }
117 +
118 + if (is.existy(req.connection.socket) && is.ip(req.connection.socket.remoteAddress)) {
119 + return req.connection.socket.remoteAddress;
120 + }
121 + }
122 +
123 + if (is.existy(req.socket) && is.ip(req.socket.remoteAddress)) {
124 + return req.socket.remoteAddress;
125 + }
126 +
127 + if (is.existy(req.info) && is.ip(req.info.remoteAddress)) {
128 + return req.info.remoteAddress;
129 + } // AWS Api Gateway + Lambda
130 +
131 +
132 + if (is.existy(req.requestContext) && is.existy(req.requestContext.identity) && is.ip(req.requestContext.identity.sourceIp)) {
133 + return req.requestContext.identity.sourceIp;
134 + }
135 +
136 + return null;
137 +}
138 +/**
139 + * Expose request IP as a middleware.
140 + *
141 + * @param {object} [options] - Configuration.
142 + * @param {string} [options.attributeName] - Name of attribute to augment request object with.
143 + * @return {*}
144 + */
145 +
146 +
147 +function mw(options) {
148 + // Defaults.
149 + var configuration = is.not.existy(options) ? {} : options; // Validation.
150 +
151 + if (is.not.object(configuration)) {
152 + throw new TypeError('Options must be an object!');
153 + }
154 +
155 + var attributeName = configuration.attributeName || 'clientIp';
156 + return function (req, res, next) {
157 + var ip = getClientIp(req);
158 + Object.defineProperty(req, attributeName, {
159 + get: function get() {
160 + return ip;
161 + },
162 + configurable: true
163 + });
164 + next();
165 + };
166 +}
167 +
168 +module.exports = {
169 + getClientIpFromXForwardedFor: getClientIpFromXForwardedFor,
170 + getClientIp: getClientIp,
171 + mw: mw
172 +};
173 +
1 +{
2 + "_from": "request-ip",
3 + "_id": "request-ip@2.1.3",
4 + "_inBundle": false,
5 + "_integrity": "sha512-J3qdE/IhVM3BXkwMIVO4yFrvhJlU3H7JH16+6yHucadT4fePnR8dyh+vEs6FIx0S2x5TCt2ptiPfHcn0sqhbYQ==",
6 + "_location": "/request-ip",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "tag",
10 + "registry": true,
11 + "raw": "request-ip",
12 + "name": "request-ip",
13 + "escapedName": "request-ip",
14 + "rawSpec": "",
15 + "saveSpec": null,
16 + "fetchSpec": "latest"
17 + },
18 + "_requiredBy": [
19 + "#USER",
20 + "/"
21 + ],
22 + "_resolved": "https://registry.npmjs.org/request-ip/-/request-ip-2.1.3.tgz",
23 + "_shasum": "99ab2bafdeaf2002626e28083cb10597511d9e14",
24 + "_spec": "request-ip",
25 + "_where": "C:\\Users\\KoMoGoon\\Desktop\\oss_project\\Singer-Composer",
26 + "author": {
27 + "name": "Petar Bojinov",
28 + "email": "petarbojinov@gmail.com"
29 + },
30 + "bugs": {
31 + "url": "https://github.com/pbojinov/request-ip/issues"
32 + },
33 + "bundleDependencies": false,
34 + "contributors": [
35 + {
36 + "name": "Jon Peck",
37 + "email": "jpeck@fluxsauce.com"
38 + }
39 + ],
40 + "dependencies": {
41 + "is_js": "^0.9.0"
42 + },
43 + "deprecated": false,
44 + "description": "A small node.js module to retrieve the request's IP address",
45 + "devDependencies": {
46 + "@babel/cli": "^7.0.0-beta.51",
47 + "@babel/core": "^7.0.0-beta.51",
48 + "@babel/preset-env": "^7.0.0-beta.51",
49 + "coveralls": "^3.0.2",
50 + "eslint": "^5.8.0",
51 + "eslint-config-airbnb-base": "^13.1.0",
52 + "eslint-plugin-import": "^2.2.0",
53 + "nyc": "^13.1.0",
54 + "request": "^2.54.0",
55 + "tap-spec": "^5.0.0",
56 + "tape": "^4.9.1"
57 + },
58 + "files": [
59 + "dist"
60 + ],
61 + "homepage": "https://github.com/pbojinov/request-ip",
62 + "keywords": [
63 + "request ip",
64 + "ip",
65 + "address",
66 + "request",
67 + "proxy",
68 + "client",
69 + "header",
70 + "X-Client-IP",
71 + "X-Forwarded-For",
72 + "CF-Connecting-IP",
73 + "Fastly-Client-IP",
74 + "True-Client-IP",
75 + "X-Real-IP",
76 + "X-Cluster-Client-IP",
77 + "X-Forwarded",
78 + "Forwarded-For",
79 + "connection.remoteAddress",
80 + "connection.socket.remoteAddress",
81 + "req.info.remoteAddress",
82 + "middleware",
83 + "ipv4",
84 + "ipv6"
85 + ],
86 + "license": "MIT",
87 + "main": "./dist/index.js",
88 + "name": "request-ip",
89 + "repository": {
90 + "type": "git",
91 + "url": "git+https://github.com/pbojinov/request-ip.git"
92 + },
93 + "scripts": {
94 + "build": "babel ./src/index.js > ./dist/index.js",
95 + "changelog": "github_changelog_generator -u pbojinov -p request-ip",
96 + "coverage": "nyc report --reporter=text-lcov | coveralls",
97 + "test": "nyc --reporter=html --reporter=text --check-coverage --lines=100 --statements=100 tape ./test/index.js"
98 + },
99 + "version": "2.1.3"
100 +}
...@@ -750,6 +750,11 @@ ...@@ -750,6 +750,11 @@
750 "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 750 "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
751 "dev": true 751 "dev": true
752 }, 752 },
753 + "is_js": {
754 + "version": "0.9.0",
755 + "resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz",
756 + "integrity": "sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0="
757 + },
753 "isarray": { 758 "isarray": {
754 "version": "1.0.0", 759 "version": "1.0.0",
755 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 760 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
...@@ -1154,6 +1159,14 @@ ...@@ -1154,6 +1159,14 @@
1154 } 1159 }
1155 } 1160 }
1156 }, 1161 },
1162 + "request-ip": {
1163 + "version": "2.1.3",
1164 + "resolved": "https://registry.npmjs.org/request-ip/-/request-ip-2.1.3.tgz",
1165 + "integrity": "sha512-J3qdE/IhVM3BXkwMIVO4yFrvhJlU3H7JH16+6yHucadT4fePnR8dyh+vEs6FIx0S2x5TCt2ptiPfHcn0sqhbYQ==",
1166 + "requires": {
1167 + "is_js": "^0.9.0"
1168 + }
1169 + },
1157 "request-promise-core": { 1170 "request-promise-core": {
1158 "version": "1.1.4", 1171 "version": "1.1.4",
1159 "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", 1172 "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
12 "ejs": "^3.1.6", 12 "ejs": "^3.1.6",
13 "express": "^4.17.1", 13 "express": "^4.17.1",
14 "mysql": "^2.18.1", 14 "mysql": "^2.18.1",
15 + "request-ip": "^2.1.3",
15 "socket.io": "^4.4.0" 16 "socket.io": "^4.4.0"
16 }, 17 },
17 "devDependencies": { 18 "devDependencies": {
......
...@@ -60,10 +60,10 @@ create table board( ...@@ -60,10 +60,10 @@ create table board(
60 >UPDATE board SET idx = @COUNT:=@COUNT+1; 60 >UPDATE board SET idx = @COUNT:=@COUNT+1;
61 61
62 --- 62 ---
63 -### 최종 수정: 2021-11-23 01:53<br> 63 +### 최종 수정: 2021-11-23 02:49<br>
64 ### 수정 내용: 64 ### 수정 내용:
65 0. 채팅기능에 버그가 있는 것 같음-피드백 바람(undefined님이 나가셨습니다. -> 콘솔에 계속 출력됨) 65 0. 채팅기능에 버그가 있는 것 같음-피드백 바람(undefined님이 나가셨습니다. -> 콘솔에 계속 출력됨)
66 -1. 일부 수정 66 +1. 로그에 IP 추가
67 2. 로그에 시간 추가 67 2. 로그에 시간 추가
68 3. 시간 실시간 반영 68 3. 시간 실시간 반영
69 4. 게시글 수정 및 삭제 세션+권한 연동/DB수정 69 4. 게시글 수정 및 삭제 세션+권한 연동/DB수정
......
...@@ -2,6 +2,7 @@ var express = require('express') ...@@ -2,6 +2,7 @@ var express = require('express')
2 var app = express() 2 var app = express()
3 var router = express.Router(); 3 var router = express.Router();
4 var path = require('path') // 상대경로 4 var path = require('path') // 상대경로
5 +var requestIp = require('request-ip');
5 6
6 // 로그용 7 // 로그용
7 var logString; 8 var logString;
...@@ -24,14 +25,15 @@ init() ...@@ -24,14 +25,15 @@ init()
24 25
25 // main page는 login이 된 상태(세션정보가 있을때만) 접근이 가능하게 하자 -> info에 구현해놓음. 26 // main page는 login이 된 상태(세션정보가 있을때만) 접근이 가능하게 하자 -> info에 구현해놓음.
26 router.get('/', function(req, res){ 27 router.get('/', function(req, res){
28 + var ip = requestIp.getClientIp(req);
27 var id = req.user; 29 var id = req.user;
28 if(!id){ 30 if(!id){
29 - console.log(logString+'익명의 유저가 about 페이지에서 작업 중입니다.') 31 + console.log(logString+'익명의 유저가 about 페이지에서 작업 중입니다.('+ip+')')
30 res.sendFile(path.join(__dirname, "../../public/about.html")) 32 res.sendFile(path.join(__dirname, "../../public/about.html"))
31 } 33 }
32 if(id){ 34 if(id){
33 var nickname = req.user.nickname; 35 var nickname = req.user.nickname;
34 - console.log(logString+req.user.ID+'('+nickname+') 유저가 about 페이지에서 작업 중입니다.') 36 + console.log(logString+req.user.ID+'('+nickname+') 유저가 about 페이지에서 작업 중입니다.('+ip+')')
35 res.render('about.ejs', {'ID': id, 'nickname': nickname}); 37 res.render('about.ejs', {'ID': id, 'nickname': nickname});
36 } 38 }
37 }); 39 });
......
...@@ -7,6 +7,7 @@ var mysql = require('mysql'); ...@@ -7,6 +7,7 @@ var mysql = require('mysql');
7 var path = require('path') // 상대경로 7 var path = require('path') // 상대경로
8 var mysql_odbc = require('../../db/db_board')(); 8 var mysql_odbc = require('../../db/db_board')();
9 var board = mysql_odbc.init(); 9 var board = mysql_odbc.init();
10 +var requestIp = require('request-ip');
10 11
11 // 로그용 12 // 로그용
12 var logString; 13 var logString;
...@@ -28,9 +29,10 @@ function init(){ ...@@ -28,9 +29,10 @@ function init(){
28 init() 29 init()
29 30
30 router.get('/list/:page', function(req, res, next) { 31 router.get('/list/:page', function(req, res, next) {
32 + var ip = requestIp.getClientIp(req);
31 var id = req.user; 33 var id = req.user;
32 if(!id){ 34 if(!id){
33 - console.log(logString+'익명 유저의 게시판 접근을 거부했습니다.') 35 + console.log(logString+'익명 유저의 게시판 접근을 거부했습니다.('+ip+')')
34 res.redirect('/board/list/1') 36 res.redirect('/board/list/1')
35 } 37 }
36 else{ 38 else{
...@@ -41,36 +43,39 @@ router.get('/list/:page', function(req, res, next) { ...@@ -41,36 +43,39 @@ router.get('/list/:page', function(req, res, next) {
41 if (err) console.error("err : " + err); 43 if (err) console.error("err : " + err);
42 var id = req.user.ID; 44 var id = req.user.ID;
43 var nickname = req.user.nickname; 45 var nickname = req.user.nickname;
44 - console.log(logString+req.user.ID+'('+nickname+') 유저가 게시판을 보고있습니다.') 46 + console.log(logString+req.user.ID+'('+nickname+') 유저가 게시판을 보고있습니다.('+ip+')')
45 res.render('list.ejs', {'ID':id, 'nickname': nickname, title: '게시판 리스트', rows: rows, page:page, length:rows.length-1,page_num:10,pass:true}) 47 res.render('list.ejs', {'ID':id, 'nickname': nickname, title: '게시판 리스트', rows: rows, page:page, length:rows.length-1,page_num:10,pass:true})
46 }) 48 })
47 } 49 }
48 }); 50 });
49 51
50 router.get('/list', function(req,res,next){ 52 router.get('/list', function(req,res,next){
53 + var ip = requestIp.getClientIp(req);
51 var id = req.user; 54 var id = req.user;
52 if(!id){ 55 if(!id){
53 - console.log(logString+'익명 유저의 게시판 접근을 거부했습니다.') 56 + console.log(logString+'익명 유저의 게시판 접근을 거부했습니다.('+ip+')')
54 res.sendFile(path.join(__dirname, "../../public/login.html")) 57 res.sendFile(path.join(__dirname, "../../public/login.html"))
55 } 58 }
56 else res.redirect('/board/list/1') 59 else res.redirect('/board/list/1')
57 }) 60 })
58 61
59 router.get('/write', function(req,res,next){ 62 router.get('/write', function(req,res,next){
63 + var ip = requestIp.getClientIp(req);
60 var id = req.user; 64 var id = req.user;
61 if(!id){ 65 if(!id){
62 - console.log(logString+'익명 유저의 글쓰기 시도를 거부했습니다.') 66 + console.log(logString+'익명 유저의 글쓰기 시도를 거부했습니다.('+ip+')')
63 res.sendFile(path.join(__dirname, "../../public/login.html")) 67 res.sendFile(path.join(__dirname, "../../public/login.html"))
64 } 68 }
65 else{ 69 else{
66 var id = req.user.ID; 70 var id = req.user.ID;
67 var nickname = req.user.nickname; 71 var nickname = req.user.nickname;
68 - console.log(logString+req.user.ID+'('+nickname+') 유저가 게시글 작성 중입니다.') 72 + console.log(logString+req.user.ID+'('+nickname+') 유저가 게시글 작성 중입니다.('+ip+')')
69 res.render('write.ejs', {'ID':id, 'nickname': nickname, title:"게시판 글 쓰기"}) 73 res.render('write.ejs', {'ID':id, 'nickname': nickname, title:"게시판 글 쓰기"})
70 } 74 }
71 }) 75 })
72 76
73 router.post('/write', function(req,res,next){ 77 router.post('/write', function(req,res,next){
78 + var ip = requestIp.getClientIp(req);
74 var nickname = req.user.nickname // var name = req.body.name 79 var nickname = req.user.nickname // var name = req.body.name
75 var title = req.body.title 80 var title = req.body.title
76 var content = req.body.content 81 var content = req.body.content
...@@ -91,12 +96,13 @@ router.post('/write', function(req,res,next){ ...@@ -91,12 +96,13 @@ router.post('/write', function(req,res,next){
91 if(!idx_) // 글이 없으면 NULL 96 if(!idx_) // 글이 없으면 NULL
92 idx_ = 1; 97 idx_ = 1;
93 98
94 - console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx_+'번 게시글을 작성했습니다.') 99 + console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx_+'번 게시글을 작성했습니다.('+ip+')')
95 res.redirect('/board/read/'+idx_); 100 res.redirect('/board/read/'+idx_);
96 }); 101 });
97 }) 102 })
98 103
99 router.get('/read/:idx', function(req,res,next){ 104 router.get('/read/:idx', function(req,res,next){
105 + var ip = requestIp.getClientIp(req);
100 var idx = req.params.idx 106 var idx = req.params.idx
101 var sql = "select idx, nickname, title, content, date_format(modidate,'%Y-%m-%d %H:%i:%s') modidate, " + 107 var sql = "select idx, nickname, title, content, date_format(modidate,'%Y-%m-%d %H:%i:%s') modidate, " +
102 "date_format(regdate,'%Y-%m-%d %H:%i:%s') regdate, hit, ID from board where idx=?"; 108 "date_format(regdate,'%Y-%m-%d %H:%i:%s') regdate, hit, ID from board where idx=?";
...@@ -105,7 +111,7 @@ router.get('/read/:idx', function(req,res,next){ ...@@ -105,7 +111,7 @@ router.get('/read/:idx', function(req,res,next){
105 111
106 var id = req.user; 112 var id = req.user;
107 if(!id){ 113 if(!id){
108 - console.log(logString+'익명 유저의 '+idx+'번 게시물 접근을 거부했습니다.') 114 + console.log(logString+'익명 유저의 '+idx+'번 게시물 접근을 거부했습니다.('+ip+')')
109 res.redirect('/login') 115 res.redirect('/login')
110 } 116 }
111 else{ 117 else{
...@@ -118,13 +124,14 @@ router.get('/read/:idx', function(req,res,next){ ...@@ -118,13 +124,14 @@ router.get('/read/:idx', function(req,res,next){
118 if(err) console.error(err) 124 if(err) console.error(err)
119 }) 125 })
120 126
121 - console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 보고있습니다.') 127 + console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 보고있습니다.('+ip+')')
122 res.render('read.ejs', {'ID':id, 'nickname': nickname, title:"글 상세", row:row[0]}) 128 res.render('read.ejs', {'ID':id, 'nickname': nickname, title:"글 상세", row:row[0]})
123 } 129 }
124 }) 130 })
125 }) 131 })
126 132
127 router.post('/update', function(req,res,next){ 133 router.post('/update', function(req,res,next){
134 + var ip = requestIp.getClientIp(req);
128 var ID = req.user.ID; 135 var ID = req.user.ID;
129 var idx = req.body.idx 136 var idx = req.body.idx
130 var title = req.body.title 137 var title = req.body.title
...@@ -135,19 +142,20 @@ router.post('/update', function(req,res,next){ ...@@ -135,19 +142,20 @@ router.post('/update', function(req,res,next){
135 board.query(sql,datas,function(err,result){ 142 board.query(sql,datas,function(err,result){
136 if(err) console.error(err) 143 if(err) console.error(err)
137 if(result.affectedRows==0){ 144 if(result.affectedRows==0){
138 - console.log(logString+req.user.ID+'('+nickname+') 유저의 '+idx+'번 게시글 수정을 거부했습니다.(권한없음)') 145 + console.log(logString+req.user.ID+'('+req.user.nickname+') 유저의 '+idx+'번 게시글 수정을 거부했습니다.(권한없음 // '+ip+')')
139 res.send("<script>alert('게시글 작성자가 아닙니다.');history.back();</script>") 146 res.send("<script>alert('게시글 작성자가 아닙니다.');history.back();</script>")
140 } 147 }
141 else{ 148 else{
142 var id = req.user.ID; 149 var id = req.user.ID;
143 var nickname = req.user.nickname; 150 var nickname = req.user.nickname;
144 - console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 수정했습니다.') 151 + console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 수정했습니다.('+ip+')')
145 res.redirect('/board/read/'+idx) 152 res.redirect('/board/read/'+idx)
146 } 153 }
147 }) 154 })
148 }) 155 })
149 156
150 router.post('/delete', function(req,res,next){ 157 router.post('/delete', function(req,res,next){
158 + var ip = requestIp.getClientIp(req);
151 var idx = req.body.idx 159 var idx = req.body.idx
152 var ID = req.user.ID; 160 var ID = req.user.ID;
153 var datas = [idx,ID] 161 var datas = [idx,ID]
...@@ -170,12 +178,12 @@ router.post('/delete', function(req,res,next){ ...@@ -170,12 +178,12 @@ router.post('/delete', function(req,res,next){
170 178
171 var nickname = req.user.nickname; 179 var nickname = req.user.nickname;
172 res.send("<script>alert('게시글이 운영자에 의해 삭제되었습니다.');window.location.href='/board/list/';</script>"); 180 res.send("<script>alert('게시글이 운영자에 의해 삭제되었습니다.');window.location.href='/board/list/';</script>");
173 - console.log(logString+"[Admin] "+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 삭제했습니다.') 181 + console.log(logString+"[Admin] "+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 삭제했습니다.('+ip+')')
174 }) 182 })
175 } 183 }
176 else{ // 작성자도, 운영자도 아니면 184 else{ // 작성자도, 운영자도 아니면
177 var nickname = req.user.nickname; 185 var nickname = req.user.nickname;
178 - console.log(logString+req.user.ID+'('+nickname+') 유저의 '+idx+'번 게시글 삭제를 거부했습니다.(권한없음)') 186 + console.log(logString+req.user.ID+'('+nickname+') 유저의 '+idx+'번 게시글 삭제를 거부했습니다.(권한없음 // '+ip+')')
179 res.send("<script>alert('게시글 작성자가 아닙니다');history.back();</script>"); 187 res.send("<script>alert('게시글 작성자가 아닙니다');history.back();</script>");
180 } 188 }
181 }) 189 })
...@@ -184,7 +192,7 @@ router.post('/delete', function(req,res,next){ ...@@ -184,7 +192,7 @@ router.post('/delete', function(req,res,next){
184 var id = req.user.ID; 192 var id = req.user.ID;
185 var nickname = req.user.nickname; 193 var nickname = req.user.nickname;
186 res.send("<script>alert('게시글이 삭제되었습니다.');window.location.href='/board/list/';</script>"); 194 res.send("<script>alert('게시글이 삭제되었습니다.');window.location.href='/board/list/';</script>");
187 - console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 삭제했습니다.') 195 + console.log(logString+req.user.ID+'('+nickname+') 유저가 '+idx+'번 게시글을 삭제했습니다.('+ip+')')
188 } 196 }
189 }) 197 })
190 }) 198 })
......
...@@ -4,6 +4,7 @@ var router = express.Router(); ...@@ -4,6 +4,7 @@ var router = express.Router();
4 var path = require('path') // 상대경로 4 var path = require('path') // 상대경로
5 var mysql_odbc = require('../../db/db_board')(); 5 var mysql_odbc = require('../../db/db_board')();
6 var myinfo = mysql_odbc.init(); 6 var myinfo = mysql_odbc.init();
7 +var requestIp = require('request-ip');
7 8
8 // 로그용 9 // 로그용
9 var logString; 10 var logString;
...@@ -25,14 +26,15 @@ function init(){ ...@@ -25,14 +26,15 @@ function init(){
25 init() 26 init()
26 27
27 router.get('/', function(req, res){ 28 router.get('/', function(req, res){
29 + var ip = requestIp.getClientIp(req);
28 var id = req.user; 30 var id = req.user;
29 if(!id){ 31 if(!id){
30 - console.log(logString+'익명 유저의 채팅 접근을 거부했습니다.') 32 + console.log(logString+'익명 유저의 채팅 접근을 거부했습니다.('+ip+')')
31 res.sendFile(path.join(__dirname, "../../public/login.html")) 33 res.sendFile(path.join(__dirname, "../../public/login.html"))
32 } 34 }
33 if(id){ 35 if(id){
34 var nickname = req.user.nickname 36 var nickname = req.user.nickname
35 - console.log(logString+req.user.ID+'('+nickname+') 유저가 채팅 중입니다.') 37 + console.log(logString+req.user.ID+'('+nickname+') 유저가 채팅 중입니다.('+ip+')')
36 res.render('chat.ejs', {'nickname':nickname}) 38 res.render('chat.ejs', {'nickname':nickname})
37 } 39 }
38 }); 40 });
......
...@@ -2,6 +2,7 @@ var express = require('express') ...@@ -2,6 +2,7 @@ var express = require('express')
2 var app = express() 2 var app = express()
3 var router = express.Router(); 3 var router = express.Router();
4 var path = require('path') 4 var path = require('path')
5 +var requestIp = require('request-ip');
5 6
6 var main = require('./main/main') 7 var main = require('./main/main')
7 var register = require('./register/index') 8 var register = require('./register/index')
...@@ -12,10 +13,39 @@ var profile = require('./profile/index') ...@@ -12,10 +13,39 @@ var profile = require('./profile/index')
12 var about = require('./about/index') 13 var about = require('./about/index')
13 var chat = require('./chat/chat') 14 var chat = require('./chat/chat')
14 15
16 +// 로그용
17 +var logString;
18 +function getTime(){
19 + var today = new Date();
20 + var year = today.getFullYear();
21 + var month = ('0' + (today.getMonth()+1)).slice(-2);
22 + var day = ('0' + today.getDate()).slice(-2);
23 + var hour = ('0' + today.getHours()).slice(-2);
24 + var minute = ('0' + today.getMinutes()).slice(-2);
25 + var second = ('0' + today.getSeconds()).slice(-2);
26 + logString = '['+year+'-'+month+'-'+day+' '+hour+':'+minute+':'+second+'] ';
27 +}
28 +// 시간 갱신용
29 +function init(){
30 + getTime();
31 + setInterval(getTime, 1000)
32 +}
33 +init()
34 +
15 // URL routing 35 // URL routing
16 // req = request, res = respond 36 // req = request, res = respond
17 router.get('/', function(req, res){ 37 router.get('/', function(req, res){
18 - res.sendFile(path.join(__dirname, "../public/main.html")); 38 + var ip = requestIp.getClientIp(req);
39 + var id = req.user;
40 + if(!id){
41 + console.log(logString+'익명의 유저가 작업 중입니다.('+ip+')')
42 + res.sendFile(path.join(__dirname, "../public/main.html"))
43 + }
44 + if(id){
45 + var nickname = req.user.nickname;
46 + console.log(logString+req.user.ID+'('+nickname+') 유저가 작업 중입니다.('+ip+')')
47 + res.render('main.ejs', {'ID': id, 'nickname': nickname});
48 + }
19 }); 49 });
20 50
21 // router 정의 51 // router 정의
......
...@@ -5,6 +5,7 @@ var path = require('path') // 상대경로 ...@@ -5,6 +5,7 @@ var path = require('path') // 상대경로
5 var mysql = require('mysql') 5 var mysql = require('mysql')
6 var passport = require('passport') 6 var passport = require('passport')
7 var LocalStrategy = require('passport-local').Strategy 7 var LocalStrategy = require('passport-local').Strategy
8 +var requestIp = require('request-ip');
8 9
9 // 로그용 10 // 로그용
10 var logString; 11 var logString;
...@@ -39,7 +40,8 @@ router.get('/', function(req, res){ ...@@ -39,7 +40,8 @@ router.get('/', function(req, res){
39 var msg; 40 var msg;
40 var errMsg = req.flash('error') 41 var errMsg = req.flash('error')
41 if(errMsg) msg = errMsg; 42 if(errMsg) msg = errMsg;
42 - console.log(logString+'익명의 유저가 로그인 중입니다.') 43 + var ip = requestIp.getClientIp(req);
44 + console.log(logString+'익명의 유저가 로그인 중입니다.('+ip+')')
43 res.render('login.ejs', {'message' : msg}); 45 res.render('login.ejs', {'message' : msg});
44 }) 46 })
45 47
...@@ -62,18 +64,19 @@ passport.use('local-login', new LocalStrategy({ ...@@ -62,18 +64,19 @@ passport.use('local-login', new LocalStrategy({
62 var query = connection.query('select * from userDB where ID=?', [ID], function(err, rows){ 64 var query = connection.query('select * from userDB where ID=?', [ID], function(err, rows){
63 if(err) return done(err); 65 if(err) return done(err);
64 66
67 + var ip = requestIp.getClientIp(req);
65 if(rows.length){ // database에 입력한 ID값이 있는가? 68 if(rows.length){ // database에 입력한 ID값이 있는가?
66 if(password == rows[0].password){ // 비밀번호와 확인이 같은가? 69 if(password == rows[0].password){ // 비밀번호와 확인이 같은가?
67 - console.log(logString+"로그인 알림: "+ ID +"(" + rows[0].nickname + ")") 70 + console.log(logString+"로그인 알림: "+ ID +"(" + rows[0].nickname +" // "+ip+')')
68 return done(null, {'ID' : ID, 'nickname' : rows[0].nickname}); 71 return done(null, {'ID' : ID, 'nickname' : rows[0].nickname});
69 } 72 }
70 else{ 73 else{
71 - console.log(logString+"로그인 알림: 잘못된 비밀번호입니다.(시도된 아이디: "+ID+")") 74 + console.log(logString+"로그인 알림: 잘못된 비밀번호입니다.(시도된 아이디: "+ID+" // "+ip+')')
72 return done(null, false, {message : '잘못된 비밀번호입니다.'}) 75 return done(null, false, {message : '잘못된 비밀번호입니다.'})
73 } 76 }
74 } 77 }
75 else{ 78 else{
76 - console.log(logString+"로그인 알림: ID를 찾을 수 없습니다.(시도된 아이디: "+ID+")") 79 + console.log(logString+"로그인 알림: ID를 찾을 수 없습니다.(시도된 아이디: "+ID+" // "+ip+')')
77 return done(null, false, {message : 'ID를 찾을 수 없습니다.'}) 80 return done(null, false, {message : 'ID를 찾을 수 없습니다.'})
78 } 81 }
79 }) 82 })
......
...@@ -2,6 +2,7 @@ var express = require('express') ...@@ -2,6 +2,7 @@ var express = require('express')
2 var app = express() 2 var app = express()
3 var router = express.Router(); 3 var router = express.Router();
4 var path = require('path') 4 var path = require('path')
5 +var requestIp = require('request-ip');
5 6
6 // 로그용 7 // 로그용
7 var logString; 8 var logString;
...@@ -23,13 +24,14 @@ function init(){ ...@@ -23,13 +24,14 @@ function init(){
23 init() 24 init()
24 25
25 router.get('/', function(req, res){ 26 router.get('/', function(req, res){
27 + var ip = requestIp.getClientIp(req);
26 var id = req.user; 28 var id = req.user;
27 if(!id){ 29 if(!id){
28 - console.log(logString+"익명 유저의 로그아웃 시도를 거부했습니다.") 30 + console.log(logString+"익명 유저의 로그아웃 시도를 거부했습니다.("+ip+')')
29 res.redirect('/main') 31 res.redirect('/main')
30 } 32 }
31 else{ 33 else{
32 - console.log(logString+req.user.ID+"("+req.user.nickname+") 유저가 로그아웃합니다.") 34 + console.log(logString+req.user.ID+"("+req.user.nickname+") 유저가 로그아웃합니다.("+ip+')')
33 req.logout(); 35 req.logout();
34 req.session.save(function(){ 36 req.session.save(function(){
35 res.redirect('/'); 37 res.redirect('/');
......
...@@ -2,6 +2,7 @@ var express = require('express') ...@@ -2,6 +2,7 @@ var express = require('express')
2 var app = express() 2 var app = express()
3 var router = express.Router(); 3 var router = express.Router();
4 var path = require('path') // 상대경로 4 var path = require('path') // 상대경로
5 +var requestIp = require('request-ip');
5 6
6 // 로그용 7 // 로그용
7 var logString; 8 var logString;
...@@ -24,14 +25,15 @@ init() ...@@ -24,14 +25,15 @@ init()
24 25
25 // main page는 login이 된 상태(세션정보가 있을때만) 접근이 가능하게 하자 -> info에 구현해놓음. 26 // main page는 login이 된 상태(세션정보가 있을때만) 접근이 가능하게 하자 -> info에 구현해놓음.
26 router.get('/', function(req, res){ 27 router.get('/', function(req, res){
28 + var ip = requestIp.getClientIp(req);
27 var id = req.user; 29 var id = req.user;
28 if(!id){ 30 if(!id){
29 - console.log(logString+'익명의 유저가 작업 중입니다.') 31 + console.log(logString+'익명의 유저가 작업 중입니다.('+ip+')')
30 res.sendFile(path.join(__dirname, "../../public/main.html")) 32 res.sendFile(path.join(__dirname, "../../public/main.html"))
31 } 33 }
32 if(id){ 34 if(id){
33 var nickname = req.user.nickname; 35 var nickname = req.user.nickname;
34 - console.log(logString+req.user.ID+'('+nickname+') 유저가 작업 중입니다.') 36 + console.log(logString+req.user.ID+'('+nickname+') 유저가 작업 중입니다.('+ip+')')
35 res.render('main.ejs', {'ID': id, 'nickname': nickname}); 37 res.render('main.ejs', {'ID': id, 'nickname': nickname});
36 } 38 }
37 }); 39 });
......
...@@ -6,6 +6,7 @@ var mysql_odbc = require('../../db/db_board')(); ...@@ -6,6 +6,7 @@ var mysql_odbc = require('../../db/db_board')();
6 var myinfo = mysql_odbc.init(); 6 var myinfo = mysql_odbc.init();
7 var passport = require('passport') 7 var passport = require('passport')
8 var LocalStrategy = require('passport-local').Strategy 8 var LocalStrategy = require('passport-local').Strategy
9 +var requestIp = require('request-ip');
9 10
10 // 로그용 11 // 로그용
11 var logString; 12 var logString;
...@@ -39,6 +40,7 @@ passport.deserializeUser(function(user, done){ ...@@ -39,6 +40,7 @@ passport.deserializeUser(function(user, done){
39 40
40 // main page는 login이 된 상태(세션정보가 있을때만) 접근이 가능하게 하자 -> info에 구현해놓음. 41 // main page는 login이 된 상태(세션정보가 있을때만) 접근이 가능하게 하자 -> info에 구현해놓음.
41 router.get('/', function(req, res){ 42 router.get('/', function(req, res){
43 + var ip = requestIp.getClientIp(req);
42 try{ 44 try{
43 var id = req.session.passport.user.ID; 45 var id = req.session.passport.user.ID;
44 // if(!id){ 46 // if(!id){
...@@ -53,18 +55,19 @@ router.get('/', function(req, res){ ...@@ -53,18 +55,19 @@ router.get('/', function(req, res){
53 var nickname = req.user.nickname; 55 var nickname = req.user.nickname;
54 var type = rows[0].type; 56 var type = rows[0].type;
55 var profilemsg = rows[0].profilemsg; 57 var profilemsg = rows[0].profilemsg;
56 - console.log(logString+req.user.ID+'('+nickname+') 유저가 프로필을 보고있습니다.') 58 + console.log(logString+req.user.ID+'('+nickname+') 유저가 프로필을 보고있습니다.('+ip+')')
57 res.render('profile.ejs', {'ID':id, 'nickname': nickname, 'type': type, 'profilemsg': profilemsg}) 59 res.render('profile.ejs', {'ID':id, 'nickname': nickname, 'type': type, 'profilemsg': profilemsg})
58 }) 60 })
59 } 61 }
60 catch{ 62 catch{
61 - console.log(logString+'익명 유저의 프로필 접근 시도를 거부했습니다.') 63 + console.log(logString+'익명 유저의 프로필 접근 시도를 거부했습니다.('+ip+')')
62 res.sendFile(path.join(__dirname, "../../public/login.html")) 64 res.sendFile(path.join(__dirname, "../../public/login.html"))
63 } 65 }
64 66
65 }); 67 });
66 68
67 router.get('/update', function(req,res){ 69 router.get('/update', function(req,res){
70 + var ip = requestIp.getClientIp(req);
68 try{ 71 try{
69 var id = req.user.ID; 72 var id = req.user.ID;
70 // if(!id){ 73 // if(!id){
...@@ -80,19 +83,20 @@ router.get('/update', function(req,res){ ...@@ -80,19 +83,20 @@ router.get('/update', function(req,res){
80 var nickname = req.user.nickname; 83 var nickname = req.user.nickname;
81 var type = req.user.type; 84 var type = req.user.type;
82 var profilemsg = rows[0].profilemsg; 85 var profilemsg = rows[0].profilemsg;
83 - console.log(logString+req.user.ID+'('+nickname+') 유저가 프로필 수정 중입니다.') 86 + console.log(logString+req.user.ID+'('+nickname+') 유저가 프로필 수정 중입니다.('+ip+')')
84 res.render('profmsgedit.ejs', {'ID':id, 'nickname': nickname, 'type':type, 'profilemsg': profilemsg, 'message':''}); 87 res.render('profmsgedit.ejs', {'ID':id, 'nickname': nickname, 'type':type, 'profilemsg': profilemsg, 'message':''});
85 }) 88 })
86 } 89 }
87 catch{ 90 catch{
88 if(!id){ 91 if(!id){
89 - console.log(logString+'익명 유저의 프로필 수정 시도를 거부했습니다.') 92 + console.log(logString+'익명 유저의 프로필 수정 시도를 거부했습니다.('+ip+')')
90 res.sendFile(path.join(__dirname, "../../public/login.html")) 93 res.sendFile(path.join(__dirname, "../../public/login.html"))
91 } 94 }
92 } 95 }
93 }) 96 })
94 97
95 router.post('/update', function(req,res,next){ 98 router.post('/update', function(req,res,next){
99 + var ip = requestIp.getClientIp(req);
96 var id = req.user.ID; 100 var id = req.user.ID;
97 var profilemsg = req.body.profilemsg; 101 var profilemsg = req.body.profilemsg;
98 var nickname = req.body.nickname; 102 var nickname = req.body.nickname;
...@@ -127,7 +131,7 @@ router.post('/update', function(req,res,next){ ...@@ -127,7 +131,7 @@ router.post('/update', function(req,res,next){
127 myinfo.query(sql,datas,function(err,result){ 131 myinfo.query(sql,datas,function(err,result){
128 if(err) console.error(err) 132 if(err) console.error(err)
129 133
130 - console.log(logString+req.user.ID+'('+req.session.passport.user.nickname+') 유저가 프로필을 수정했습니다.') 134 + console.log(logString+req.user.ID+'('+req.session.passport.user.nickname+') 유저가 프로필을 수정했습니다.('+ip+')')
131 console.log(" ▷ 변경전: "+id+"("+req.user.nickname+") "+oldType+" // "+oldProfilemsg) 135 console.log(" ▷ 변경전: "+id+"("+req.user.nickname+") "+oldType+" // "+oldProfilemsg)
132 req.session.passport.user.nickname = nickname; 136 req.session.passport.user.nickname = nickname;
133 console.log(" ▶ 변경후: "+id+"("+nickname+") "+type+" // "+profilemsg) 137 console.log(" ▶ 변경후: "+id+"("+nickname+") "+type+" // "+profilemsg)
...@@ -135,7 +139,7 @@ router.post('/update', function(req,res,next){ ...@@ -135,7 +139,7 @@ router.post('/update', function(req,res,next){
135 }) 139 })
136 } 140 }
137 else{ // 다른 유저의 닉네임과 중복되는 경우 141 else{ // 다른 유저의 닉네임과 중복되는 경우
138 - console.log(logString+id+" 유저가 중복된 닉네임으로 변경을 시도했습니다.(시도한 닉네임: "+req.body.nickname+")") 142 + console.log(logString+id+" 유저가 중복된 닉네임으로 변경을 시도했습니다.(시도한 닉네임: "+req.body.nickname+" // ("+ip+')')
139 res.render('profmsgedit.ejs', {nickname: req.session.passport.user.nickname, profilemsg: oldProfilemsg, message : '중복된 닉네임입니다.'}) 143 res.render('profmsgedit.ejs', {nickname: req.session.passport.user.nickname, profilemsg: oldProfilemsg, message : '중복된 닉네임입니다.'})
140 } 144 }
141 }) 145 })
......
...@@ -5,6 +5,7 @@ var path = require('path') // 상대경로 ...@@ -5,6 +5,7 @@ var path = require('path') // 상대경로
5 var mysql = require('mysql') 5 var mysql = require('mysql')
6 var passport = require('passport') 6 var passport = require('passport')
7 var LocalStrategy = require('passport-local').Strategy 7 var LocalStrategy = require('passport-local').Strategy
8 +var requestIp = require('request-ip');
8 9
9 // 로그용 10 // 로그용
10 var logString; 11 var logString;
...@@ -39,7 +40,8 @@ router.get('/', function(req, res){ ...@@ -39,7 +40,8 @@ router.get('/', function(req, res){
39 var msg; 40 var msg;
40 var errMsg = req.flash('error') 41 var errMsg = req.flash('error')
41 if(errMsg) msg = errMsg; 42 if(errMsg) msg = errMsg;
42 - console.log(logString+'익명의 유저가 회원가입 중입니다.') 43 + var ip = requestIp.getClientIp(req);
44 + console.log(logString+'익명의 유저가 회원가입 중입니다.('+ip+')')
43 res.render('register.ejs', {'message' : msg}); 45 res.render('register.ejs', {'message' : msg});
44 }) 46 })
45 47
...@@ -63,29 +65,30 @@ passport.use('local-join', new LocalStrategy({ ...@@ -63,29 +65,30 @@ passport.use('local-join', new LocalStrategy({
63 passReqToCallback: true 65 passReqToCallback: true
64 }, function(req, ID, password, done){ 66 }, function(req, ID, password, done){
65 var query = connection.query('select * from userDB where ID=?', [ID], function(err, rows){ 67 var query = connection.query('select * from userDB where ID=?', [ID], function(err, rows){
66 - if(err) return done(err); 68 + var ip = requestIp.getClientIp(req);
69 + if(err) return done(err);
67 70
68 if(rows.length){ // database에 입력한 ID값이 있는가? 71 if(rows.length){ // database에 입력한 ID값이 있는가?
69 - console.log(logString+"회원가입 알림: 중복된 ID입니다.("+ID+")") 72 + console.log(logString+"회원가입 알림: 중복된 ID입니다.("+ID+" // "+ip+')')
70 return done(null, false, {message : '중복된 ID입니다.'}) 73 return done(null, false, {message : '중복된 ID입니다.'})
71 } 74 }
72 else{ 75 else{
73 if(password != req.body.pw_com){ // 비밀번호와 확인이 같지 않은가? 76 if(password != req.body.pw_com){ // 비밀번호와 확인이 같지 않은가?
74 - console.log(logString+"회원가입 알림: 비밀번호가 일치하지 않습니다.(시도 중인 아이디: "+ID+")") 77 + console.log(logString+"회원가입 알림: 비밀번호가 일치하지 않습니다.(시도 중인 아이디: "+ID+" // "+ip+')')
75 return done(null, false, {message : '비밀번호가 일치하지 않습니다.'}) 78 return done(null, false, {message : '비밀번호가 일치하지 않습니다.'})
76 } 79 }
77 else{ 80 else{
78 var subqry = connection.query('select * from userDB where nickname=?', [req.body.nickname], function(err, rows_){ 81 var subqry = connection.query('select * from userDB where nickname=?', [req.body.nickname], function(err, rows_){
79 if(err) return done(err); 82 if(err) return done(err);
80 if(rows_.length){ 83 if(rows_.length){
81 - console.log(logString+"회원가입 알림: 중복된 닉네임입니다.("+req.body.nickname+")") 84 + console.log(logString+"회원가입 알림: 중복된 닉네임입니다.("+req.body.nickname+" // "+ip+')')
82 return done(null, false, {message : '중복된 닉네임입니다.'}) 85 return done(null, false, {message : '중복된 닉네임입니다.'})
83 } 86 }
84 else{ 87 else{
85 var sql = {ID: ID, password: password, type:req.body.type, nickname:req.body.nickname}; 88 var sql = {ID: ID, password: password, type:req.body.type, nickname:req.body.nickname};
86 var query = connection.query('insert into userDB set ?', sql, function(err, rows){ 89 var query = connection.query('insert into userDB set ?', sql, function(err, rows){
87 if(err) throw err 90 if(err) throw err
88 - console.log(logString+"회원가입 알림: 사용자가 추가되었습니다.(" + ID +", " + req.body.nickname + ")") 91 + console.log(logString+"회원가입 알림: 사용자가 추가되었습니다.(" + ID +", " + req.body.nickname + " // "+ip+')')
89 return done(null, {'ID' : ID, 'nickname' : req.body.nickname}); 92 return done(null, {'ID' : ID, 'nickname' : req.body.nickname});
90 }) 93 })
91 } 94 }
......