there are no rules yet, since they are strictly limited by the system, build premises, arrange, bring friends, earn money. but to fake, break, or cheat is an exception. respect the authorship.
if [ ! -f not_file ]; then
# begin not(!) yes
else
# begin not no
fi
info@namapi.org
info@kivie.in
info@plantas.vip
01. Форум
02. Биллинг. ключь
03. InstantMaps. key
04. SmartChat. платная
05. NeoMessenger.
06. Рубрикатор. платная
07. onliner(импорт товаров). платная
08. ЧатБро.
09. Плавающее меню действий.
10. «Информация из биллинга» v1.0.2
11. Виджет Меню 2 v1.0.1
12. шаблон мобильного меню
13. Виджет статистики контента пользователя v1.0.0
14. Интеграция редактора Quill
15. CKEditor 4.12.1
16. neomessenger premium. платная
17. json-api.
18. bb smile (code)
19. fieldslider
20. Виджет Бегущая строка v1.0.1z
21. Карта сайта. платная
22. Менеджер подписок на Комментарии v1.0.1
23. Пинг сервисов обновления
24. Черный список v1.2.1
25. Витрина товаров v1.2.10
26. Живой поиск ajax v2.0.1
27. Список контента AJAX v1.0.2. платная
28. Импорт-Экспорт конфигураций v2.0.6
30. Языки 2.0.2. платная
33. Контент в Ajax окне v1.0.1
34. ГудГалерея. куплен
35. list_category_featured
36. list_tiles_featured_template
37. PayPal3
38. История просмотров v1.0.1. платная
39. Логирование авторизаций v2.0.0
40. uLogin - регистрация/авторизация через соцсети v2.0.13
41. Фотоконкурс v1.0.2
42. Избранное v2.0.2
43. Изображение из категории v1.0.0
44. Платежная система PayPal для компонента Билинг v1.0.0
46. Калькулятор v1.0.0
47. Виджет Стена профиля, группы v1.0.0
48. Парсер новостей v1.9.7
49. Умная стена v1.1.0. платная
50. Виджет Записи со стен v1.0.3. платная
51. Виджет - список групп(и ролей) пользователей v1.0.1
52. Timeline post v1.0.0
53. Форма заявки на конкурс v1.1.0
54. Логирование действий пользователя v1.1.0
56. Компонент 'Гостевая книга' v1.6.0
57. Файл сканнер v1.0.0
58. Расширение для биллинга v1.0.0
59. История просмотров v1.0.1
60. Рейтинг "Лайк"
61. Календарь событий. v1.1.0(моменты)
62. Поле телефон с смс подтверждением v1.2.0
63. Мастер виджетов. платная
64. Мигратор виджетов v1.0.2
66. *Редактор компонента v1.0.3
67. Последнее видео youtube v1.0.2
68. Поле видео файл [goodmade] v1.0.0
69. Виджет Медиа объекты [GoodMade] v1.1.1
70. -Колесо фортуны PRO v1.0.7
71. Цвет + v1.0.0. платная
72. Виджет Фильтр+ v1.0.3
73. Плавающие меню действий(modern) v1.0.0
74. Плавающее меню действий v1.0.0
75. Плитка контента v1.0.0
76. Шапка контента
77. *Виджет Шапка записей v1.0.1
78. Поле Код v1.0.0
79. поле HTML текст с нужными полями внутри
80. +fieldlinks
81. Поле Список - альтернативное
82. Компонент Мастер комментариев v1.0.2
83. Contentus - 14 стилей для вывода контента
интересуйтесь
| vds - kvm (unix / linux)
KVM - 5 $/мес
- 1 ядро
- Лимит доп. IP-адресов - 16 адресов
- 1 Гб Оперативная память
- 100Mb/s Скорость канала
- 30 Гб SAS
KVM - 10 $/мес
- 2 ядра
- Лимит доп. IP-адресов - 64 адресов
- 2 Гб Оперативная память
- 100Mb/s Скорость канала
- 60 Гб SAS
KVM - 15 $/мес
- 3 ядра
- Лимит доп. IP-адресов - 128 адресов
- 3 Гб Оперативная память
- 100Mb/s Скорость канала
- 90 Гб SAS
KVM - 31 $/мес
- 6 ядер
- Лимит доп. IP-адресов - 255 адресов
- 6 Гб Оперативная память
- 100Mb/s Скорость канала
- 180 Гб SAS
сервера москвы, украины, голландии, германии
Some Mathematical Symbols Supported by HTML
Char | Number | Entity | Description |
---|---|---|---|
∀ | ∀ | ∀ | FOR ALL |
∂ | ∂ | ∂ | PARTIAL DIFFERENTIAL |
∃ | ∃ | ∃ | THERE EXISTS |
∅ | ∅ | ∅ | EMPTY SETS |
∇ | ∇ | ∇ | NABLA |
∈ | ∈ | ∈ | ELEMENT OF |
∉ | ∉ | ∉ | NOT AN ELEMENT OF |
∋ | ∋ | ∋ | CONTAINS AS MEMBER |
∏ | ∏ | ∏ | N-ARY PRODUCT |
∑ | ∑ | ∑ | N-ARY SUMMATION |
Older browsers may not support all the HTML5 entities in the table below.
Chrome and Opera have good support, and IE 11+ and Firefox 35+ support all the entities.
Char | Dec | Hex | Entity | Name |
---|---|---|---|---|
← | 8592 | 2190 | ← | LEFTWARDS ARROW |
↑ | 8593 | 2191 | ↑ | UPWARDS ARROW |
→ | 8594 | 2192 | → | RIGHTWARDS ARROW |
↓ | 8595 | 2193 | ↓ | DOWNWARDS ARROW |
↔ | 8596 | 2194 | ↔ | LEFT RIGHT ARROW |
↕ | 8597 | 2195 | UP DOWN ARROW | |
↖ | 8598 | 2196 | NORTH WEST ARROW | |
↗ | 8599 | 2197 | NORTH EAST ARROW | |
↘ | 8600 | 2198 | SOUTH EAST ARROW | |
↙ | 8601 | 2199 | SOUTH WEST ARROW | |
↚ | 8602 | 219A | LEFTWARDS ARROW WITH STROKE | |
↛ | 8603 | 219B | RIGHTWARDS ARROW WITH STROKE | |
↜ | 8604 | 219C | LEFTWARDS WAVE ARROW | |
↝ | 8605 | 219D | RIGHTWARDS WAVE ARROW | |
↞ | 8606 | 219E | LEFTWARDS TWO HEADED ARROW | |
↟ | 8607 | 219F | UPWARDS TWO HEADED ARROW | |
↠ | 8608 | 21A0 | RIGHTWARDS TWO HEADED ARROW | |
↡ | 8609 | 21A1 | DOWNWARDS TWO HEADED ARROW | |
↢ | 8610 | 21A2 | LEFTWARDS ARROW WITH TAIL | |
↣ | 8611 | 21A3 | RIGHTWARDS ARROW WITH TAIL | |
↤ | 8612 | 21A4 | LEFTWARDS ARROW FROM BAR | |
↥ | 8613 | 21A5 | UPWARDS ARROW FROM BAR | |
↦ | 8614 | 21A6 | RIGHTWARDS ARROW FROM BAR | |
↧ | 8615 | 21A7 | DOWNWARDS ARROW FROM BAR | |
↨ | 8616 | 21A8 | UP DOWN ARROW WITH BASE | |
↩ | 8617 | 21A9 | LEFTWARDS ARROW WITH HOOK | |
↪ | 8618 | 21AA | RIGHTWARDS ARROW WITH HOOK | |
↫ | 8619 | 21AB | LEFTWARDS ARROW WITH LOOP | |
↬ | 8620 | 21AC | RIGHTWARDS ARROW WITH LOOP | |
↭ | 8621 | 21AD | LEFT RIGHT WAVE ARROW | |
↮ | 8622 | 21AE | LEFT RIGHT ARROW WITH STROKE | |
↯ | 8623 | 21AF | DOWNWARDS ZIGZAG ARROW | |
↰ | 8624 | 21B0 | UPWARDS ARROW WITH TIP LEFTWARDS | |
↱ | 8625 | 21B1 | UPWARDS ARROW WITH TIP RIGHTWARDS | |
↲ | 8626 | 21B2 | DOWNWARDS ARROW WITH TIP LEFTWARDS | |
↳ | 8627 | 21B3 | DOWNWARDS ARROW WITH TIP RIGHTWARDS | |
↴ | 8628 | 21B4 | RIGHTWARDS ARROW WITH CORNER DOWNWARDS | |
↵ | 8629 | 21B5 | ↵ | DOWNWARDS ARROW WITH CORNER LEFTWARDS |
↶ | 8630 | 21B6 | ANTICLOCKWISE TOP SEMICIRCLE ARROW | |
↷ | 8631 | 21B7 | CLOCKWISE TOP SEMICIRCLE ARROW | |
↸ | 8632 | 21B8 | NORTH WEST ARROW TO LONG BAR | |
↹ | 8633 | 21B9 | LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR | |
↺ | 8634 | 21BA | ANTICLOCKWISE OPEN CIRCLE ARROW | |
↻ | 8635 | 21BB | CLOCKWISE OPEN CIRCLE ARROW | |
↼ | 8636 | 21BC | LEFTWARDS HARPOON WITH BARB UPWARDS | |
↽ | 8637 | 21BD | LEFTWARDS HARPOON WITH BARB DOWNWARDS | |
↾ | 8638 | 21BE | UPWARDS HARPOON WITH BARB RIGHTWARDS | |
↿ | 8639 | 21BF | UPWARDS HARPOON WITH BARB LEFTWARDS | |
⇀ | 8640 | 21C0 | RIGHTWARDS HARPOON WITH BARB UPWARDS | |
⇁ | 8641 | 21C1 | RIGHTWARDS HARPOON WITH BARB DOWNWARDS | |
⇂ | 8642 | 21C2 | DOWNWARDS HARPOON WITH BARB RIGHTWARDS | |
⇃ | 8643 | 21C3 | DOWNWARDS HARPOON WITH BARB LEFTWARDS | |
⇄ | 8644 | 21C4 | RIGHTWARDS ARROW OVER LEFTWARDS ARROW | |
⇅ | 8645 | 21C5 | UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW | |
⇆ | 8646 | 21C6 | LEFTWARDS ARROW OVER RIGHTWARDS ARROW | |
⇇ | 8647 | 21C7 | LEFTWARDS PAIRED ARROWS | |
⇈ | 8648 | 21C8 | UPWARDS PAIRED ARROWS | |
⇉ | 8649 | 21C9 | RIGHTWARDS PAIRED ARROWS | |
⇊ | 8650 | 21CA | DOWNWARDS PAIRED ARROWS | |
⇋ | 8651 | 21CB | LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON | |
⇌ | 8652 | 21CC | RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON | |
⇍ | 8653 | 21CD | LEFTWARDS DOUBLE ARROW WITH STROKE | |
⇎ | 8654 | 21CE | LEFT RIGHT DOUBLE ARROW WITH STROKE | |
⇏ | 8655 | 21CF | RIGHTWARDS DOUBLE ARROW WITH STROKE | |
⇐ | 8656 | 21D0 | ⇐ | LEFTWARDS DOUBLE ARROW |
⇑ | 8657 | 21D1 | ⇑ | UPWARDS DOUBLE ARROW |
⇒ | 8658 | 21D2 | ⇒ | RIGHTWARDS DOUBLE ARROW |
⇓ | 8659 | 21D3 | ⇓ | DOWNWARDS DOUBLE ARROW |
⇔ | 8660 | 21D4 | ⇔ | LEFT RIGHT DOUBLE ARROW |
⇕ | 8661 | 21D5 | UP DOWN DOUBLE ARROW | |
⇖ | 8662 | 21D6 | NORTH WEST DOUBLE ARROW | |
⇗ | 8663 | 21D7 | NORTH EAST DOUBLE ARROW | |
⇘ | 8664 | 21D8 | SOUTH EAST DOUBLE ARROW | |
⇙ | 8665 | 21D9 | SOUTH WEST DOUBLE ARROW | |
⇚ | 8666 | 21DA | LEFTWARDS TRIPLE ARROW | |
⇛ | 8667 | 21DB | RIGHTWARDS TRIPLE ARROW | |
⇜ | 8668 | 21DC | LEFTWARDS SQUIGGLE ARROW | |
⇝ | 8669 | 21DD | RIGHTWARDS SQUIGGLE ARROW | |
⇞ | 8670 | 21DE | UPWARDS ARROW WITH DOUBLE STROKE | |
⇟ | 8671 | 21DF | DOWNWARDS ARROW WITH DOUBLE STROKE | |
⇠ | 8672 | 21E0 | LEFTWARDS DASHED ARROW | |
⇡ | 8673 | 21E1 | UPWARDS DASHED ARROW | |
⇢ | 8674 | 21E2 | RIGHTWARDS DASHED ARROW | |
⇣ | 8675 | 21E3 | DOWNWARDS DASHED ARROW | |
⇤ | 8676 | 21E4 | LEFTWARDS ARROW TO BAR | |
⇥ | 8677 | 21E5 | RIGHTWARDS ARROW TO BAR | |
⇦ | 8678 | 21E6 | LEFTWARDS WHITE ARROW | |
⇧ | 8679 | 21E7 | UPWARDS WHITE ARROW | |
⇨ | 8680 | 21E8 | RIGHTWARDS WHITE ARROW | |
⇩ | 8681 | 21E9 | DOWNWARDS WHITE ARROW | |
⇪ | 8682 | 21EA | UPWARDS WHITE ARROW FROM BAR | |
⇫ | 8683 | 21EB | UPWARDS WHITE ARROW ON PEDESTAL | |
⇬ | 8684 | 21EC | UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR | |
⇭ | 8685 | 21ED | UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR | |
⇮ | 8686 | 21EE | UPWARDS WHITE DOUBLE ARROW | |
⇯ | 8687 | 21EF | UPWARDS WHITE DOUBLE ARROW ON PEDESTAL | |
⇰ | 8688 | 21F0 | RIGHTWARDS WHITE ARROW FROM WALL | |
⇱ | 8689 | 21F1 | NORTH WEST ARROW TO CORNER | |
⇲ | 8690 | 21F2 | SOUTH EAST ARROW TO CORNER | |
⇳ | 8691 | 21F3 | UP DOWN WHITE ARROW | |
⇴ | 8692 | 21F4 | RIGHT ARROW WITH SMALL CIRCLE | |
⇵ | 8693 | 21F5 | DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW | |
⇶ | 8694 | 21F6 | THREE RIGHTWARDS ARROWS | |
⇷ | 8695 | 21F7 | LEFTWARDS ARROW WITH VERTICAL STROKE | |
⇸ | 8696 | 21F8 | RIGHTWARDS ARROW WITH VERTICAL STROKE | |
⇹ | 8697 | 21F9 | LEFT RIGHT ARROW WITH VERTICAL STROKE | |
⇺ | 8698 | 21FA | LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE | |
⇻ | 8699 | 21FB | RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE | |
⇼ | 8700 | 21FC | LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE | |
⇽ | 8701 | 21FD | LEFTWARDS OPEN-HEADED ARROW | |
⇾ | 8702 | 21FE | RIGHTWARDS OPEN-HEADED ARROW | |
⇿ | 8703 | 21FF | LEFT RIGHT OPEN-HEADED ARROW |
Older browsers may not support all the HTML5 entities in the table below.
Char | Dec | Hex | Entity | Name |
---|---|---|---|---|
₠ | 8352 | 20A0 | EURO-CURRENCY SIGN |
₡ | 8353 | 20A1 | COLON SIGN | |
₢ | 8354 | 20A2 | CRUZEIRO SIGN | |
₣ | 8355 | 20A3 | FRENCH FRANC SIGN | |
₤ | 8356 | 20A4 | LIRA SIGN | |
₥ | 8357 | 20A5 | MILL SIGN | |
₦ | 8358 | 20A6 | NAIRA SIGN | |
₧ | 8359 | 20A7 | PESETA SIGN | |
₨ | 8360 | 20A8 | RUPEE SIGN | |
₩ | 8361 | 20A9 | WON SIGN | |
₪ | 8362 | 20AA | NEW SHEQEL SIGN | |
₫ | 8363 | 20AB | DONG SIGN | |
€ | 8364 | 20AC | € | EURO SIGN |
₭ | 8365 | 20AD | KIP SIGN | |
₮ | 8366 | 20AE | TUGRIK SIGN | |
₯ | 8367 | 20AF | DRACHMA SIGN | |
₰ | 8368 | 20B0 | GERMAN PENNY SYMBOL | |
₱ | 8369 | 20B1 | PESO SIGN | |
₲ | 8370 | 20B2 | GUARANI SIGN | |
₳ | 8371 | 20B3 | AUSTRAL SIGN | |
₴ | 8372 | 20B4 | HRYVNIA SIGN | |
₵ | 8373 | 20B5 | CEDI SIGN | |
₶ | 8374 | 20B6 | LIVRE TOURNOIS SIGN | |
₷ | 8375 | 20B7 | SPESMILO SIGN | |
₸ | 8376 | 20B8 | TENGE SIGN | |
₹ | 8377 | 20B9 | INDIAN RUPEE SIGN | |
₺ | 8378 | 20BA | TURKISH LIRA SIGN | |
₻ | 8379 | 20BB | NORDIC MARK SIGN | |
₼ | 8380 | 20BC | MANAT SIGN | |
₽ | 8381 | 20BD | RUBLE SIGN | |
₾ | 8382 | 20BE | LARI SIGN | |
₿ | 8383 | 20BF | BITCOIN SIGN |
Some Greek Letters Supported by HTML
Char | Number | Entity | Description |
---|---|---|---|
Α | Α | Α | GREEK CAPITAL LETTER ALPHA |
Β | Β | Β | GREEK CAPITAL LETTER BETA |
Γ | Γ | Γ | GREEK CAPITAL LETTER GAMMA |
Δ | Δ | Δ | GREEK CAPITAL LETTER DELTA |
Ε | Ε | Ε | GREEK CAPITAL LETTER EPSILON |
Ζ | Ζ | Ζ | GREEK CAPITAL LETTER ZETA |
Some Other Entities Supported by HTML
Char | Number | Entity | Description |
---|---|---|---|
© | © | © | COPYRIGHT SIGN |
® | ® | ® | REGISTERED SIGN |
€ | € | € | EURO SIGN |
™ | ™ | ™ | TRADEMARK |
← | ← | ← | LEFTWARDS ARROW |
↑ | ↑ | ↑ | UPWARDS ARROW |
→ | → | → | RIGHTWARDS ARROW |
↓ | ↓ | ↓ | DOWNWARDS ARROW |
♠ | ♠ | ♠ | BLACK SPADE SUIT |
♣ | ♣ | ♣ | BLACK CLUB SUIT |
♥ | ♥ | ♥ | BLACK HEART SUIT |
♦ | ♦ | ♦ | BLACK DIAMOND SUIT |
Char | Dec | Hex | Entity | Name |
---|---|---|---|---|
☀ | 9728 | 2600 | BLACK SUN WITH RAYS | |
☁ | 9729 | 2601 | CLOUD | |
☂ | 9730 | 2602 | UMBRELLA | |
☃ | 9731 | 2603 | SNOWMAN | |
☄ | 9732 | 2604 | COMET | |
★ | 9733 | 2605 | BLACK STAR | |
☆ | 9734 | 2606 | WHITE STAR | |
☇ | 9735 | 2607 | LIGHTNING | |
☈ | 9736 | 2608 | THUNDERSTORM | |
☉ | 9737 | 2609 | SUN | |
☊ | 9738 | 260A | ASCENDING NODE | |
☋ | 9739 | 260B | DESCENDING NODE | |
☌ | 9740 | 260C | CONJUNCTION | |
☍ | 9741 | 260D | OPPOSITION | |
☎ | 9742 | 260E | BLACK TELEPHONE | |
☏ | 9743 | 260F | WHITE TELEPHONE | |
☐ | 9744 | 2610 | BALLOT BOX | |
☑ | 9745 | 2611 | BALLOT BOX WITH CHECK | |
☒ | 9746 | 2612 | BALLOT BOX WITH X | |
☓ | 9747 | 2613 | SALTIRE | |
☔ | 9748 | 2614 | UMBRELLA WITH RAIN DROPS | |
☕ | 9749 | 2615 | HOT BEVERAGE | |
☖ | 9750 | 2616 | WHITE SHOGI PIECE | |
☗ | 9751 | 2617 | BLACK SHOGI PIECE | |
☘ | 9752 | 2618 | SHAMROCK | |
☙ | 9753 | 2619 | REVERSED ROTATED FLORAL HEART BULLET | |
☚ | 9754 | 261A | BLACK LEFT POINTING INDEX | |
☛ | 9755 | 261B | BLACK RIGHT POINTING INDEX | |
☜ | 9756 | 261C | WHITE LEFT POINTING INDEX | |
☝ | 9757 | 261D | WHITE UP POINTING INDEX | |
☞ | 9758 | 261E | WHITE RIGHT POINTING INDEX | |
☟ | 9759 | 261F | WHITE DOWN POINTING INDEX | |
☠ | 9760 | 2620 | SKULL AND CROSSBONES | |
☡ | 9761 | 2621 | CAUTION SIGN | |
☢ | 9762 | 2622 | RADIOACTIVE SIGN | |
☣ | 9763 | 2623 | BIOHAZARD SIGN | |
☤ | 9764 | 2624 | CADUCEUS | |
☥ | 9765 | 2625 | ANKH | |
☦ | 9766 | 2626 | ORTHODOX CROSS | |
☧ | 9767 | 2627 | CHI RHO | |
☨ | 9768 | 2628 | CROSS OF LORRAINE | |
☩ | 9769 | 2629 | CROSS OF JERUSALEM | |
☪ | 9770 | 262A | STAR AND CRESCENT | |
☫ | 9771 | 262B | FARSI SYMBOL | |
☬ | 9772 | 262C | KHANDA | |
☭ | 9773 | 262D | HAMMER AND SICKLE | |
☮ | 9774 | 262E | PEACE SYMBOL | |
☯ | 9775 | 262F | YIN YANG | |
☰ | 9776 | 2630 | TRIGRAM FOR HEAVEN | |
☱ | 9777 | 2631 | TRIGRAM FOR LAKE | |
☲ | 9778 | 2632 | TRIGRAM FOR FIRE | |
☳ | 9779 | 2633 | TRIGRAM FOR THUNDER | |
☴ | 9780 | 2634 | TRIGRAM FOR WIND | |
☵ | 9781 | 2635 | TRIGRAM FOR WATER | |
☶ | 9782 | 2636 | TRIGRAM FOR MOUNTAIN | |
☷ | 9783 | 2637 | TRIGRAM FOR EARTH | |
☸ | 9784 | 2638 | WHEEL OF DHARMA | |
☹ | 9785 | 2639 | WHITE FROWNING FACE | |
☺ | 9786 | 263A | WHITE SMILING FACE | |
☻ | 9787 | 263B | BLACK SMILING FACE | |
☼ | 9788 | 263C | WHITE SUN WITH RAYS | |
☽ | 9789 | 263D | FIRST QUARTER MOON | |
☾ | 9790 | 263E | LAST QUARTER MOON | |
☿ | 9791 | 263F | MERCURY | |
♀ | 9792 | 2640 | FEMALE SIGN | |
♁ | 9793 | 2641 | EARTH | |
♂ | 9794 | 2642 | MALE SIGN | |
♃ | 9795 | 2643 | JUPITER | |
♄ | 9796 | 2644 | SATURN | |
♅ | 9797 | 2645 | URANUS | |
♆ | 9798 | 2646 | NEPTUNE | |
♇ | 9799 | 2647 | PLUTO | |
♈ | 9800 | 2648 | ARIES | |
♉ | 9801 | 2649 | TAURUS | |
♊ | 9802 | 264A | GEMINI | |
♋ | 9803 | 264B | CANCER | |
♌ | 9804 | 264C | LEO | |
♍ | 9805 | 264D | VIRGO | |
♎ | 9806 | 264E | LIBRA | |
♏ | 9807 | 264F | SCORPIUS | |
♐ | 9808 | 2650 | SAGITTARIUS | |
♑ | 9809 | 2651 | CAPRICORN | |
♒ | 9810 | 2652 | AQUARIUS | |
♓ | 9811 | 2653 | PISCES | |
♔ | 9812 | 2654 | WHITE CHESS KING | |
♕ | 9813 | 2655 | WHITE CHESS QUEEN | |
♖ | 9814 | 2656 | WHITE CHESS ROOK | |
♗ | 9815 | 2657 | WHITE CHESS BISHOP | |
♘ | 9816 | 2658 | WHITE CHESS KNIGHT | |
♙ | 9817 | 2659 | WHITE CHESS PAWN | |
♚ | 9818 | 265A | BLACK CHESS KING | |
♛ | 9819 | 265B | BLACK CHESS QUEEN | |
♜ | 9820 | 265C | BLACK CHESS ROOK | |
♝ | 9821 | 265D | BLACK CHESS BISHOP | |
♞ | 9822 | 265E | BLACK CHESS KNIGHT | |
♟ | 9823 | 265F | BLACK CHESS PAWN | |
♠ | 9824 | 2660 | ♠ | BLACK SPADE SUIT |
♡ | 9825 | 2661 | WHITE HEART SUIT | |
♢ | 9826 | 2662 | WHITE DIAMOND SUIT | |
♣ | 9827 | 2663 | ♣ | BLACK CLUB SUIT |
♤ | 9828 | 2664 | WHITE SPADE SUIT | |
♥ | 9829 | 2665 | ♥ | BLACK HEART SUIT |
♦ | 9830 | 2666 | ♦ | BLACK DIAMOND SUIT |
♧ | 9831 | 2667 | WHITE CLUB SUIT | |
♨ | 9832 | 2668 | HOT SPRINGS | |
♩ | 9833 | 2669 | QUARTER NOTE | |
♪ | 9834 | 266A | EIGHTH NOTE | |
♫ | 9835 | 266B | BEAMED EIGHTH NOTES | |
♬ | 9836 | 266C | BEAMED SIXTEENTH NOTES | |
♭ | 9837 | 266D | MUSIC FLAT SIGN | |
♮ | 9838 | 266E | MUSIC NATURAL SIGN | |
♯ | 9839 | 266F | MUSIC SHARP SIGN | |
♰ | 9840 | 2670 | WEST SYRIAC CROSSTry it | |
♱ | 9841 | 2671 | EAST SYRIAC CROSSTry it | |
♲ | 9842 | 2672 | UNIVERSAL RECYCLING SYMBOLTry it | |
♳ | 9843 | 2673 | RECYCLING SYMBOL FOR TYPE-1 PLASTICSTry it | |
♴ | 9844 | 2674 | RECYCLING SYMBOL FOR TYPE-2 PLASTICSTry it | |
♵ | 9845 | 2675 | RECYCLING SYMBOL FOR TYPE-3 PLASTICSTry it | |
♶ | 9846 | 2676 | RECYCLING SYMBOL FOR TYPE-4 PLASTICSTry it | |
♷ | 9847 | 2677 | RECYCLING SYMBOL FOR TYPE-5 PLASTICSTry it | |
♸ | 9848 | 2678 | RECYCLING SYMBOL FOR TYPE-6 PLASTICSTry it | |
♹ | 9849 | 2679 | RECYCLING SYMBOL FOR TYPE-7 PLASTICSTry it | |
♺ | 9850 | 267A | RECYCLING SYMBOL FOR GENERIC MATERIALSTry it | |
♻ | 9851 | 267B | BLACK UNIVERSAL RECYCLING SYMBOLTry it | |
♼ | 9852 | 267C | RECYCLED PAPER SYMBOLTry it | |
♽ | 9853 | 267D | PARTIALLY-RECYCLED PAPER SYMBOLTry it | |
♾ | 9854 | 267E | PERMANENT PAPER SIGNTry it | |
♿ | 9855 | 267F | WHEELCHAIR SYMBOLTry it | |
⚀ | 9856 | 2680 | DIE FACE-1Try it | |
⚁ | 9857 | 2681 | DIE FACE-2Try it | |
⚂ | 9858 | 2682 | DIE FACE-3Try it | |
⚃ | 9859 | 2683 | DIE FACE-4Try it | |
⚄ | 9860 | 2684 | DIE FACE-5Try it | |
⚅ | 9861 | 2685 | DIE FACE-6Try it | |
⚆ | 9862 | 2686 | WHITE CIRCLE WITH DOT RIGHTTry it | |
⚇ | 9863 | 2687 | WHITE CIRCLE WITH TWO DOTSTry it | |
⚈ | 9864 | 2688 | BLACK CIRCLE WITH WHITE DOT RIGHTTry it | |
⚉ | 9865 | 2689 | BLACK CIRCLE WITH TWO WHITE DOTSTry it | |
⚊ | 9866 | 268A | MONOGRAM FOR YANGTry it | |
⚋ | 9867 | 268B | MONOGRAM FOR YINTry it | |
⚌ | 9868 | 268C | DIGRAM FOR GREATER YANGTry it | |
⚍ | 9869 | 268D | DIGRAM FOR LESSER YINTry it | |
⚎ | 9870 | 268E | DIGRAM FOR LESSER YANGTry it | |
⚏ | 9871 | 268F | DIGRAM FOR GREATER YINTry it | |
⚐ | 9872 | 2690 | WHITE FLAGTry it | |
⚑ | 9873 | 2691 | BLACK FLAGTry it | |
⚒ | 9874 | 2692 | HAMMER AND PICKTry it | |
⚓ | 9875 | 2693 | ANCHORTry it | |
⚔ | 9876 | 2694 | CROSSED SWORDSTry it | |
⚕ | 9877 | 2695 | STAFF OF AESCULAPIUSTry it | |
⚖ | 9878 | 2696 | SCALESTry it | |
⚗ | 9879 | 2697 | ALEMBICTry it | |
⚘ | 9880 | 2698 | FLOWERTry it | |
⚙ | 9881 | 2699 | GEARTry it | |
⚚ | 9882 | 269A | STAFF OF HERMESTry it | |
⚛ | 9883 | 269B | ATOM SYMBOLTry it | |
⚜ | 9884 | 269C | FLEUR-DE-LISTry it | |
⚝ | 9885 | 269D | OUTLINED WHITE STARTry it | |
⚞ | 9886 | 269E | THREE LINES CONVERGING RIGHTTry it | |
⚟ | 9887 | 269F | THREE LINES CONVERGING LEFTTry it | |
⚠ | 9888 | 26A0 | WARNING SIGNTry it | |
⚡ | 9889 | 26A1 | HIGH VOLTAGE SIGNTry it | |
⚢ | 9890 | 26A2 | DOUBLED FEMALE SIGNTry it | |
⚣ | 9891 | 26A3 | DOUBLED MALE SIGNTry it | |
⚤ | 9892 | 26A4 | INTERLOCKED FEMALE AND MALE SIGNTry it | |
⚥ | 9893 | 26A5 | MALE AND FEMALE SIGNTry it | |
⚦ | 9894 | 26A6 | MALE WITH STROKE SIGNTry it | |
⚧ | 9895 | 26A7 | MALE WITH STROKE AND MALE AND FEMALE SIGNTry it | |
⚨ | 9896 | 26A8 | VERTICAL MALE WITH STROKE SIGNTry it | |
⚩ | 9897 | 26A9 | HORIZONTAL MALE WITH STROKE SIGNTry it | |
⚪ | 9898 | 26AA | MEDIUM WHITE CIRCLETry it | |
⚫ | 9899 | 26AB | MEDIUM BLACK CIRCLETry it | |
⚬ | 9900 | 26AC | MEDIUM SMALL WHITE CIRCLETry it | |
⚭ | 9901 | 26AD | MARRIAGE SYMBOLTry it | |
⚮ | 9902 | 26AE | DIVORCE SYMBOLTry it | |
⚯ | 9903 | 26AF | UNMARRIED PARTNERSHIP SYMBOLTry it | |
⚰ | 9904 | 26B0 | COFFINTry it | |
⚱ | 9905 | 26B1 | FUNERAL URNTry it | |
⚲ | 9906 | 26B2 | NEUTERTry it | |
⚳ | 9907 | 26B3 | CERESTry it | |
⚴ | 9908 | 26B4 | PALLASTry it | |
⚵ | 9909 | 26B5 | JUNOTry it | |
⚶ | 9910 | 26B6 | VESTATry it | |
⚷ | 9911 | 26B7 | CHIRONTry it | |
⚸ | 9912 | 26B8 | BLACK MOON LILITHTry it | |
⚹ | 9913 | 26B9 | SEXTILETry it | |
⚺ | 9914 | 26BA | SEMISEXTILETry it | |
⚻ | 9915 | 26BB | QUINCUNXTry it | |
⚼ | 9916 | 26BC | SESQUIQUADRATETry it | |
⚽ | 9917 | 26BD | SOCCER BALLTry it | |
⚾ | 9918 | 26BE | BASEBALLTry it | |
⚿ | 9919 | 26BF | SQUARED KEYTry it | |
⛀ | 9920 | 26C0 | WHITE DRAUGHTS MANTry it | |
⛁ | 9921 | 26C1 | WHITE DRAUGHTS KINGTry it | |
⛂ | 9922 | 26C2 | BLACK DRAUGHTS MANTry it | |
⛃ | 9923 | 26C3 | BLACK DRAUGHTS KINGTry it | |
⛄ | 9924 | 26C4 | SNOWMAN WITHOUT SNOWTry it | |
⛅ | 9925 | 26C5 | SUN BEHIND CLOUDTry it | |
⛆ | 9926 | 26C6 | RAINTry it | |
⛇ | 9927 | 26C7 | BLACK SNOWMANTry it | |
⛈ | 9928 | 26C8 | THUNDER CLOUD AND RAINTry it | |
⛉ | 9929 | 26C9 | TURNED WHITE SHOGI PIECETry it | |
⛊ | 9930 | 26CA | TURNED BLACK SHOGI PIECETry it | |
⛋ | 9931 | 26CB | WHITE DIAMOND IN SQUARETry it | |
⛌ | 9932 | 26CC | CROSSING LANESTry it | |
⛍ | 9933 | 26CD | DISABLED CARTry it | |
⛎ | 9934 | 26CE | OPHIUCHUSTry it | |
⛏ | 9935 | 26CF | PICKTry it | |
⛐ | 9936 | 26D0 | CAR SLIDINGTry it | |
⛑ | 9937 | 26D1 | HELMET WITH WHITE CROSSTry it | |
⛒ | 9938 | 26D2 | CIRCLED CROSSING LANESTry it | |
⛓ | 9939 | 26D3 | CHAINSTry it | |
⛔ | 9940 | 26D4 | NO ENTRYTry it | |
⛕ | 9941 | 26D5 | ALTERNATE ONE-WAY LEFT WAY TRAFFICTry it | |
⛖ | 9942 | 26D6 | BLACK TWO-WAY LEFT WAY TRAFFICTry it | |
⛗ | 9943 | 26D7 | WHITE TWO-WAY LEFT WAY TRAFFICTry it | |
⛘ | 9944 | 26D8 | BLACK LEFT LANE MERGETry it | |
⛙ | 9945 | 26D9 | WHITE LEFT LANE MERGETry it | |
⛚ | 9946 | 26DA | DRIVE SLOW SIGNTry it | |
⛛ | 9947 | 26DB | HEAVY WHITE DOWN-POINTING TRIANGLETry it | |
⛜ | 9948 | 26DC | LEFT CLOSED ENTRYTry it | |
⛝ | 9949 | 26DD | SQUARED SALTIRETry it | |
⛞ | 9950 | 26DE | FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARETry it | |
⛟ | 9951 | 26DF | BLACK TRUCKTry it | |
⛠ | 9952 | 26E0 | RESTRICTED LEFT ENTRY-1Try it | |
⛡ | 9953 | 26E1 | RESTRICTED LEFT ENTRY-2Try it | |
⛢ | 9954 | 26E2 | ASTRONOMICAL SYMBOL FOR URANUSTry it | |
⛣ | 9955 | 26E3 | HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVETry it | |
⛤ | 9956 | 26E4 | PENTAGRAMTry it | |
⛥ | 9957 | 26E5 | RIGHT-HANDED INTERLACED PENTAGRAMTry it | |
⛦ | 9958 | 26E6 | LEFT-HANDED INTERLACED PENTAGRAMTry it | |
⛧ | 9959 | 26E7 | INVERTED PENTAGRAMTry it | |
⛨ | 9960 | 26E8 | BLACK CROSS ON SHIELDTry it | |
⛩ | 9961 | 26E9 | SHINTO SHRINETry it | |
⛪ | 9962 | 26EA | CHURCHTry it | |
⛫ | 9963 | 26EB | CASTLETry it | |
⛬ | 9964 | 26EC | HISTORIC SITETry it | |
⛭ | 9965 | 26ED | GEAR WITHOUT HUBTry it | |
⛮ | 9966 | 26EE | GEAR WITH HANDLESTry it | |
⛯ | 9967 | 26EF | MAP SYMBOL FOR LIGHTHOUSETry it | |
⛰ | 9968 | 26F0 | MOUNTAINTry it | |
⛱ | 9969 | 26F1 | UMBRELLA ON GROUNDTry it | |
⛲ | 9970 | 26F2 | FOUNTAINTry it | |
⛳ | 9971 | 26F3 | FLAG IN HOLETry it | |
⛴ | 9972 | 26F4 | FERRYTry it | |
⛵ | 9973 | 26F5 | SAILBOATTry it | |
⛶ | 9974 | 26F6 | SQUARE FOUR CORNERSTry it | |
⛷ | 9975 | 26F7 | SKIERTry it | |
⛸ | 9976 | 26F8 | ICE SKATETry it | |
⛹ | 9977 | 26F9 | PERSON WITH BALLTry it | |
⛺ | 9978 | 26FA | TENTTry it | |
⛻ | 9979 | 26FB | JAPANESE BANK SYMBOLTry it | |
⛼ | 9980 | 26FC | HEADSTONE GRAVEYARD SYMBOLTry it | |
⛽ | 9981 | 26FD | FUEL PUMPTry it | |
⛾ | 9982 | 26FE | CUP ON BLACK SQUARETry it | |
⛿ | 9983 | 26FF | WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPETry it |
server.js , create ldap database server - clients socket
ldapjs Server API
This document covers the ldapjs server API and assumes that you are familiar with LDAP. If you're not, read the guide first.
Create a server
The code to create a new server looks like:
const server = ldap.createServer();
The full list of options is:
||log||You can optionally pass in a Bunyan compatible logger instance the client will use to acquire a child logger.|| ||certificate||A PEM-encoded X.509 certificate; will cause this server to run in TLS mode.|| ||key||A PEM-encoded private key that corresponds to certificate for SSL.||
Note On Logger
The passed in logger is expected to conform to the Log4j standard API. Internally, abstract-logging is used to implement the interface. As a result, no log messages will be generated unless an external logger is supplied.
Known compatible loggers are:
Properties on the server object
maxConnections
Set this property to reject connections when the server's connection count gets high.
connections (getter only) - DEPRECATED
The number of concurrent connections on the server. This property is deprecated, please use server.getConnections() instead.
url
Returns the fully qualified URL this server is listening on. For example: ldaps://10.1.2.3:1636
. If you haven't yet called listen
, it will always return ldap://localhost:389
.
Event: 'close'
function() {}
Emitted when the server closes.
Listening for requests
The LDAP server API wraps up and mirrors the node.js server.listen
family of APIs.
After calling listen
, the property url
on the server object itself will be available.
Example:
server.listen(389, '127.0.0.1', function() {
console.log('LDAP server listening at: ' + server.url);
});
Port and Host
listen(port, [host], [callback])
Begin accepting connections on the specified port and host. If the host is omitted, the server will accept connections directed to any IPv4 address (INADDR_ANY).
This function is asynchronous. The last parameter callback will be called when the server has been bound.
Unix Domain Socket
listen(path, [callback])
Start a UNIX socket server listening for connections on the given path.
This function is asynchronous. The last parameter callback will be called when the server has been bound.
File descriptor
listenFD(fd)
Start a server listening for connections on the given file descriptor.
This file descriptor must have already had the bind(2)
and listen(2)
system calls invoked on it. Additionally, it must be set non-blocking; try fcntl(fd, F_SETFL, O_NONBLOCK)
.
Inspecting server state
server.getConnections(callback)
The LDAP server API mirrors the Node.js server.getConnections
API. Callback should take two arguments err and count.
Routes
The LDAP server API is meant to be the LDAP-equivalent of the express/restify paradigm of programming. Essentially every method is of the form OP(req, res, next)
where OP is one of bind, add, del, etc. You can chain handlers together by calling next()
and ordering your functions in the definition of the route. For example:
function authorize(req, res, next) {
if (!req.connection.ldap.bindDN.equals('cn=root'))
return next(new ldap.InsufficientAccessRightsError());
return next();
}
server.search('o=example', authorize, function(req, res, next) { ... });
Note that ldapjs is also slightly different, since it's often going to be backed to a DB-like entity, in that it also has an API where you can pass in a 'backend' object. This is necessary if there are persistent connection pools, caching, etc. that need to be placed in an object.
For example ldapjs-riak is a complete implementation of the LDAP protocol over Riak. Getting an LDAP server up with riak looks like:
const ldap = require('ldapjs');
const ldapRiak = require('ldapjs-riak');
const server = ldap.createServer();
const backend = ldapRiak.createBackend({
"host": "localhost",
"port": 8098,
"bucket": "example",
"indexes": ["l", "cn"],
"uniqueIndexes": ["uid"],
"numConnections": 5
});
server.add("o=example",
backend,
backend.add());
...
The first parameter to an ldapjs route is always the point in the tree to mount the handler chain at. The second argument is optionally a backend object. After that you can pass in an arbitrary combination of functions in the form f(req, res, next)
or arrays of functions of the same signature (ldapjs will unroll them).
Unlike HTTP, LDAP operations do not have a heterogeneous wire format, so each operation requires specific methods/fields on the request/response objects. However, there is a .use()
method availabe, similar to that on express/connect, allowing you to chain up "middleware":
server.use(function(req, res, next) {
console.log('hello world');
return next();
});
Common Request Elements
All request objects have the dn
getter on it, which is "context-sensitive" and returns the point in the tree that the operation wants to operate on. The LDAP protocol itself sadly doesn't define operations this way, and has a unique name for just about every op. So, ldapjs calls it dn
. The DN object itself is documented at DN.
All requests have an optional array of Control
objects. Control
will have the properties type
(string), criticality
(boolean), and optionally, a string value
.
All request objects will have a connection
object, which is the net.Socket
associated to this request. Off the connection
object is an ldap
object. The most important property to pay attention to is the bindDN
property which will be an instance of an ldap.DN
object. This is what the client authenticated as on this connection. If the client didn't bind, then a DN object will be there defaulted to cn=anonymous
.
Additionally, request will have a logId
parameter you can use to uniquely identify the request/connection pair in logs (includes the LDAP messageID).
Common Response Elements
All response objects will have an end
method on them. By default, calling res.end()
with no arguments will return SUCCESS (0x00) to the client (with the exception of compare
which will return COMPARE_TRUE (0x06)). You can pass in a status code to the end()
method to return an alternate status code.
However, it's more common/easier to use the return next(new LDAPError())
pattern, since ldapjs will fill in the extra LDAPResult fields like matchedDN and error message for you.
Errors
ldapjs includes an exception hierarchy that directly corresponds to the RFC list of error codes. The complete list is documented in errors. But the paradigm is something defined like CONSTRAINT_VIOLATION in the RFC would be ConstraintViolationError
in ldapjs. Upon calling next(new LDAPError())
, ldapjs will stop calling your handler chain. For example:
server.search('o=example',
(req, res, next) => { return next(); },
(req, res, next) => { return next(new ldap.OperationsError()); },
(req, res, next) => { res.end(); }
);
In the code snipped above, the third handler would never get invoked.
Bind
Adds a mount in the tree to perform LDAP binds with. Example:
server.bind('ou=people, o=example', (req, res, next) => {
console.log('bind DN: ' + req.dn.toString());
console.log('bind PW: ' + req.credentials);
res.end();
});
BindRequest
BindRequest objects have the following properties:
version
The LDAP protocol version the client is requesting to run this connection on. Note that ldapjs only supports LDAP version 3.
name
The DN the client is attempting to bind as (note this is the same as the dn
property).
authentication
The method of authentication. Right now only simple
is supported.
credentials
The credentials to go with the name/authentication
pair. For simple
, this will be the plain-text password.
BindResponse
No extra methods above an LDAPResult
API call.
Add
Adds a mount in the tree to perform LDAP adds with.
server.add('ou=people, o=example', (req, res, next) => {
console.log('DN: ' + req.dn.toString());
console.log('Entry attributes: ' + req.toObject().attributes);
res.end();
});
AddRequest
AddRequest objects have the following properties:
entry
The DN the client is attempting to add (this is the same as the dn
property).
attributes
The set of attributes in this entry. This will be an array of Attribute
objects (which have a type and an array of values). This directly maps to how the request came in off the wire. It's likely you'll want to use toObject()
and iterate that way, since that will transform an AddRequest into a standard JavaScript object.
toObject()
This operation will return a plain JavaScript object from the request that looks like:
{
dn: 'cn=foo, o=example', // string, not DN object
attributes: {
cn: ['foo'],
sn: ['bar'],
objectclass: ['person', 'top']
}
}
AddResponse
No extra methods above an LDAPResult
API call.
Search
Adds a handler for the LDAP search operation.
server.search('o=example', (req, res, next) => {
console.log('base object: ' + req.dn.toString());
console.log('scope: ' + req.scope);
console.log('filter: ' + req.filter.toString());
res.end();
});
SearchRequest
SearchRequest objects have the following properties:
baseObject
The DN the client is attempting to start the search at (equivalent to dn
).
scope
(string) one of:
- base
- one
- sub
derefAliases
An integer (defined in the LDAP protocol). Defaults to '0' (meaning never deref).
sizeLimit
The number of entries to return. Defaults to '0' (unlimited). ldapjs doesn't currently automatically enforce this, but probably will at some point.
timeLimit
Maximum amount of time the server should take in sending search entries. Defaults to '0' (unlimited).
typesOnly
Whether to return only the names of attributes, and not the values. Defaults to 'false'. ldapjs will take care of this for you.
filter
The filter object that the client requested. Notably this has a matches()
method on it that you can leverage. For an example of introspecting a filter, take a look at the ldapjs-riak source.
attributes
An optional list of attributes to restrict the returned result sets to. ldapjs will automatically handle this for you.
SearchResponse
send(entry)
Allows you to send a SearchEntry
object. You do not need to explicitly pass in a SearchEntry
object, and can instead just send a plain JavaScript object that matches the format used from AddRequest.toObject()
.
server.search('o=example', (req, res, next) => {
const obj = {
dn: 'o=example',
attributes: {
objectclass: ['top', 'organization'],
o: ['example']
}
};
if (req.filter.matches(obj))
res.send(obj)
res.end();
});
modify
Allows you to handle an LDAP modify operation.
server.modify('o=example', (req, res, next) => {
console.log('DN: ' + req.dn.toString());
console.log('changes:');
for (const c of req.changes) {
console.log(' operation: ' + c.operation);
console.log(' modification: ' + c.modification.toString());
}
res.end();
});
ModifyRequest
ModifyRequest objects have the following properties:
object
The DN the client is attempting to update (this is the same as the dn
property).
changes
An array of Change
objects the client is attempting to perform. See below for details on the Change
object.
Change
The Change
object will have the following properties:
operation
A string, and will be one of: 'add', 'delete', or 'replace'.
modification
Will be an Attribute
object, which will have a 'type' (string) field, and 'vals', which will be an array of string values.
ModifyResponse
No extra methods above an LDAPResult
API call.
del
Allows you to handle an LDAP delete operation.
server.del('o=example', (req, res, next) => {
console.log('DN: ' + req.dn.toString());
res.end();
});
DeleteRequest
entry
The DN the client is attempting to delete (this is the same as the dn
property).
DeleteResponse
No extra methods above an LDAPResult
API call.
compare
Allows you to handle an LDAP compare operation.
server.compare('o=example', (req, res, next) => {
console.log('DN: ' + req.dn.toString());
console.log('attribute name: ' + req.attribute);
console.log('attribute value: ' + req.value);
res.end(req.value === 'foo');
});
CompareRequest
entry
The DN the client is attempting to compare (this is the same as the dn
property).
attribute
The string name of the attribute to compare values of.
value
The string value of the attribute to compare.
CompareResponse
The end()
method for compare takes a boolean, as opposed to a numeric code (you can still pass in a numeric LDAP status code if you want). Beyond that, there are no extra methods above an LDAPResult
API call.
modifyDN
Allows you to handle an LDAP modifyDN operation.
server.modifyDN('o=example', (req, res, next) => {
console.log('DN: ' + req.dn.toString());
console.log('new RDN: ' + req.newRdn.toString());
console.log('deleteOldRDN: ' + req.deleteOldRdn);
console.log('new superior: ' +
(req.newSuperior ? req.newSuperior.toString() : ''));
res.end();
});
ModifyDNRequest
entry
The DN the client is attempting to rename (this is the same as the dn
property).
newRdn
The leaf RDN the client wants to rename this entry to. This will be a DN object.
deleteOldRdn
Whether or not to delete the old RDN (i.e., rename vs copy). Defaults to 'true'.
newSuperior
Optional (DN). If the modifyDN operation wishes to relocate the entry in the tree, the newSuperior
field will contain the new parent.
ModifyDNResponse
No extra methods above an LDAPResult
API call.
exop
Allows you to handle an LDAP extended operation. Extended operations are pretty much arbitrary extensions, by definition. Typically the extended 'name' is an OID, but ldapjs makes no such restrictions; it just needs to be a string. Unlike the other operations, extended operations don't map to any location in the tree, so routing here will be exact match, as opposed to subtree.
// LDAP whoami
server.exop('1.3.6.1.4.1.4203.1.11.3', (req, res, next) => {
console.log('name: ' + req.name);
console.log('value: ' + req.value);
res.value = 'u:xxyyz@EXAMPLE.NET';
res.end();
return next();
});
ExtendedRequest
name
Will always be a match to the route-defined name. Clients must include this in their requests.
value
Optional string. The arbitrary blob the client sends for this extended operation.
ExtendedResponse
name
The name of the extended operation. ldapjs will automatically set this.
value
The arbitrary (string) value to send back as part of the response.
unbind
ldapjs by default provides an unbind handler that just disconnects the client and cleans up any internals (in ldapjs core). You can override this handler if you need to clean up any items in your backend, or perform any other cleanup tasks you need to.
server.unbind((req, res, next) => {
res.end();
});
Note that the LDAP unbind operation actually doesn't send any response (by definition in the RFC), so the UnbindResponse is really just a stub that ultimately calls net.Socket.end()
for you. There are no properties available on either the request or response objects, except, of course, for end()
on the response.
ldap javascript client socket api
ldapjs Client API
This document covers the ldapjs client API and assumes that you are familiar with LDAP. If you're not, read the guide first.
Create a client
The code to create a new client looks like:
const ldap = require('ldapjs');
const client = ldap.createClient({
url: ['ldap://127.0.0.1:1389', 'ldap://127.0.0.2:1389']
});
client.on('error', (err) => {
// handle connection error
})
You can use ldap://
or ldaps://
; the latter would connect over SSL (note that this will not use the LDAP TLS extended operation, but literally an SSL connection to port 636, as in LDAP v2). The full set of options to create a client is:
Attribute | Description |
---|---|
url | A string or array of valid LDAP URL(s) (proto/host/port) |
socketPath | Socket path if using AF_UNIX sockets |
log | A compatible logger instance (Default: no-op logger) |
timeout | Milliseconds client should let operations live for before timing out (Default: Infinity) |
connectTimeout | Milliseconds client should wait before timing out on TCP connections (Default: OS default) |
tlsOptions | Additional options passed to TLS connection layer when connecting via ldaps:// (See: The TLS docs for node.js) |
idleTimeout | Milliseconds after last activity before client emits idle event |
strictDN | Force strict DN parsing for client methods (Default is true) |
reconnect | Try to reconnect when the connection gets lost (Default is false) |
url
This parameter takes a single connection string or an array of connection strings as an input. In case an array is provided, the client tries to connect to the servers in given order. To achieve random server strategy (e.g. to distribute the load among the servers), please shuffle the array before passing it as an argument.
Note On Logger
A passed in logger is expected to conform to the Bunyan API. Specifically, the logger is expected to have a child()
method. If a logger is supplied that does not have such a method, then a shim version is added that merely returns the passed in logger.
Known compatible loggers are:
Connection management
As LDAP is a stateful protocol (as opposed to HTTP), having connections torn down from underneath you can be difficult to deal with. Several mechanisms have been provided to mitigate this trouble.
Reconnect
You can provide a Boolean option indicating if a reconnect should be tried. For more sophisticated control, you can provide an Object with the properties initialDelay
(default: 100
), maxDelay
(default: 10000
) and failAfter
(default: Infinity
). After the reconnect you maybe need to bind again.
Client events
The client is an EventEmitter
and can emit the following events:
Event | Description |
---|---|
error | General error |
connectRefused | Server refused connection. Most likely bad authentication |
connectTimeout | Server timeout |
connectError | Socket connection error |
setupError | Setup error after successful connection |
socketTimeout | Socket timeout |
resultError | Search result error |
timeout | Search result timeout |
destroy | After client is disconnected |
end | Socket end event |
close | Socket closed |
connect | Client connected |
idle | Idle timeout reached |
Common patterns
The last two parameters in every API are controls
and callback
. controls
can be either a single instance of a Control
or an array of Control
objects. You can, and probably will, omit this option.
Almost every operation has the callback form of function(err, res)
where err will be an instance of an LDAPError
(you can use instanceof
to switch). You probably won't need to check the res
parameter, but it's there if you do.
bind
bind(dn, password, controls, callback)
Performs a bind operation against the LDAP server.
The bind API only allows LDAP 'simple' binds (equivalent to HTTP Basic Authentication) for now. Note that all client APIs can optionally take an array of Control
objects. You probably don't need them though...
Example:
client.bind('cn=root', 'secret', (err) => {
assert.ifError(err);
});
add
add(dn, entry, controls, callback)
Performs an add operation against the LDAP server.
Allows you to add an entry (which is just a plain JS object), and as always, controls are optional.
Example:
const entry = {
cn: 'foo',
sn: 'bar',
email: ['foo@bar.com', 'foo1@bar.com'],
objectclass: 'fooPerson'
};
client.add('cn=foo, o=example', entry, (err) => {
assert.ifError(err);
});
compare
compare(dn, attribute, value, controls, callback)
Performs an LDAP compare operation with the given attribute and value against the entry referenced by dn.
Example:
client.compare('cn=foo, o=example', 'sn', 'bar', (err, matched) => {
assert.ifError(err);
console.log('matched: ' + matched);
});
del
del(dn, controls, callback)
Deletes an entry from the LDAP server.
Example:
client.del('cn=foo, o=example', (err) => {
assert.ifError(err);
});
exop
exop(name, value, controls, callback)
Performs an LDAP extended operation against an LDAP server. name
is typically going to be an OID (well, the RFC says it must be; however, ldapjs has no such restriction). value
is completely arbitrary, and is whatever the exop says it should be.
Example (performs an LDAP 'whois' extended op):
client.exop('1.3.6.1.4.1.4203.1.11.3', (err, value, res) => {
assert.ifError(err);
console.log('whois: ' + value);
});
modify
modify(name, changes, controls, callback)
Performs an LDAP modify operation against the LDAP server. This API requires you to pass in a Change
object, which is described below. Note that you can pass in a single Change
or an array of Change
objects.
Example:
const change = new ldap.Change({
operation: 'add',
modification: {
pets: ['cat', 'dog']
}
});
client.modify('cn=foo, o=example', change, (err) => {
assert.ifError(err);
});
Change
A Change
object maps to the LDAP protocol of a modify change, and requires you to set the operation
and modification
. The operation
is a string, and must be one of:
Operation | Description |
---|---|
replace | Replaces the attribute referenced in modification . If the modification has no values, it is equivalent to a delete. |
add | Adds the attribute value(s) referenced in modification . The attribute may or may not already exist. |
delete | Deletes the attribute (and all values) referenced in modification . |
modification
is just a plain old JS object with the values you want.
modifyDN
modifyDN(dn, newDN, controls, callback)
Performs an LDAP modifyDN (rename) operation against an entry in the LDAP server. A couple points with this client API:
- There is no ability to set "keep old dn." It's always going to flag the old dn to be purged.
- The client code will automatically figure out if the request is a "new superior" request ("new superior" means move to a different part of the tree, as opposed to just renaming the leaf).
Example:
client.modifyDN('cn=foo, o=example', 'cn=bar', (err) => {
assert.ifError(err);
});
search
search(base, options, controls, callback)
Performs a search operation against the LDAP server.
The search operation is more complex than the other operations, so this one takes an options
object for all the parameters. However, ldapjs makes some defaults for you so that if you pass nothing in, it's pretty much equivalent to an HTTP GET operation (i.e., base search against the DN, filter set to always match).
Like every other operation, base
is a DN string.
Options can be a string representing a valid LDAP filter or an object containing the following fields:
Attribute | Description |
---|---|
scope | One of base , one , or sub . Defaults to base . |
filter | A string version of an LDAP filter (see below), or a programatically constructed Filter object. Defaults to (objectclass=*) . |
attributes | attributes to select and return (if these are set, the server will return only these attributes). Defaults to the empty set, which means all attributes. You can provide a string if you want a single attribute or an array of string for one or many. |
attrsOnly | boolean on whether you want the server to only return the names of the attributes, and not their values. Borderline useless. Defaults to false. |
sizeLimit | the maximum number of entries to return. Defaults to 0 (unlimited). |
timeLimit | the maximum amount of time the server should take in responding, in seconds. Defaults to 10. Lots of servers will ignore this. |
paged | enable and/or configure automatic result paging |
Responses inside callback of the search
method are an EventEmitter
where you will get a notification for each searchEntry
that comes back from the server. You will additionally be able to listen for a searchRequest
, searchReference
, error
and end
event. searchRequest
is emitted immediately after every SearchRequest
is sent with a SearchRequest
parameter. You can do operations like client.abandon
with searchRequest.messageID
to abandon this search request. Note that the error
event will only be for client/TCP errors, not LDAP error codes like the other APIs. You'll want to check the LDAP status code (likely for 0
) on the end
event to assert success. LDAP search results can give you a lot of status codes, such as time or size exceeded, busy, inappropriate matching, etc., which is why this method doesn't try to wrap up the code matching.
Example:
const opts = {
filter: '(&(l=Seattle)(email=*@foo.com))',
scope: 'sub',
attributes: ['dn', 'sn', 'cn']
};
client.search('o=example', opts, (err, res) => {
assert.ifError(err);
res.on('searchRequest', (searchRequest) => {
console.log('searchRequest: ', searchRequest.messageID);
});
res.on('searchEntry', (entry) => {
console.log('entry: ' + JSON.stringify(entry.object));
});
res.on('searchReference', (referral) => {
console.log('referral: ' + referral.uris.join());
});
res.on('error', (err) => {
console.error('error: ' + err.message);
});
res.on('end', (result) => {
console.log('status: ' + result.status);
});
});
Filter Strings
The easiest way to write search filters is to write them compliant with RFC2254, which is "The string representation of LDAP search filters." Note that ldapjs doesn't support extensible matching, since it's one of those features that almost nobody actually uses in practice.
Assuming you don't really want to read the RFC, search filters in LDAP are basically are a "tree" of attribute/value assertions, with the tree specified in prefix notation. For example, let's start simple, and build up a complicated filter. The most basic filter is equality, so let's assume you want to search for an attribute email
with a value of foo@bar.com
. The syntax would be:
(email=foo@bar.com)
ldapjs requires all filters to be surrounded by '()' blocks. Ok, that was easy. Let's now assume that you want to find all records where the email is actually just anything in the "@bar.com" domain and the location attribute is set to Seattle:
(&(email=*@bar.com)(l=Seattle))
Now our filter is actually three LDAP filters. We have an and
filter (single amp &
), an equality
filter (the l=Seattle)
, and a substring
filter. Substrings are wildcard filters. They use *
as the wildcard. You can put more than one wildcard for a given string. For example you could do (email=*@*bar.com)
to match any email of @bar.com or its subdomains like "example@foo.bar.com"
.
Now, let's say we also want to set our filter to include a specification that either the employeeType not be a manager nor a secretary:
(&(email=*@bar.com)(l=Seattle)(!(|(employeeType=manager)(employeeType=secretary))))
The not
character is represented as a !
, the or
as a single pipe |
. It gets a little bit complicated, but it's actually quite powerful, and lets you find almost anything you're looking for.
Paging
Many LDAP server enforce size limits upon the returned result set (commonly 1000). In order to retrieve results beyond this limit, a PagedResultControl
is passed between the client and server to iterate through the entire dataset. While callers could choose to do this manually via the controls
parameter to search()
, ldapjs has internal mechanisms to easily automate the process. The most simple way to use the paging automation is to set the paged
option to true when performing a search:
const opts = {
filter: '(objectclass=commonobject)',
scope: 'sub',
paged: true,
sizeLimit: 200
};
client.search('o=largedir', opts, (err, res) => {
assert.ifError(err);
res.on('searchEntry', (entry) => {
// do per-entry processing
});
res.on('page', (result) => {
console.log('page end');
});
res.on('error', (resErr) => {
assert.ifError(resErr);
});
res.on('end', (result) => {
console.log('done ');
});
});
This will enable paging with a default page size of 199 (sizeLimit
- 1) and will output all of the resulting objects via the searchEntry
event. At the end of each result during the operation, a page
event will be emitted as well (which includes the intermediate searchResult
object).
For those wanting more precise control over the process, an object with several parameters can be provided for the paged
option. The pageSize
parameter sets the size of result pages requested from the server. If no value is specified, it will fall back to the default (100 or sizeLimit
- 1, to obey the RFC). The pagePause
parameter allows back-pressure to be exerted on the paged search operation by pausing at the end of each page. When enabled, a callback function is passed as an additional parameter to page
events. The client will wait to request the next page until that callback is executed.
Here is an example where both of those parameters are used:
const queue = new MyWorkQueue(someSlowWorkFunction);
const opts = {
filter: '(objectclass=commonobject)',
scope: 'sub',
paged: {
pageSize: 250,
pagePause: true
},
};
client.search('o=largerdir', opts, (err, res) => {
assert.ifError(err);
res.on('searchEntry', (entry) => {
// Submit incoming objects to queue
queue.push(entry);
});
res.on('page', (result, cb) => {
// Allow the queue to flush before fetching next page
queue.cbWhenFlushed(cb);
});
res.on('error', (resErr) => {
assert.ifError(resErr);
});
res.on('end', (result) => {
console.log('done');
});
});
starttls
starttls(options, controls, callback)
Attempt to secure existing LDAP connection via STARTTLS.
Example:
const opts = {
ca: [fs.readFileSync('mycacert.pem')]
};
client.starttls(opts, (err, res) => {
assert.ifError(err);
// Client communication now TLS protected
});
unbind
unbind(callback)
Performs an unbind operation against the LDAP server.
Note that unbind operation is not an opposite operation for bind. Unbinding results in disconnecting the client regardless of whether a bind operation was performed.
The callback
argument is optional as unbind does not have a response.
Example:
client.unbind((err) => {
assert.ifError(err);
});
main, controllers. search recoder c - js ->
class XEnvironment {
public:
boost::ptr_vector<XObjectEye> eyes;
boost::ptr_vector<XLight> lights;
boost::ptr_vector<XSolidObject> solidObjects;
std::vector<XObject> objects;
XRender render;
bool LoadEnv(const char* filename);
void CreateScene();
void Draw();
bool isSolidObject(char * name);
bool deleteSolidObject(char * name);
XSolidObject * getSolidObject(char * name);
void saveObjects(char * filename);
bool loadObjects(char * filename);
XEnvironment();
XEnvironment(const XEnvironment& orig);
virtual ~XEnvironment();
private:
hello code and json or ldap
<style type="text/css">
.plantas3d{
position:fixed;
z-index: -1;
top:0%;
left:0%;
width: 100%;
height: 100%;
/*background-color: #111;*/
}
#renderCanvas {
width: 100%;
height: 100%;
touch-action: none;
position:fixed;
}
</style>
<script>
//<div class="plantas3d">
// <canvas id="renderCanvas" touch-action="none"></canvas>
//</div>
const canvas = document.getElementById("renderCanvas"); // Get the canvas element
const engine = new BABYLON.Engine(canvas, true); // Generate the BABYLON 3D engine
// Add your code here matching the playground format
const createScene = function () {
const scene = new BABYLON.Scene(engine);
// BABYLON.SceneLoader.ImportMeshAsync("", "https://assets.babylonjs.com/meshes/", "box.babylon");
// Light
const light = new BABYLON.HemisphericLight("HemiLight", new BABYLON.Vector3(-2, 0, 0), scene);
// Camera
const camera = new BABYLON.ArcRotateCamera("Camera", -1.57, 1.0, 200, new BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas);
//Creation of a sphere (name of the sphere, segments, diameter, scene)
var sphere = BABYLON.Mesh.CreateSphere("sphere", 100.0, 100.0, scene);
sphere.position = new BABYLON.Vector3(0, 0, 0);
sphere.rotation.x = Math.PI;
//Add material to sphere
var groundMaterial = new BABYLON.StandardMaterial("mat", scene);
groundMaterial.diffuseTexture = new BABYLON.Texture("/templates/smart/gl/on/earthmap1k.jpg", scene);
groundMaterial.specularTexture = new BABYLON.Texture("/templates/smart/gl/on/earthspec1k.jpg", scene);
groundMaterial.bumpTexture = new BABYLON.Texture("/templates/smart/gl/on/earthbump1k.jpg", scene);
groundMaterial.invertNormalMapX = true;
groundMaterial.invertNormalMapY = true;
sphere.material = groundMaterial;
//Creation of atmosphere (name of the sphere, segments, diameter, scene)
var patmosphere = BABYLON.Mesh.CreateSphere("patmosphere", 105.0, 105.0, scene);
patmosphere.position = new BABYLON.Vector3(0, 0, 0);
patmosphere.rotation.x = Math.PI;
var patmosphereS = new BABYLON.StandardMaterial("patmosphereS", scene);
patmosphereS.diffuseColor = new BABYLON.Color3(0.4, 0.5, 0.3);
//patmosphereS.bumpTexture = new BABYLON.Texture("/templates/smart/gl/on/lyod.jpg", scene);
patmosphereS.opacityTexture = new BABYLON.Texture("/templates/smart/gl/on/clouda.png", scene);
//patmosphere.diffuseTexture.hasAlpha = true;
patmosphereS.alpha = 0.7;
//Creation of atmosphere (name of the sphere, segments, diameter, scene)
var atmosphere = BABYLON.Mesh.CreateSphere("atmosphere", 110.0, 110.0, scene);
atmosphere.position = new BABYLON.Vector3(0, 0, 0);
atmosphere.rotation.x = Math.PI;
var atmosphereS = new BABYLON.StandardMaterial("atmosphereS", scene);
atmosphereS.diffuseColor = new BABYLON.Color3(0.3, 0.3, 0.3);
//atmosphereS.bumpTexture = new BABYLON.Texture("/templates/smart/gl/on/lyod.jpg", scene);
atmosphereS.opacityTexture = new BABYLON.Texture("/templates/smart/gl/on/clouda.png", scene);
//atmosphereS.diffuseTexture.hasAlpha = true;
atmosphereS.invertNormalMapX = true;
atmosphereS.invertNormalMapY = true;
atmosphereS.alpha = 0.9;
//myMaterial.diffuseTexture.hasAlpha = true;
//materialSphere1.wireframe = true;
// atmosphereS.diffuseTexture = new BABYLON.Texture("/templates/smart/gl/on/lyod.jpg", scene);
//atmosphereS.specularColor = new BABYLON.Color3(0.5, 0.6, 0.87);
//atmosphereS.emissiveColor = new BABYLON.Color3(1, 1, 1);
//atmosphereS.ambientColor = new BABYLON.Color3(0.23, 0.98, 0.53);
//atmosphereS.invertNormalMapX = true;
//atmosphereS.invertNormalMapY = true;
atmosphere.material = atmosphereS;
var skybox = BABYLON.Mesh.CreateBox("skyBox", 400.0, scene);
var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
skyboxMaterial.backFaceCulling = false;
skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("/templates/smart/gl/on/starbox2", scene);
skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
skybox.material = skyboxMaterial;
// Animations - rotate earth
var alpha = 0;
scene.beforeRender = function () {
sphere.rotation.y = alpha;
atmosphere.rotation.y = alpha;
alpha -= 0.0015;
};
return scene;
};
const scene = createScene(); //Call the createScene function
// Register a render loop to repeatedly render the scene
engine.runRenderLoop(function () {
scene.render();
});
// Watch for browser/canvas resize events
window.addEventListener("resize", function () {
engine.resize();
});
</script>
source code help
Demo with just material:
<!doctype html>
<html>
<head>
<meta charset = "utf-8">
<title>BabylonJs - Basic Element-Creating Scene</title>
<script src = "babylon.js"></script>
<style>
canvas {width: 100%; height: 100%;}
</style>
</head>
<body>
<canvas id = "renderCanvas"></canvas>
<script type = "text/javascript">
var canvas = document.getElementById("renderCanvas");
var engine = new BABYLON.Engine(canvas, true);
var createScene = function() {
var scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3(0, 1, 0);
var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene);
camera.attachControl(canvas, true);
var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.7;
var materialforbox = new BABYLON.StandardMaterial("texture1", scene);
var box = BABYLON.Mesh.CreateBox("box", '3', scene);
box.material = materialforbox;
return scene;
};
var scene = createScene();
engine.runRenderLoop(function() {
scene.render();
});
</script>
</body>
</html>
Demo with transparency:
<!doctype html> <html> <head> <meta charset = "utf-8"> <title>BabylonJs - Basic Element-Creating Scene</title> <script src = "babylon.js"></script> <style> canvas {width: 100%; height: 100%;} </style> </head> <body> <canvas id = "renderCanvas"></canvas> <script type = "text/javascript"> var canvas = document.getElementById("renderCanvas"); var engine = new BABYLON.Engine(canvas, true); var createScene = function() { var scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color3(0, 1, 0); var camera = new BABYLON.ArcRotateCamera("Camera", 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene); camera.attachControl(canvas, true); var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene); light.intensity = 0.7; var materialforbox = new BABYLON.StandardMaterial("texture1", scene); var box = BABYLON.Mesh.CreateBox("box", '3', scene); box.material = materialforbox; materialforbox.alpha = 0.3; // value of 0.3 is applied fro transparency return scene; }; var scene = createScene(); engine.runRenderLoop(function() { scene.render(); }); </script> </body> </html>
More: www.tutorialspoint.com/babylonjs/
ldap.plantas.vip http://ldap.namapi.org ldap.kivie.in
web ldap manager
ldapjs Client API
This document covers the ldapjs client API and assumes that you are familiar with LDAP. If you're not, read the guide first.
Create a client
The code to create a new client looks like:
const ldap = require('ldapjs');
const client = ldap.createClient({
url: ['ldap://127.0.0.1:1389', 'ldap://127.0.0.2:1389']
});
client.on('error', (err) => {
// handle connection error
})
You can use ldap://
or ldaps://
; the latter would connect over SSL (note that this will not use the LDAP TLS extended operation, but literally an SSL connection to port 636, as in LDAP v2). The full set of options to create a client is:
Attribute | Description |
---|---|
url | A string or array of valid LDAP URL(s) (proto/host/port) |
socketPath | Socket path if using AF_UNIX sockets |
log | A compatible logger instance (Default: no-op logger) |
timeout | Milliseconds client should let operations live for before timing out (Default: Infinity) |
connectTimeout | Milliseconds client should wait before timing out on TCP connections (Default: OS default) |
tlsOptions | Additional options passed to TLS connection layer when connecting via ldaps:// (See: The TLS docs for node.js) |
idleTimeout | Milliseconds after last activity before client emits idle event |
strictDN | Force strict DN parsing for client methods (Default is true) |
reconnect | Try to reconnect when the connection gets lost (Default is false) |
url
This parameter takes a single connection string or an array of connection strings as an input. In case an array is provided, the client tries to connect to the servers in given order. To achieve random server strategy (e.g. to distribute the load among the servers), please shuffle the array before passing it as an argument.
Note On Logger
A passed in logger is expected to conform to the Bunyan API. Specifically, the logger is expected to have a child()
method. If a logger is supplied that does not have such a method, then a shim version is added that merely returns the passed in logger.
Known compatible loggers are:
Connection management
As LDAP is a stateful protocol (as opposed to HTTP), having connections torn down from underneath you can be difficult to deal with. Several mechanisms have been provided to mitigate this trouble.
Reconnect
You can provide a Boolean option indicating if a reconnect should be tried. For more sophisticated control, you can provide an Object with the properties initialDelay
(default: 100
), maxDelay
(default: 10000
) and failAfter
(default: Infinity
). After the reconnect you maybe need to bind again.
Client events
The client is an EventEmitter
and can emit the following events:
Event | Description |
---|---|
error | General error |
connectRefused | Server refused connection. Most likely bad authentication |
connectTimeout | Server timeout |
connectError | Socket connection error |
setupError | Setup error after successful connection |
socketTimeout | Socket timeout |
resultError | Search result error |
timeout | Search result timeout |
destroy | After client is disconnected |
end | Socket end event |
close | Socket closed |
connect | Client connected |
idle | Idle timeout reached |
Common patterns
The last two parameters in every API are controls
and callback
. controls
can be either a single instance of a Control
or an array of Control
objects. You can, and probably will, omit this option.
Almost every operation has the callback form of function(err, res)
where err will be an instance of an LDAPError
(you can use instanceof
to switch). You probably won't need to check the res
parameter, but it's there if you do.
bind
bind(dn, password, controls, callback)
Performs a bind operation against the LDAP server.
The bind API only allows LDAP 'simple' binds (equivalent to HTTP Basic Authentication) for now. Note that all client APIs can optionally take an array of Control
objects. You probably don't need them though...
Example:
client.bind('cn=root', 'secret', (err) => {
assert.ifError(err);
});
add
add(dn, entry, controls, callback)
Performs an add operation against the LDAP server.
Allows you to add an entry (which is just a plain JS object), and as always, controls are optional.
Example:
const entry = {
cn: 'foo',
sn: 'bar',
email: ['foo@bar.com', 'foo1@bar.com'],
objectclass: 'fooPerson'
};
client.add('cn=foo, o=example', entry, (err) => {
assert.ifError(err);
});
compare
compare(dn, attribute, value, controls, callback)
Performs an LDAP compare operation with the given attribute and value against the entry referenced by dn.
Example:
client.compare('cn=foo, o=example', 'sn', 'bar', (err, matched) => {
assert.ifError(err);
console.log('matched: ' + matched);
});
del
del(dn, controls, callback)
Deletes an entry from the LDAP server.
Example:
client.del('cn=foo, o=example', (err) => {
assert.ifError(err);
});
exop
exop(name, value, controls, callback)
Performs an LDAP extended operation against an LDAP server. name
is typically going to be an OID (well, the RFC says it must be; however, ldapjs has no such restriction). value
is completely arbitrary, and is whatever the exop says it should be.
Example (performs an LDAP 'whois' extended op):
client.exop('1.3.6.1.4.1.4203.1.11.3', (err, value, res) => {
assert.ifError(err);
console.log('whois: ' + value);
});
modify
modify(name, changes, controls, callback)
Performs an LDAP modify operation against the LDAP server. This API requires you to pass in a Change
object, which is described below. Note that you can pass in a single Change
or an array of Change
objects.
Example:
const change = new ldap.Change({
operation: 'add',
modification: {
pets: ['cat', 'dog']
}
});
client.modify('cn=foo, o=example', change, (err) => {
assert.ifError(err);
});
Change
A Change
object maps to the LDAP protocol of a modify change, and requires you to set the operation
and modification
. The operation
is a string, and must be one of:
Operation | Description |
---|---|
replace | Replaces the attribute referenced in modification . If the modification has no values, it is equivalent to a delete. |
add | Adds the attribute value(s) referenced in modification . The attribute may or may not already exist. |
delete | Deletes the attribute (and all values) referenced in modification . |
modification
is just a plain old JS object with the values you want.
modifyDN
modifyDN(dn, newDN, controls, callback)
Performs an LDAP modifyDN (rename) operation against an entry in the LDAP server. A couple points with this client API:
- There is no ability to set "keep old dn." It's always going to flag the old dn to be purged.
- The client code will automatically figure out if the request is a "new superior" request ("new superior" means move to a different part of the tree, as opposed to just renaming the leaf).
Example:
client.modifyDN('cn=foo, o=example', 'cn=bar', (err) => {
assert.ifError(err);
});
search
search(base, options, controls, callback)
Performs a search operation against the LDAP server.
The search operation is more complex than the other operations, so this one takes an options
object for all the parameters. However, ldapjs makes some defaults for you so that if you pass nothing in, it's pretty much equivalent to an HTTP GET operation (i.e., base search against the DN, filter set to always match).
Like every other operation, base
is a DN string.
Options can be a string representing a valid LDAP filter or an object containing the following fields:
Attribute | Description |
---|---|
scope | One of base , one , or sub . Defaults to base . |
filter | A string version of an LDAP filter (see below), or a programatically constructed Filter object. Defaults to (objectclass=*) . |
attributes | attributes to select and return (if these are set, the server will return only these attributes). Defaults to the empty set, which means all attributes. You can provide a string if you want a single attribute or an array of string for one or many. |
attrsOnly | boolean on whether you want the server to only return the names of the attributes, and not their values. Borderline useless. Defaults to false. |
sizeLimit | the maximum number of entries to return. Defaults to 0 (unlimited). |
timeLimit | the maximum amount of time the server should take in responding, in seconds. Defaults to 10. Lots of servers will ignore this. |
paged | enable and/or configure automatic result paging |
Responses from the search
method are an EventEmitter
where you will get a notification for each searchEntry
that comes back from the server. You will additionally be able to listen for a searchReference
, error
and end
event. Note that the error
event will only be for client/TCP errors, not LDAP error codes like the other APIs. You'll want to check the LDAP status code (likely for 0
) on the end
event to assert success. LDAP search results can give you a lot of status codes, such as time or size exceeded, busy, inappropriate matching, etc., which is why this method doesn't try to wrap up the code matching.
Example:
const opts = {
filter: '(&(l=Seattle)(email=*@foo.com))',
scope: 'sub',
attributes: ['dn', 'sn', 'cn']
};
client.search('o=example', opts, (err, res) => {
assert.ifError(err);
res.on('searchEntry', (entry) => {
console.log('entry: ' + JSON.stringify(entry.object));
});
res.on('searchReference', (referral) => {
console.log('referral: ' + referral.uris.join());
});
res.on('error', (err) => {
console.error('error: ' + err.message);
});
res.on('end', (result) => {
console.log('status: ' + result.status);
});
});
Filter Strings
The easiest way to write search filters is to write them compliant with RFC2254, which is "The string representation of LDAP search filters." Note that ldapjs doesn't support extensible matching, since it's one of those features that almost nobody actually uses in practice.
Assuming you don't really want to read the RFC, search filters in LDAP are basically are a "tree" of attribute/value assertions, with the tree specified in prefix notation. For example, let's start simple, and build up a complicated filter. The most basic filter is equality, so let's assume you want to search for an attribute email
with a value of foo@bar.com
. The syntax would be:
(email=foo@bar.com)
ldapjs requires all filters to be surrounded by '()' blocks. Ok, that was easy. Let's now assume that you want to find all records where the email is actually just anything in the "@bar.com" domain and the location attribute is set to Seattle:
(&(email=*@bar.com)(l=Seattle))
Now our filter is actually three LDAP filters. We have an and
filter (single amp &
), an equality
filter (the l=Seattle)
, and a substring
filter. Substrings are wildcard filters. They use *
as the wildcard. You can put more than one wildcard for a given string. For example you could do (email=*@*bar.com)
to match any email of @bar.com or its subdomains like "example@foo.bar.com"
.
Now, let's say we also want to set our filter to include a specification that either the employeeType not be a manager nor a secretary:
(&(email=*@bar.com)(l=Seattle)(!(|(employeeType=manager)(employeeType=secretary))))
The not
character is represented as a !
, the or
as a single pipe |
. It gets a little bit complicated, but it's actually quite powerful, and lets you find almost anything you're looking for.
Paging
Many LDAP server enforce size limits upon the returned result set (commonly 1000). In order to retrieve results beyond this limit, a PagedResultControl
is passed between the client and server to iterate through the entire dataset. While callers could choose to do this manually via the controls
parameter to search()
, ldapjs has internal mechanisms to easily automate the process. The most simple way to use the paging automation is to set the paged
option to true when performing a search:
const opts = {
filter: '(objectclass=commonobject)',
scope: 'sub',
paged: true,
sizeLimit: 200
};
client.search('o=largedir', opts, (err, res) => {
assert.ifError(err);
res.on('searchEntry', (entry) => {
// do per-entry processing
});
res.on('page', (result) => {
console.log('page end');
});
res.on('error', (resErr) => {
assert.ifError(resErr);
});
res.on('end', (result) => {
console.log('done ');
});
});
This will enable paging with a default page size of 199 (sizeLimit
- 1) and will output all of the resulting objects via the searchEntry
event. At the end of each result during the operation, a page
event will be emitted as well (which includes the intermediate searchResult
object).
For those wanting more precise control over the process, an object with several parameters can be provided for the paged
option. The pageSize
parameter sets the size of result pages requested from the server. If no value is specified, it will fall back to the default (100 or sizeLimit
- 1, to obey the RFC). The pagePause
parameter allows back-pressure to be exerted on the paged search operation by pausing at the end of each page. When enabled, a callback function is passed as an additional parameter to page
events. The client will wait to request the next page until that callback is executed.
Here is an example where both of those parameters are used:
const queue = new MyWorkQueue(someSlowWorkFunction);
const opts = {
filter: '(objectclass=commonobject)',
scope: 'sub',
paged: {
pageSize: 250,
pagePause: true
},
};
client.search('o=largerdir', opts, (err, res) => {
assert.ifError(err);
res.on('searchEntry', (entry) => {
// Submit incoming objects to queue
queue.push(entry);
});
res.on('page', (result, cb) => {
// Allow the queue to flush before fetching next page
queue.cbWhenFlushed(cb);
});
res.on('error', (resErr) => {
assert.ifError(resErr);
});
res.on('end', (result) => {
console.log('done');
});
});
starttls
starttls(options, controls, callback)
Attempt to secure existing LDAP connection via STARTTLS.
Example:
const opts = {
ca: [fs.readFileSync('mycacert.pem')]
};
client.starttls(opts, (err, res) => {
assert.ifError(err);
// Client communication now TLS protected
});
unbind
unbind(callback)
Performs an unbind operation against the LDAP server.
Note that unbind operation is not an opposite operation for bind. Unbinding results in disconnecting the client regardless of whether a bind operation was performed.
The callback
argument is optional as unbind does not have a response.
Example:
client.unbind((err) => {
assert.ifError(err);
});
Litegui is a javascript library to create webapps with a desktop look-alike user interface. All the widgets, panels, dialogs, etc are created from Javascript instead of HTML. The upside of this is that this helps to create more dynamic interfaces and gives a lot of flexibility. The downside is that you'll need to write some code to make it all work. If you're looking for a library that just needs some HTML and a couple of event handlers to work, litegui is not what you're looking for. On the other hand, any advanced UI will need a lot of coding and in creating advanced UI's litegui shines.
Creating a UI
So let's start with building something simple. This first introduction will show you how to create a menubar and add some items to it. Please note that the javascript is brief on purpose and doesn't reflect javascript best coding practices. The goal here is to get you up and running as fast as possible.
Start with the following index.html:
<!DOCTYPE html>
<html>
<head>
<title>Algae</title>
<link type="text/css" rel="stylesheet" href="litegui.js/build/litegui.css">
<script type="text/javascript" src="litegui.js/external/jscolor/jscolor.js"></script>
<script type="application/javascript" src="litegui.js/build/litegui.js"></script>
</head>
<body>
<script src="init.js"></script>
</body>
</html>
Add the following to init.js:
// Initialize litegui.js
LiteGUI.init();
// Create a menu bar
var menu = new LiteGUI.Menubar();
// Add some items to it
menu.add('File/New');
menu.add('File/Settings');
// This will be shown greyed out
menu.add('File/I\'m not clickable', { disabled: true });
// Add a second main menu item
menu.add('Help/Help');
menu.add('Help/About');
// Add the menu bar to litegui
LiteGUI.add(menu);
Now open index.html in your browser. You should see a menu bar on the top of the screen. That might be pretty nifty, but it's not yet doing anything usefull. Let's fix that by adding a settings dialog
Add the following code to init.js after the call to LiteGUI.init():
function createSettingsDialog() {
// Create a new dialog
var dialog = new LiteGUI.Dialog('Settings', { title:'Settings', close: true, minimize: false, width: 300, height: 500, scroll: false, resizable: false, draggable: true });
// Create a collection of widgets
var widgets = new LiteGUI.Inspector();
var nameWidget = widgets.addString("Your name","foo");
var ageWidget = widgets.addNumber("Your age", 35, { min: 0, max: 125 });
dialog.add(widgets);
// Placeholder function to show the new settings. Normally you would do something usefull here
// with the new settings.
function applySettings() {
console.log("Your name is " + nameWidget.getValue() + ", and you are " + ageWidget.getValue() + " years old");
}
// Add some buttons
dialog.addButton('Ok', { close: true, callback: applySettings });
dialog.addButton('Apply', { close: false, callback: applySettings });
dialog.addButton('Cancel',{ close: 'fade' });
return dialog;
}
var settingsDialog = createSettingsDialog();
// dialogs are shown on creation, let's hide it until the settings menu item is clicked
settingsDialog.hide();
And change the initialization of the menu bar:
menu.add('File/Settings', {callback: function() { settingsDialog.show('fade'); } });
- is a library that wraps WebGL to make it more user-friendly by creating classes for managing different items like Buffer, Mesh, Texture, Shader and other common aspects of any WebGL applications.
It helps simplifying working with WebGL without having to handle all the low-level calls but without losing any freedom.
Some features are:
- Easy context creation
- Classes for:
- Meshes and Buffers: Fill a buffer easily and upload it to the GPU
- Textures: load, fill, clone, copy (even blur) for TEXTURE_2D and TEXTURE_CUBE_MAP
- Shaders: compile from string, from file, insert preprocessor macros, extracts all the uniform locations
- FrameBufferObjects: to render to a texture, to multiple textures, to depth texture.
- Some basic primitive shapes (plane, cube, sphere, cylinder, hemisphere).
- OBJ parser and encoder (easy to add new ones)
- Loaders for Images and Meshes from URL (uses a placeholder till its loaded)
- Uses typed-arrays for everything (uses glMatrix for all operations)
- No garbage generated (reuses containers)
- Basic Raytracing (for ray-sphere and ray-plane collision)
- Events system
- Cross-browser input handling for mouse, keyboard and gamepad
- Supports multiple WebGL contexts
- Supports WebGL1 and WebGL2
- Octree class
It is a fork from LightGL.js by Evan Wallace, but some major changes have been made. Some of the main differences:
- Matrices have been replaced by glMatrix
- Meshes are forced to be stored in ArrayBuffer formats
- Meshes support range rendering with offset
- Removed fixed pipeline behaviour
- Better event handling (mouse position, mouse wheel, dragging)
- Textures expanded to support Arraybuffers and Cubemaps
- Events system to trigger events from any object
- Support for multiple WebGL contexts in the same page
This library has been used in several projects like Rendeer.js or Canvas2DtoWebGL.
For a list of similar libraries check this list
Demos
Demos are included in the Examples folder but you can check them in this website.
Usage
Include the library and dependencies
<script src="js/gl-matrix-min.js"></script>
<script src="js/litegl.js"></script>
Create the context
var gl = GL.create({width:800, height:600});
Attach to DOM
document.getElementById("mycontainer").appendChild( gl.canvas )
Get user input
gl.captureMouse();
gl.onmousedown = function(e) { ... }
gl.captureKeys();
gl.onkey = function(e) { ... }
Compile shader
var shader = new GL.Shader( vertex_shader_code, fragment_shader_code );
Create Mesh
var mesh = new GL.Mesh({vertices:[-1,-1,0, 1,-1,0, 0,1,0], coords:[0,0, 1,0, 0.5,1]});
Load a texture
var texture = GL.Texture.fromURL("image.jpg", { minFilter: gl.LINEAR_MIPMAP_LINEAR });
Render
gl.ondraw = function() {
texture.bind(0);
var my_uniforms = { u_texture: 0, u_color: [1,1,1,1] };
shader.uniforms( my_uniforms ).draw( mesh );
}
gl.animate(); //calls the requestAnimFrame constantly, which will call ondraw
For better understanding of all the features and how to use them check the guides folder.
is a lightweight 3D scene graph library, meant to be used in 3D web apps and games. It is meant to be flexible and easy to tweak. It used the library litegl.js as a low level layer for WebGL. It comes with some common useful classes like: Scene and SceneNode Camera Renderer ParticleEmissor And because it uses litegl you have all the basic ones (Mesh, Shader and Texture).
Usage
Here is a brief example of how to use it, but I totally encourage to read the more detailed starter guide stored in the guides folder, or to check the boilerplate provided, and finally check the documentation for better understanding of the API.
First include the library and dependencies
<script src="js/gl-matrix-min.js"></script>
<script src="js/litegl.js"></script>
<script src="js/rendeer.js"></script>
Create the scene
var scene = new RD.Scene();
Create the renderer
var context = GL.create({width: window.innerWidth, height:window.innerHeight});
var renderer = new RD.Renderer(context);
Attach to DOM
document.body.appendChild(renderer.canvas);
Get user input
gl.captureMouse();
renderer.context.onmousedown = function(e) { ... }
renderer.context.onmousemove = function(e) { ... }
gl.captureKeys();
renderer.context.onkey = function(e) { ... }
Set camera
var camera = new RD.Camera();
camera.perspective( 45, gl.canvas.width / gl.canvas.height, 1, 1000 );
camera.lookAt( [100,100,100],[0,0,0],[0,1,0] );
Create and register mesh
var mesh = GL.Mesh.fromURL("data/mesh.obj");
renderer.meshes["mymesh"] = mesh;
load and register texture
var texture = GL.Texture.fromURL("mytexture.png", { minFilter: gl.LINEAR_MIPMAP_LINEAR, magFilter: gl.LINEAR });
renderer.textures["mytexture.png"] = texture;
Compile and register shader
var shader = new GL.Shader(vs_code, fs_code);
renderer.shaders["phong"] = shader;
Add a node to the scene
var node = new RD.SceneNode();
node.color = [1,0,0,1];
node.mesh = "mymesh";
node.texture = "mytexture.png";
node.shader = "phong";
node.position = [0,0,0];
node.scale([10,10,10]);
scene.root.addChild(node);
Create main loop
requestAnimationFrame(animate);
function animate() {
requestAnimationFrame( animate );
last = now;
now = getTime();
var dt = (now - last) * 0.001;
renderer.render(scene, camera);
scene.update(dt);
}
the front-end and back-end library that allows javascript apps to store resources (images, text-files, binaries) in the server. It comes with its own users and units system that allow every user to partition its own space and share it among other users.
Some of the features:
- REST HTTP API for storing, listing, moving, updating or deleting files.
- Basic users (register, login, delete, administration )
- Independent file tree per user
- Units, users can have several units to store files and share with other users
- Files can have thumbnail image and metadata
Usage
Once installed you can include the litefileserver.js
script in your project you must first login:
var lfs = LFS.setup("myhost", onReady );
var session = null;
//check to see if the server is available
function onReady()
{
LFS.login( username, password, onLogin );
}
function onLogin( my_session, err )
{
if(!my_session)
throw("error login in:", err);
session = my_session;
}
Once logged you can fetch for files and folders using the session:
session.getUnitsAndFolders( function(units) {
//units contain info about every unit and which folders it has
});
session.getFiles( unit_id, folder, function( files ) {
//info about the files in that folder
});
Check the LFS.Session
class for more info about all the actions you can perform (create folders, units, give privileges, upload files, etc).
Also check the demo in the src folder to see an usage of the system.
текстовый код для разбивки и оформления интернет станиц
http://www.w3schools.com - html инструкции
nodes can be programmed easily and it includes an editor to construct and tests the graphs. It can be integrated easily in any existing web applications and graphs can be run without the need of the editor.
Features
- Renders on Canvas2D (zoom in/out and panning, easy to render complex interfaces, can be used inside a WebGLTexture)
- Easy to use editor (searchbox, keyboard shortcuts, multiple selection, context menu, ...)
- Optimized to support hundreds of nodes per graph (on editor but also on execution)
- Customizable theme (colors, shapes, background)
- Callbacks to personalize every action/drawing/event of nodes
- Subgraphs (nodes that contain graphs themselves)
- Live mode system (hides the graph but calls nodes to render whatever they want, useful to create UIs)
- Graphs can be executed in NodeJS
- Highly customizable nodes (color, shape, slots vertical or horizontal, widgets, custom rendering)
- Easy to integrate in any JS application (one single file, no dependencies)
- Typescript support
examples video: http://github.com/jagenjo/litegraph.js
Nodes provided
Although it is easy to create new node types, LiteGraph comes with some default nodes that could be useful for many cases:
- Interface (Widgets)
- Math (trigonometry, math operations)
- Audio (AudioAPI and MIDI)
- 3D Graphics (Postprocessing in WebGL)
- Input (read Gamepad)
Installation
You can install it using npm
npm install litegraph.js
Or downloading the build/litegraph.js
and css/litegraph.css
version from this repository.
First project
<html>
<head>
<link rel="stylesheet" type="text/css" href="litegraph.css">
<script type="text/javascript" src="litegraph.js"></script>
</head>
<body style='width:100%; height:100%'>
<canvas id='mycanvas' width='1024' height='720' style='border: 1px solid'></canvas>
<script>
var graph = new LGraph();
var canvas = new LGraphCanvas("#mycanvas", graph);
var node_const = LiteGraph.createNode("basic/const");
node_const.pos = [200,200];
graph.add(node_const);
node_const.setValue(4.5);
var node_watch = LiteGraph.createNode("basic/watch");
node_watch.pos = [700,200];
graph.add(node_watch);
node_const.connect(0, node_watch, 0 );
graph.start()
</script>
</body>
</html>
How to code a new Node type
Here is an example of how to build a node that sums two inputs:
//node constructor class
function MyAddNode()
{
this.addInput("A","number");
this.addInput("B","number");
this.addOutput("A+B","number");
this.properties = { precision: 1 };
}
//name to show
MyAddNode.title = "Sum";
//function to call when the node is executed
MyAddNode.prototype.onExecute = function()
{
var A = this.getInputData(0);
if( A === undefined )
A = 0;
var B = this.getInputData(1);
if( B === undefined )
B = 0;
this.setOutputData( 0, A + B );
}
//register in the system
LiteGraph.registerNodeType("basic/sum", MyAddNode );
or you can wrap an existing function:
function sum(a,b)
{
return a+b;
}
LiteGraph.wrapFunctionAsNode("math/sum",sum, ["Number","Number"],"Number");
Server side
It also works server-side using NodeJS although some nodes do not work in server (audio, graphics, input, etc).
var LiteGraph = require("./litegraph.js").LiteGraph;
var graph = new LiteGraph.LGraph();
var node_time = LiteGraph.createNode("basic/time");
graph.add(node_time);
var node_console = LiteGraph.createNode("basic/console");
node_console.mode = LiteGraph.ALWAYS;
graph.add(node_console);
node_time.connect( 0, node_console, 1 );
graph.start()
Litescene is a scene graph library for WebGL with a component based hierarchical node system. It comes with a realistic rendering pipeline and some interesting components to make it easier to build and share scenes. Component based node system Realistic rendering pipeline, it supports shadows, reflections, textures for all properties, etc Material system that automatically computes the best shader, making it easy to control properties Resources Manager to load and store any kind of resource ( textures, meshes, etc) Serializing methods to convert any Scene to JSON Parser for most common file formats Easy to embed It uses its own low-level library called litegl.js
Usage
Include the library and dependencies
<script src="external/gl-matrix-min.js"></script>
<script src="external/litegl.min.js"></script>
<script src="js/litescene.js"></script>
Create the context
var player = new LS.Player({
width:800, height:600,
resources: "resources/",
shaders: "data/shaders.xml"
});
Attach to Canvas to the DOM:
document.getElementById("mycontainer").appendChild( player.canvas )
or you can pass the canvas in the player settings as { canvas: my_canvas_element }
Load the scene and play it:
player.loadScene("scene.json");
Описание методов API
Все методы API сгруппированные по компонентам.
Контент
Название | Описание |
---|---|
content.get_ctypes | Возвращает все типы контента. |
content.get_datasets.CTYPE | Возвращает наборы для заданного типа контента. |
content.get_categories.CTYPE | Возвращает категории для заданного типа контента. |
content.get_fields.CTYPE | Возвращает поля записей для заданного типа контента. |
content.get_props.CTYPE | Возвращает свойства категорий для заданного типа контента. |
content.get_props_values.CTYPE | Возвращает значения свойств записи для заданного типа контента. |
content.get_folders.CTYPE | Возвращает папки записей для заданного типа контента. |
content.get.CTYPE | Возвращает записи для заданного типа контента. |
content.get_item.CTYPE | Возвращает одну запись для заданного типа контента. |
content.update_item.CTYPE | Редактирует одну запись для заданного типа контента. |
content.add_item.CTYPE | Добавляет запись в заданный тип контента. |
Примечание. CTYPE - название типа контента, например news, board, articles и т.д.
Авторизация и регистрация
Название | Описание |
---|---|
auth.signup_fields | Получает имена полей, обязательных для регистрации. |
auth.signup | Регистрирует нового пользователя. |
auth.confirm | Завершает регистрацию нового пользователя, начатую методом auth.signup. |
auth.restore | Отправка запроса на восстановление пароля пользователя. |
auth.login | Авторизация пользователя стандартным способом (используются cookie). |
auth.logout | Разавторизация пользователя. |
Пользователи
Название | Описание |
---|---|
users.get | Возвращает информацию о пользователях. |
users.get_sig | Возвращает SIG и csrf_token. |
users.add | Добавляет пользователя. |
users.get_groups | Возвращает все группы пользователей. |
users.add_to_groups | Добавляет пользователя в группы. |
users.remove_from_groups | Убирает пользователя из групп. |
Стена
Название | Описание |
---|---|
wall.get | Возвращает список записей со стены пользователя или группы. |
Комментарии
Название | Описание |
---|---|
comments.get | Получает комментарии. |
Личные сообщения
Название | Описание |
---|---|
messages.send | Отправляет сообщение. |
messages.delete_contact | Удаляет контакт. |
messages.delete_mesages | Удаляет сообщения. |
messages.delete_notice | Удаляет уведомления. |
messages.forgive | Прекращает игнорирование контакта. |
messages.ignore | Включает игнорирование контакта. |
messages.get | Возвращает список сообщений. |
messages.get_notices | Возвращает список уведомлений. |
messages.readed | Помечает сообщения как прочитанные. |
messages.restore_mesage | Восстанавливает сообщение. |
Местоположение
Название | Описание |
---|---|
geo.get | Возвращает список стран/регионов/городов. |
geo.get_current_country | Возвращает данные по текущей стране пользователя, если она была определена по его ip адресу. |
Загрузка изображений
Название | Описание |
---|---|
images.get_presets | Возвращает список всех доступных пресетов. |
images.upload | Загружает изображение. |
Общие методы
Название | Описание |
---|---|
execute | Универсальный метод, который позволяет запускать последовательность других методов, сохраняя промежуточные результаты и возвращая их все в одном ответе. |
JSON API
Описание
Компонент реализует легкое API между сайтом и сторонним сервисом, например, мобильным приложением. Компонент позволяет вести логи ошибок и успешных запросов, выводя их в диаграмме на главной страницы админ-панели. В основном, синтаксис запросов и формат ответов схож с официальными API. Это сделано специально, для более легкого понимания интеграторами. Ответы API возвращаются только в JSON формате.
Настройки
Логировать запросы с ошибками
Включает логирование ошибочных запросов.
Логировать успешные запросы
Включает логирование успешных запросов. Внимание! Фиксируется каждый запрос к API.
Для каждого тип запроса фиксируется:
-
id ключа;
-
Название метода API;
-
Код ошибки, при наличии таковой;
-
Дата запроса;
-
Время, потраченное на обработку запроса.
Авторизация
Все запросы к API подписываются ключом доступа, который создаётся в админ-панели компонента. Для запросов чтения этого достаточно. Ключ API можете передаваться как в POST/GET параметре, так и в заголовке запроса с именем api_key
. Длина ключа может быть не более 32 символов. При создании ключ генерируется автоматически, однако его можно вручную изменить. Каждый ключ можно ограничить по ip адресу, временно выключить.
Для каждого ключа можно задать ограничения по ip адресам и по методам, которые будут доступны для данного ключа.
Другие методы авторизации и подписывания запросов, а также механизм авторизации пользователей - в разработке.
Синтаксис запроса
Чтобы обратиться к любому методу API (за исключением метода execute, о нём ниже), вам необходимо выполнить POST или GET запрос такого вида:
http://this.site/api/method/METHOD_NAME?PARAMETERS&api_key=API_KEY
Он состоит из нескольких частей:
-
METHOD_NAME (обязательно) — название метода API, к которому Вы хотите обратиться. Полный список методов доступен на этой странице.
-
PARAMETERS (опционально) — входные параметры соответствующего метода API, последовательность пар name=value, разделенных амперсандом. Список параметров указан на странице с описанием метода. Значения параметров должны быть в кодировке UTF-8.
-
API_KEY — ключ доступа.
Параметры могут передаваться как методом GET, так и POST. Если вы будете передавать большие данные (больше 2 килобайт), следует использовать POST.
Формат METHOD_NAME состоит из названия контроллера, названия экшена и параметров экшена, что в целом схоже с основным роутингом InstantCMS. Контроллер, экшен и параметры разделены символом ».» (точка). Например, мы имеем METHOD_NAME с названием content.get_datasets.articles
:
-
content - название контроллера (компонента);
-
get_datasets - действие (экшен) контроллера;
-
articles - первый параметр этого действия.
Например, вызовем метод content.get_datasets.articles
, чтобы получить список всех наборов типа контента с названием articles и укажем в параметре, что нам нужно вернуть все наборы, включая скрытые:
http://this.site/api/method/content.get_datasets.articles?api_key=API_KEY&show_all=1
Вы получите ответ в формате JSON (часть ответа скрыта в примере, чтобы не загромождать):
{ "response":{ "count":5, "items":{ "all":{ "id":"1", "ctype_id":"5", "name":"all", "title":"Все", "description":null, "ordering":"1", "is_visible":"1", "filters":[ ], "sorting":[ ], "index":"date_pub", "groups_view":[ ], "groups_hide":[ ], "seo_keys":null, "seo_desc":null }, "reviews":{ }, "translations":{ }, "featured":{ }, "rating":{ } } } }
Обратите внимание, ответы возвращаются только в формате JSON.
Компонент также поддерживает универсальный метод, который позволяет запускать последовательность других методов, сохраняя промежуточные результаты и возвращая их все в одном ответе. Внимание! Запрос будет иметь другой базовый вид:
http://this.site/api/execute?PARAMETERS&api_key=API_KEY
Разбивка на страницы
В ответах, где отдаётся список чего-либо с возможностью разбивки на страницы, присутствует объект paging, содержащий ячейки:
-
has_next (true или false) - флаг наличия следующей страницы;
-
page - номер текущей страницы;
-
per_page - количество элементов на одну страницу.
Определение IP адреса посетителя
В случае, если запросы к api выполняются из одного места, например из скрипта PHP на сервере, но при этом необходимо, чтобы ip адрес посетителей учитывался в API, вы можете передавать ip адрес в параметре запроса с названием ip, например:
http://this.site/api/method/METHOD_NAME?PARAMETERS&api_key=API_KEY&ip=8.8.8.8
Обработка ошибок
На все запросы к методам
this.site/api/method/
и/api/execute/
, включая запросы с ошибками возвращают HTTP CODE 200. Ошибки генерируются в JSON ответе специальным образом:
{ "error":{ "error_code":101, "error_msg":"Неверный ключ доступа", "request_params":[ ] } }
Коды ошибок (error_code). В ячейке error_msg указывается текстовое представление ошибки на выбранном языке. В некоторых сообщениях об ошибках присутствует непустое поле request_params с массивом названий параметров и ошибками их валидации.
Код | Описание |
---|---|
1 | Произошла неизвестная ошибка |
2 | Ключ доступа выключен |
3 | Передан неизвестный метод |
5 | Авторизация пользователя не удалась |
7 | Нет прав для выполнения этого действия |
71 | Требуется авторизация пользователя |
710 | Требуется административный доступ |
8 | Неверный запрос |
15 | Доступ запрещён |
115 | Параметр sig не передан или является некорректным |
23 | Метод был выключен |
24 | Метод вам недоступен |
100 | Один из необходимых параметров был не передан или неверен |
101 | Неверный ключ доступа |
115 | Параметр sig не передан или является некорректным |
777 | ip адрес посетителя передан некорректный |
Список методов API
Разработчикам методов
Разработка методов API для ваших компонентов достаточно проста. Весь процесс разработки метода сводится к созданию специального экшена или хука, на ваш выбор.
Метод как экшен
Компонент InstantCMS API поддерживает только внешние экшены контроллера. Например, мы хотим создать экшен для метода API youcontroller.list_items
, который будет отдавать нам список неких записей. Механизм формирования названия экшена такой:
api_youcontroller_list_items
Файл экшена будет называться соответственно:
api_youcontroller_list_items.php
И располагаться по пути /system/controllers/youcontroller/actions/api_youcontroller_list_items.php
.
Далее создаётся код экшена стандартным способом, но с некоторыми обязательными свойствами:
api_youcontroller_list_items.php
class actionYoucontrollerApiYoucontrollerListItems extends cmsAction { /** * Блокировка прямого вызова экшена * обязательное свойство * @var boolean */ public $lock_explicit_call = true; /** * Результат запроса * обязательное свойство * @var array */ public $result; /** * Массив названий ячеек * которые нужно удалить из результирующего массива * необязательное свойство * @var array */ public $unset_fields; /** * Флаг, обязующий проверять параметр sig запроса * sig привязан к домену сайта и к ip адресу посетителя * @var boolean */ public $check_sig = false; /** * Флаг, обязующий проверять авторизацию пользователя * @var boolean */ public $auth_required = false; /** * Флаг, обязующий проверять авторизацию пользователя * И принадлежность пользователя к административному доступу * @var boolean */ public $admin_required = false; /** * Возможные параметры запроса * с правилами валидации * Если запрос имеет параметры, необходимо описать их здесь * Правила валидации параметров задаются по аналогии с полями форм * @var array */ public $request_params = array(); /** * Необязательный метод проверки запроса * В нём выполняются некий действия по валидации * возвращает либо false в случае успешной проверки * либо массив данных ошибки */ public function validateApiRequest() { return false; } /** * Основной метод работы экшена * Его задача заполнить свойство $this->result */ public function run(){ $this->result = array('items' => array()); } }
Метод как хук
Отличие это варианта лишь в расположении файла и именовании класса. Учитывая пример выше, в этом случае файл хука должен быть расположен по пути:
/system/controllers/youcontroller/hooks/api_youcontroller_list_items.php
А класс называться:
class onYoucontrollerApiYoucontrollerListItems extends cmsAction {}
plantas.vip namapi.org kivie.in (176.114.8.35)
root@plantas:~# nmap plantas.vip
Starting Nmap 7.70 ( https://nmap.org ) at 2021-05-04 08:39 EEST
Nmap scan report for plantas.vip (176.114.8.35)
Host is up (0.000011s latency).
Not shown: 982 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
25/tcp open smtp
80/tcp open http
110/tcp open pop3
111/tcp open rpcbind
143/tcp open imap
389/tcp open ldap
443/tcp open https
465/tcp open smtps
587/tcp open submission
636/tcp open ldapssl
993/tcp open imaps
995/tcp open pop3s
2049/tcp open nfs
3306/tcp open mysql
8000/tcp open shoutcast
8001/tcp open shoutcast-oni
Nmap done: 1 IP address (1 host up) scanned in 1.69 seconds
namapi.com kivie.in plantas.vip
namapi.org kivie.in plantas.vip
$TTL 300 @ IN SOA ns11.rehost.com.ua. hostmaster.redo.com.ua. ( 2021062601 10000 2400 604800 3600 ) plantas.vip. 300 IN NS ns11.rehost.com.ua. plantas.vip. 300 IN NS ns12.rehost.com.ua. 3de 300 IN A 176.114.8.35 @ 300 IN A 176.114.8.35 avahi 300 IN A 176.114.8.35 dev 300 IN A 176.114.8.35 display 300 IN A 176.114.8.35 fish 300 IN A 176.114.8.35 ftp 300 IN A 176.114.8.35 ga 300 IN A 176.114.8.35 gw 300 IN A 176.114.8.35 hidden 300 IN A 176.114.8.35 i02 300 IN A 185.227.110.250 i03 300 IN A 93.77.9.9 i04 300 IN A 62.173.154.124 i05 300 IN A 176.114.8.35 icms 300 IN A 176.114.8.35 imap 300 IN A 176.114.8.35 imaps 300 IN A 176.114.8.35 info 300 IN A 176.114.8.35 iss 300 IN A 176.114.8.35 ldap 300 IN A 176.114.8.35 ldaps 300 IN A 176.114.8.35 localhost 300 IN A 127.0.0.1 plantas.vip. 300 IN A 176.114.8.35 lt 300 IN A 212.122.95.230 mail 300 IN A 176.114.8.35 mysql 300 IN A 176.114.8.35 pop3 300 IN A 176.114.8.35 pop3s 300 IN A 176.114.8.35 ppp 300 IN A 176.114.8.35 pptp 300 IN A 176.114.8.35 radio 300 IN A 176.114.8.35 scast 300 IN A 176.114.8.35 select 300 IN A 176.114.8.35 server 300 IN A 176.114.8.35 smtp 300 IN A 176.114.8.35 smtps 300 IN A 176.114.8.35 system 300 IN A 176.114.8.35 test 300 IN A 176.114.8.35 tunnel 300 IN A 176.114.8.35 ua 300 IN A 176.114.8.35 www 300 IN A 176.114.8.35 yp 300 IN A 176.114.8.35 plantas.vip. 300 IN MX 10 mail _domainkey 300 IN TXT "o=~" plantas.vip. 300 IN TXT "google-site-verification=r79b78hjmpWudRnH3TJ7cqHEXTknZVu8yc60pGPLlvQ" plantas.vip. 300 IN TXT "v=spf1 a mx ip4:176.114.8.35 ~all" x._domainkey 300 IN TXT ( "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+pirySc0Tpj1fjGpIi6pEEcxs36GMhTrdYVk7K4DgE6zgNvJF8GUMmNZlnqwCM+ZLG9VJqhhMrX8C1HAPofmn6" "cVwdP4mcwHINlZsFOGjp9YR/5nncdj11cxNYPZ1vb7V5T8PIcMm+e+GeEWOWZCQ8Ei+gBxpADl2oCjtVzUUcllc77bx8+YIHOHOUfnPo8o+cqQFzKWimCw35Jre+gHQXiP1qUL0HVsQJJIxxfQmGFy" "WJf49VDYUuykzAC/fStxoTvyhzXt5QZo1EgJVsNOQ6x9MnmYKokqtMVjADjbhesT1ncPMrHgg8Yp4ctf4+ga9L8gVoCtSAxisAbzzNuNwIDAQAB" )