Advertisement
Guest User

Untitled

a guest
Nov 23rd, 2016
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 53.46 KB | None | 0 0
  1. helpChannelsId: { title: 'Support Channels - IDs (comma separated)', type: 'string' },
  2. helpGroupsId: { title: 'Support Members - GroupsID (comma separated)', type: 'string' },
  3. helpIgnoredGroupsId: { title: 'Group ignored on support channels - GroupsID (comma separated)', type: 'string' },
  4. helpCloseNoStaff: {title: 'Should support channels should be closed when no staff online?', type: 'select',
  5. options: ['Yes', 'No']},
  6. helpAwayMode: {title: 'Should staff with away status be excluded from online support?', type: 'select',
  7. options: ['Yes', 'No']},
  8. helpClosePrefix: {title: 'Prefix added to channel name when closed (must be short, because of chars limit)', type: 'string',
  9. placeholder: '(Closed)'},
  10. helpUserNotification: {title: 'Message to user waiting support - s0 for Username, s1 for Staff Online', type: 'string',
  11. placeholder: 'Hi [b]s0[/b]! Staff member will help you soon! [b]Online staff:[/b] s1'},
  12. helpUserNotification2: {title: 'Message to user when no staff online - s0 for Username', type: 'string',
  13. placeholder: 'Hi [b]s0[/b]! Sorry, but all our staff is offline come back later.'},
  14. helpStaffNotification: {title: 'Message to staff - s0 for Username, s1 for Staff Online', type: 'string',
  15. placeholder: 'User [b]s0[/b] is waiting in support zone! [b]Online staff:[/b] s1'},
  16. helpStaffAway: {title: 'Message to user after Staff Away Time passed about staff currently busy', type: 'string',
  17. placeholder: 'Sorry! Our staff is currently busy. They will contact you as soon as possible.'},
  18. helpStaffAwayTime: {title: 'Timer after with user will get notification about staff is busy right now in seconds (0 to disable)', type: 'number',
  19. placeholder: 'Default 60 seconds'},
  20. helpStaffJoined: {title: 'Message to staff when someone of them join to help user - s0 for Username of helper, s1 for Username of user', type: 'string',
  21. placeholder: 'Staff member [b]s0[/b] joined to help [b]s1[/b].'},
  22. staffJoinSupport: {title: 'Send message to whole staff when one of them help start to help waiting user?', type: 'select',
  23. options: ['Yes','No']},
  24. helpStaffNotificationType: {title: 'Support (staff users) notification type', type: 'select',
  25. options: ['Chat','Poke']},
  26. helpUsersNotificationType: {title: 'Support (normal users) notification type', type: 'select',
  27. options: ['Chat','Poke']},
  28. autoTempChannelsId: {title: 'Auto temporary channels (comma separated)', type: 'string' },
  29. autoTempChannelsParentId: {title: 'Auto temporary channels parent', type: 'channel' },
  30. autoTempChannelsRestrictedGroups: {title: 'Groups that are not allowed to get temporary channels - IDs (comma separated)', type: 'string'},
  31. autoTempChannelsName: {title: 'Automatic temporary channel name - s0 is channel number', type: 'string',
  32. placeholder: 'Temporary Channel s0'},
  33. autoTempChannelsMessage: {title: 'Message to user about auto temporary chanel get created', type: 'string',
  34. placeholder: 'I created temporary channel as you wish!'},
  35. autoTempChannelsPassMessage: {title: 'Message to user about auto temporary chanel password - s0 is password', type: 'string',
  36. placeholder: 'Your channel password: [b]s0[/b]'},
  37. autoTempChannelsPass: {title: 'Automatic temporary channels with password?', type: 'select',
  38. options: ['Yes', 'No']},
  39. autoTempChannelsPassLength: {title: 'Automatic temporary channel password length', type: 'number',
  40. placeholder: '4'},
  41. autoTempChannelsRestricted: {title: 'Message when users is not permitted do get temporary channel', type: 'string',
  42. placeholder: 'Sorry! You are not allowed to get temporary channel.'},
  43. autoTempChannelsErrorMessage: {title: 'Message to user about auto temp channel creation error', type: 'string',
  44. placeholder: "I can't created temporary channel for you right now, try later."},
  45. botChecksEvery: {title: 'Every x seconds bot will do checks (optimal is 60)', type: 'number'},
  46. botAIPrivateChat: {title: 'Should bot use his AI to replay for private chat messages to user?', type: 'select',
  47. options: ['Yes', 'No']},
  48. botAIPoke: {title: 'Should bot use his AI to replay for poke messages to user?', type: 'select',
  49. options: ['Yes', 'No']},
  50. onlineUsersChannelId: {title: 'Channel with name update for online users information', type: 'channel'},
  51. onlineUsersChannel: {title: 'Name of auto online channel - s0 is online number', type: 'string',
  52. placeholder: "Users Online: s0"},
  53. maxOnlineUsersChannelId: {title: 'Channel with name update for max online users information', type: 'channel'},
  54. maxOnlineUsersChannel: {title: 'Name of auto max online channel - s0 is for max online number', type: 'string',
  55. placeholder: "Max Users Online: s0"},
  56. maxOnlineUsersChannelDesc: {title: 'Desc of max channel - s0 is for record date', type: 'string',
  57. placeholder: "Last record date: s0"},
  58. staffOnlineChannelId: {title: 'Channel with name update for staff online information', type: 'channel'},
  59. staffOnlineChannelName: {title: 'Name of staff online channel - s0 is online number', type: 'string',
  60. placeholder: "Staff Online: s0"},
  61. staffOnlineChannelSublist: {title: 'Turn on or off staff list by subchannels', type: 'select',
  62. options: ['On', 'Off']},
  63. staffOnlineChannelZero: {title: 'When none admins are online text - can be 0', type: 'string',
  64. placeholder: "none"},
  65. staffOnlineChannelDesc: {title: 'Desc of staff online channel - s0 is nicname, s1 is group', type: 'string',
  66. placeholder: "s0 - s1 is online"},
  67. registerGroupId: {title: 'Registration Group Id', type: 'number'},
  68. registerWelcomeMessage: {title: 'Welcome message for user without register group', type: 'multiline'},
  69. registerMessageType: {title: 'Type of message poke or chat', type: 'select',
  70. options: ['Poke', 'Chat']},
  71. registerMessageOn: {title: 'Turn on or off welcome message poke or chat', type: 'select',
  72. options: ['On', 'Off']},
  73. autoMusicCodecBot: {title: 'Change codec of channel to music when bot joins?', type: 'select',
  74. options: ['On', 'Off']},
  75. autoMusicCodecNew: {title: 'Codec and quality to set on channel with bot joins - syntax: "codecId#quality", example for opus music "5#10"', type: 'string',
  76. placeholder: '5#10'},
  77. clockChannel: {title: 'Channel for clock display', type: 'channel'},
  78. clockFormat: {title: 'Format of clock - s0 day, s1 month, s2 year, s3 hour, s4 minute', type: 'string',
  79. placeholder: "[cspacer*] s3:s4 | s0.s1.s2"},
  80. clockTimezone: {title: 'Select clock timezone offset from UTC (type number like 2 or -2 etc.)', type: 'string',
  81. placeholder: "0"}
  82. }
  83. },
  84. function(sinusbot, config, info) {
  85. sinusbot.log('Loading ' + info.name + ' version: ' + info.version + ' - powered by ' + info.author);
  86. sinusbot.log('Do not forget to check all settings!');
  87.  
  88. sinusbot.setVar('staff', []);
  89. sinusbot.setVar('onChannelCreate', []);
  90. sinusbot.setVar('onlineClients', 1);
  91. sinusbot.setVar('usersOnHelp', []);
  92. sinusbot.setVar('channelCodec', []);
  93. sinusbot.setVar('botMove' + self, {});
  94. sinusbot.setVar("helpClosed", 0);
  95.  
  96. var self = sinusbot.getBotId();
  97. var staff = sinusbot.getVar('staff');
  98.  
  99. //Defaults values handling
  100. if (isUndefined(config.helpChannelsId))
  101. config.helpChannelsId = -1;
  102. if (isUndefined(config.helpGroupsId))
  103. config.helpGroupsId = -1;
  104. if (isUndefined(config.helpIgnoredGroupsId))
  105. config.helpIgnoredGroupsId = -1;
  106. if (isUndefined(config.helpStaffAwayTime) || config.helpStaffAwayTime < 0)
  107. config.helpStaffAwayTime = 60;
  108. if (isUndefined(config.autoTempChannelsId))
  109. config.autoTempChannelsId = -1;
  110. if (isUndefined(config.autoTempChannelsParentId) || parseInt(config.autoTempChannelsParentId) < 0)
  111. config.autoTempChannelsParentId = 0;
  112. if (isUndefined(config.autoTempChannelsRestrictedGroups))
  113. config.autoTempChannelsRestrictedGroups = -1;
  114. if (isUndefined(config.autoTempChannelsPass))
  115. config.autoTempChannelsPass = 1;
  116. if (isUndefined(config.autoTempChannelsPassLength) || config.autoTempChannelsPassLength < 0)
  117. config.autoTempChannelsPassLength = 4;
  118. if (isUndefined(config.botChecksEvery) || config.botChecksEvery < 0)
  119. config.botChecksEvery = 60;
  120. if (isUndefined(config.helpCloseNoStaff))
  121. config.helpCloseNoStaff = 1;
  122. if (isUndefined(config.helpAwayMode))
  123. config.helpAwayMode = 1;
  124. if (isUndefined(config.staffJoinSupport))
  125. config.staffJoinSupport = 1;
  126. if (isUndefined(config.staffOnlineChannelSublist))
  127. config.staffOnlineChannelSublist = 1;
  128. if (isUndefined(config.helpStaffNotificationType))
  129. config.helpStaffNotificationType = 0;
  130. if (isUndefined(config.helpUsersNotificationType))
  131. config.helpUsersNotificationType = 0;
  132. if (isUndefined(config.botAIPrivateChat))
  133. config.botAIPrivateChat = 1;
  134. if (isUndefined(config.botAIPoke))
  135. config.botAIPoke = 1;
  136. if (isUndefined(config.registerMessageType))
  137. config.registerMessageType = 1;
  138. if (isUndefined(config.registerMessageOn))
  139. config.registerMessageOn = 1;
  140. if (isUndefined(config.autoMusicCodecBot))
  141. config.autoMusicCodecBot = 1;
  142. if (isUndefined(config.clockChannel))
  143. config.clockChannel = -1;
  144. if (isUndefined(config.clockTimezone))
  145. config.clockTimezone = 0;
  146. if (isUndefined(sinusbot.getVar("maxOnlineRecord")))
  147. sinusbot.setVar("maxOnlineRecord", 0);
  148. if (isUndefined(sinusbot.getVar("tempChannels")))
  149. sinusbot.setVar("tempChannels", []);
  150. if (isUndefined(config.helpClosePrefix))
  151. config.helpClosePrefix = "(Closed)";
  152. if (isUndefined(config.helpUserNotification))
  153. config.helpUserNotification = "Hi [b]s0[/b]! Staff member will help you soon! [b]Online staff:[/b] s1";
  154. if (isUndefined(config.helpUserNotification2))
  155. config.helpUserNotification2 = "Hi [b]s0[/b]! Sorry, but all our staff is offline come back later.";
  156. if (isUndefined(config.helpStaffNotification))
  157. config.helpStaffNotification = "User [b]s0[/b] is waiting in support zone! [b]Online staff:[/b] s1";
  158. if (isUndefined(config.helpStaffAway))
  159. config.helpStaffAway = "Sorry! Our staff is currently busy. They will contact you as soon as possible.";
  160. if (isUndefined(config.helpStaffJoined))
  161. config.helpStaffJoined = "Staff member [b]s0[/b] joined to help [b]s1[/b].";
  162. if (isUndefined(config.autoTempChannelsName))
  163. config.autoTempChannelsName = "Temporary Channel s0";
  164. if (isUndefined(config.autoTempChannelsMessage))
  165. config.autoTempChannelsMessage = "I created temporary channel as you wish!";
  166. if (isUndefined(config.autoTempChannelsPassMessage))
  167. config.autoTempChannelsPassMessage = "Your channel password: [b]s0[/b]";
  168. if (isUndefined(config.autoTempChannelsRestricted))
  169. config.autoTempChannelsRestricted = "Sorry! You are not allowed to get temporary channel.";
  170. if (isUndefined(config.autoTempChannelsErrorMessage))
  171. config.autoTempChannelsErrorMessage = "I can't created temporary channel for you right now, try later.";
  172. if (isUndefined(config.onlineUsersChannel))
  173. config.onlineUsersChannel = "Users Online: s0";
  174. if (isUndefined(config.maxOnlineUsersChannel))
  175. config.maxOnlineUsersChannel = "Max Users Online: s0";
  176. if (isUndefined(config.maxOnlineUsersChannelDesc))
  177. config.maxOnlineUsersChannelDesc = "Last record date: s0";
  178. if (isUndefined(config.staffOnlineChannelName))
  179. config.staffOnlineChannelName = "Staff Online: s0";
  180. if (isUndefined(config.staffOnlineChannelZero))
  181. config.staffOnlineChannelZero = "none";
  182. if (isUndefined(config.staffOnlineChannelDesc))
  183. config.staffOnlineChannelDesc = "s0 - s1 is online";
  184. if (isUndefined(config.autoMusicCodecNew))
  185. config.autoMusicCodecNew = '5#10';
  186. if (isUndefined(config.clockFormat))
  187. config.clockFormat = "[cspacer*] s3:s4 | s0.s1.s2";
  188.  
  189. try {
  190. var helpChannelsId = config.helpChannelsId.toString().split(',');
  191. var helpGroupsId = config.helpGroupsId.toString().split(',');
  192. var helpIgnoredGroupsId = config.helpIgnoredGroupsId.toString().split(',');
  193. var autoTempChannelsId = config.autoTempChannelsId.toString().split(',');
  194. var autoTempChannelsRestrictedGroups = config.autoTempChannelsRestrictedGroups.toString().split(',');
  195. var autoMusicCodecNew = config.autoMusicCodecNew.toString().split('#');
  196. } catch (e) {
  197. sinusbot.log('Your configuration is wrong! Check if you typed correct values.');
  198. sinusbot.log('START - Error code: ' + e);
  199. sinusbot.log('Line: ' + e.lineNumber + ' Column: ' + e.columnNumber);
  200. sinusbot.log('Setting1: ' + config.helpChannelsId);
  201. sinusbot.log('Setting2: ' + config.helpGroupsId);
  202. sinusbot.log('Setting3: ' + config.helpIgnoredGroupsId);
  203. sinusbot.log('Setting4: ' + config.autoTempChannelsId);
  204. sinusbot.log('Setting5: ' + config.autoTempChannelsRestrictedGroups);
  205. sinusbot.log('Setting6: ' + config.autoMusicCodecNew);
  206. sinusbot.log('END ---------------------- END');
  207.  
  208. //Temp again defaults
  209. helpChannelsId = -1;
  210. helpGroupsId = -1;
  211. helpIgnoredGroupsId = -1;
  212. autoTempChannelsId = -1;
  213. autoTempChannelsRestrictedGroups = -1;
  214. autoMusicCodecNew = [5,10];
  215. }
  216.  
  217. /*
  218. Support Channels auto poke function event section
  219. */
  220. sinusbot.on('clientMove', function (e) {
  221. var isStaff = haveGroupFromArray(e, helpGroupsId);
  222. var isHelpClosed = sinusbot.getVar('helpClosed');
  223. var isIgnored = haveGroupFromArray(e, helpIgnoredGroupsId);
  224. var staff = sinusbot.getVar('staff');
  225. var usersOnHelp = sinusbot.getVar('usersOnHelp');
  226.  
  227. if(config.helpAwayMode == 0 && e.client.away == 1)
  228. isStaff = false;
  229.  
  230. var objectId = getObjectIdArray(staff, e.clientId);
  231.  
  232. if (isStaff != false) {
  233.  
  234. for (var i = 0; i < staff.length; i++) {
  235. if (getUserChannelId(staff[i].id) == 0) {
  236. if(config.staffOnlineChannelSublist == 0) {
  237. var channelId = getChannelId(staff[i].nick + ' | ' + staff[i].groups.n, config.staffOnlineChannelId);
  238. }
  239. staff.splice(i, 1);
  240. if(!isUndefined(channelId))
  241. {
  242. channelDelete(channelId, true);
  243. }
  244. }
  245. }
  246.  
  247. if (objectId == -1) {
  248. var group = haveGroupFromArray(e, helpGroupsId);
  249. staff.push({id: e.clientId, uuid: e.clientUid, nick: e.clientNick, groups: group});
  250. if(config.staffOnlineChannelSublist == 0) {
  251. var channel = {
  252. name: e.clientNick + ' | ' + group.n,
  253. parent: config.staffOnlineChannelId,
  254. topic: e.clientNick + ' | ' + group.n,
  255. description: '[URL=client://0/' + e.clientUid + ']' + e.clientNick + '[/URL] | ' + group.n +
  256. ' - [COLOR=#00aa00]online![/COLOR]',
  257. enc: 1,
  258. perm: 0,
  259. sperm: 1,
  260. maxClients: 0,
  261. default: 0
  262. };
  263. channelCreate(channel);
  264. }
  265. }
  266. } else if (objectId >= 0) {
  267. if(config.staffOnlineChannelSublist == 0) {
  268. var channelId = getChannelId(staff[objectId].nick + ' | ' + staff[objectId].groups.n, config.staffOnlineChannelId);
  269. }
  270. staff.splice(objectId, 1);
  271. if(!isUndefined(channelId)) {
  272. channelDelete(channelId, true);
  273. }
  274. }
  275.  
  276. if(config.helpCloseNoStaff == 0) {
  277. if (staff.length == 0 && isHelpClosed == 0) {
  278. for (var i = 0; i < helpChannelsId.length; i++) {
  279. var channel = getChannelParams(parseInt(helpChannelsId[i]));
  280. if (channel == false)
  281. continue;
  282. var newName = config.helpClosePrefix + channel.name;
  283. channelUpdate(channel.id, {name: newName, maxClients: 0});
  284. }
  285. sinusbot.setVar('helpClosed', 1);
  286. } else if (staff.length > 0 && isHelpClosed == 1) {
  287. for (var i = 0; i < helpChannelsId.length; i++) {
  288. var channel = getChannelParams(parseInt(helpChannelsId[i]));
  289. if (channel == false)
  290. continue;
  291. var newName = channel.name.substring(config.helpClosePrefix.length);
  292. channelUpdate(channel.id, {name: newName, maxClients: -1});
  293. }
  294. sinusbot.setVar('helpClosed', 0);
  295. }
  296. }
  297.  
  298. sinusbot.setVar('staff', staff);
  299.  
  300. if (isChannelInArray(e.newChannel, helpChannelsId)) {
  301. if (isIgnored == false) {
  302. if (isUndefined(staff) || staff.length <= 0) {
  303. sendUserNotification(config.helpUsersNotificationType, e.clientId, replaceSNVariables(config.helpUserNotification2, e.clientNick));
  304. usersOnHelp.push({
  305. clientId: e.clientId,
  306. clientUid: e.clientUid,
  307. clientNick: e.clientNick,
  308. newChannel: e.newChannel,
  309. oldChannel: e.oldChannel,
  310. action: 1,
  311. staffReaction: false
  312. });
  313. } else {
  314. for (var i = 0; i < staff.length; i++) {
  315. var message = replaceSNVariables(config.helpStaffNotification, e.clientNick, staff.length);
  316. if (config.helpStaffNotificationType == 0) {
  317. message = replaceSNVariables(
  318. config.helpStaffNotification,
  319. '[URL=client://0/' + e.clientUid + ']' + e.clientNick + '[/URL]',
  320. staff.length
  321. );
  322. }
  323. sendUserNotification(config.helpStaffNotificationType, staff[i].id, message);
  324. }
  325. sendUserNotification(config.helpUsersNotificationType, e.clientId, replaceSNVariables(config.helpUserNotification, e.clientNick, staff.length));
  326. usersOnHelp.push({
  327. clientId: e.clientId,
  328. clientUid: e.clientUid,
  329. clientNick: e.clientNick,
  330. newChannel: e.newChannel,
  331. oldChannel: e.oldChannel,
  332. action: 2,
  333. staffReaction: false
  334. });
  335. if (config.helpStaffAwayTime > 0) {
  336. setTimeout(function () {
  337. var userOnHelpF = sinusbot.getVar('usersOnHelp');
  338. for (var i = 0; i < userOnHelpF.length; i++) {
  339. var user = userOnHelpF[i];
  340. if (user.clientId == e.clientId && user.staffReaction != true) {
  341. sendUserNotification(config.helpUsersNotificationType, e.clientId, config.helpStaffAway);
  342. }
  343. }
  344. }, 1000 * config.helpStaffAwayTime);
  345. }
  346. }
  347. sinusbot.setVar('usersOnHelp', usersOnHelp);
  348.  
  349. } else {
  350. for (var i = 0; i < usersOnHelp.length; i++) {
  351. var user = usersOnHelp[i];
  352. if (user.newChannel == e.newChannel && user.staffReaction != true) {
  353. if(config.staffJoinSupport == 0) {
  354. for (var i = 0; i < staff.length; i++) {
  355. if (staff[i].id != e.clientId) {
  356. var message = replaceSNVariables(config.helpStaffJoined, e.clientNick, user.clientNick);
  357. if (config.helpStaffNotificationType == 0) {
  358. message = replaceSNVariables(
  359. config.helpStaffJoined,
  360. '[URL=client://0/' + e.clientUid + ']' + e.clientNick + '[/URL]',
  361. '[URL=client://0/' + user.clientUid + ']' + user.clientNick + '[/URL]'
  362. );
  363. }
  364. sendUserNotification(config.helpStaffNotificationType, staff[i].id, message);
  365. }
  366. }
  367. }
  368. user.staffReaction = true;
  369. usersOnHelp[i] = user;
  370. }
  371. }
  372. sinusbot.setVar('usersOnHelp', usersOnHelp);
  373. }
  374. } else if (isChannelInArray(e.oldChannel, helpChannelsId)) {
  375. if (isIgnored == false) {
  376. for (var i = 0; i < usersOnHelp.length; i++) {
  377. var user = usersOnHelp[i];
  378. if (user.clientId == e.clientId && user.oldChannel == e.oldChannel) {
  379. usersOnHelp.splice(i, 1);
  380. }
  381. }
  382. sinusbot.setVar('usersOnHelp', usersOnHelp);
  383. }
  384. }
  385.  
  386. });
  387. /*
  388. //END Support Channels auto poke function section //END
  389. */
  390.  
  391. /*
  392. Automatic temporary channel events section
  393. */
  394. sinusbot.on('clientMove', function (e) {
  395. if (isChannelInArray(e.newChannel, autoTempChannelsId)) {
  396. if (haveGroupFromArray(e, autoTempChannelsRestrictedGroups) == false) {
  397. var autoTempChannelParentId = parseInt(config.autoTempChannelsParentId);
  398. var channelName = config.autoTempChannelsName;
  399. var channelPassword = randomString(config.autoTempChannelsPassLength, '#');
  400.  
  401. for (var i = 1; i <= 1000; i++) {
  402. var tempChannelName = replaceSNVariables(channelName, i);
  403.  
  404. if (getChannelId(tempChannelName, autoTempChannelParentId) == false) {
  405. channelName = tempChannelName;
  406. break;
  407. }
  408. }
  409.  
  410. var channel = {
  411. name: channelName,
  412. parent: autoTempChannelParentId,
  413. password: channelPassword,
  414. topic: e.clientNick,
  415. enc: 1,
  416. perm: 0,
  417. sperm: 1,
  418. default: 0
  419. };
  420.  
  421. var channelCreated = {
  422. channelName: channelName,
  423. channelParentId: autoTempChannelParentId,
  424. creator: e,
  425. password: channelPassword
  426. };
  427.  
  428. if(config.autoTempChannelsPass == 1) {
  429. channel.password = '';
  430. channelCreated.password = '';
  431. }
  432.  
  433. channelCreate(channel);
  434.  
  435. var onChannelCreate = sinusbot.getVar("onChannelCreate");
  436.  
  437. if (!isUndefined(onChannelCreate) && onChannelCreate.indexOf(channelCreated) == -1) {
  438. onChannelCreate.push(channelCreated);
  439. sinusbot.setVar("onChannelCreate", onChannelCreate);
  440. } else {
  441. sinusbot.log('Something goes wrong when adding you new channel to event list checks!');
  442. }
  443. } else {
  444. chatPrivate(e.clientId, config.autoTempChannelsRestricted);
  445. }
  446. }
  447. });
  448.  
  449. sinusbot.on('channelCreate', function (channel) {
  450. var onChannelCreate = sinusbot.getVar("onChannelCreate");
  451. if(!isUndefined(onChannelCreate) && !isEmpty(onChannelCreate)) {
  452. for (var i = 0; i < onChannelCreate.length; i++) {
  453. if (onChannelCreate[i].channelName == channel.name && onChannelCreate[i].channelParentId == channel.parent) {
  454. if (channel.id > 0) {
  455. var tempChannels = sinusbot.getVar("tempChannels");
  456.  
  457. sinusbot.log('Temp channel ' + channel.name + ' ID: ' + channel.id + ' was created by ' + onChannelCreate[i].creator.clientId + "@" + onChannelCreate[i].creator.clientNick);
  458. tempChannels.push(channel.id);
  459. sinusbot.setVar("tempChannels", tempChannels);
  460. move(onChannelCreate[i].creator.clientId, channel.id);
  461. chatPrivate(onChannelCreate[i].creator.clientId, config.autoTempChannelsMessage);
  462. if (config.autoTempChannelsPass == 0) {
  463. chatPrivate(onChannelCreate[i].creator.clientId, replaceSNVariables(config.autoTempChannelsPassMessage, onChannelCreate[i].password));
  464. }
  465. } else {
  466. sinusbot.log('Something goes wrong when creating auto temp channel! ' + channel.id);
  467. chatPrivate(onChannelCreate[i].creator.clientId, config.autoTempChannelsErrorMessage);
  468. }
  469.  
  470. onChannelCreate.splice(i, 1);
  471. sinusbot.setVar("onChannelCreate", onChannelCreate);
  472. break;
  473. }
  474. }
  475. }
  476. });
  477.  
  478. /*
  479. Timer checks event
  480. */
  481. setInterval(function () {
  482. //Temporary channels inactive deleting
  483. var tempChannels = sinusbot.getVar("tempChannels");
  484. if(!isUndefined(tempChannels) && !isEmpty(tempChannels)) {
  485. for (var i = 0; i < tempChannels.length; i++) {
  486. if (getClientsNumber(tempChannels[i]) == 0) {
  487. channelDelete(tempChannels[i], true);
  488. sinusbot.log('Temp channel ' + tempChannels[i] + ' was deleted by check timer.');
  489. tempChannels.splice(i, 1);
  490. }
  491. }
  492. sinusbot.setVar("tempChannels", tempChannels);
  493. }
  494. //Users on help check
  495. var userOnHelp = sinusbot.getVar('usersOnHelp');
  496. if(!isUndefined(userOnHelp) && !isEmpty(userOnHelp)) {
  497. for (var i = 0; i < userOnHelp.length; i++) {
  498. var userChannel = getUserChannelId(userOnHelp[i].clientId);
  499. var out = true;
  500. for (var i2 = 0; i < helpChannelsId.length; i2++) {
  501. if (userChannel == helpChannelsId[i2]) {
  502. out = false;
  503. }
  504. }
  505. if (out) {
  506. userOnHelp.splice(i, 1);
  507. }
  508. }
  509.  
  510. sinusbot.setVar('usersOnHelp', userOnHelp);
  511. }
  512.  
  513. if(config.clockChannel != -1)
  514. {
  515. var clockChannel = getChannelParams(config.clockChannel);
  516. var date_local = new Date();
  517. var date = new Date(date_local.getUTCFullYear(), date_local.getUTCMonth(), date_local.getDate(),
  518. date_local.getUTCHours(), date_local.getUTCMinutes(), date_local.getUTCSeconds());
  519.  
  520. var timezone = parseInt(config.clockTimezone);
  521. if(timezone < 9)
  522. {
  523. date.setHours(date.getHours() + timezone);
  524. } else if (timezone > 8)
  525. {
  526. date.setHours(date.getHours() - (timezone - 8));
  527. }
  528. var minutes = date.getMinutes();
  529. if(minutes < 10){
  530. minutes = '0' + minutes;
  531. }
  532.  
  533. clockChannel.name = replaceSNVariables(config.clockFormat, date.getDate(), date.getMonth() + 1, date.getFullYear(),
  534. date.getHours(), minutes);
  535.  
  536. channelUpdate(clockChannel.id, clockChannel);
  537. }
  538. }, 1000 * config.botChecksEvery);
  539.  
  540. /*
  541. Bot AI and commands, event for chat
  542. */
  543. sinusbot.on('chat', function (chat) {
  544. if (config.botAIPrivateChat == 0 && chat.mode == 1 && getNick() != chat.clientNick) {
  545. var check = true;
  546. if (new RegExp('info [0-9]+').test(chat.msg) || chat.msg == 'info' || chat.msg == 'info server' || chat.msg == 'info all') {
  547. if (haveGroupOnServer(chat, helpGroupsId)) {
  548. check = false;
  549. }
  550. }
  551. if (check) {
  552. var options = {
  553. method: "GET",
  554. headers: "Content-type: text/html; charset=utf-8",
  555. timeout: 15000,
  556. url: "https://usets.pl/bot.php?msg=" + chat.msg
  557. };
  558. http(options, function (error, response) {
  559. if (error == null && response != null && response.statusCode == 200) {
  560. chatPrivate(chat.clientId, response.data);
  561. } else if (response != null) {
  562. sinusbot.log('Problem with your bot chat! ' + response.statusCode + "-" + typeof(response.statusCode) + "-" + typeof(200));
  563. } else {
  564. sinusbot.log('Problem with your bot chat! ' + error);
  565. }
  566. });
  567. }
  568. }
  569. });
  570.  
  571. /*
  572. Bot AI and commands, event for poke
  573. */
  574. sinusbot.on('poke', function (message) {
  575. if (config.botAIPoke == 0 && getNick() != message.clientNick) {
  576. var options = {
  577. method: "GET",
  578. headers: "Content-type: text/html; charset=utf-8",
  579. timeout: 15000, url: "https://usets.pl/bot.php?msg=" + message.msg
  580. };
  581. http(options, function (error, response) {
  582. if (error == null && response != null && response.statusCode == 200) {
  583. poke(message.clientId, response.data);
  584. } else if (response != null) {
  585. sinusbot.log('Problem with your bot poke! ' + response.statusCode + "-" + typeof(response.statusCode) + "-" + typeof(200));
  586. } else {
  587. sinusbot.log('Problem with your bot poke! ' + error);
  588. }
  589. });
  590. }
  591. });
  592.  
  593. /*
  594. Welcome poke information event
  595. */
  596. sinusbot.on('clientMove', function (e) {
  597. if (e.oldChannel == 0 && config.registerMessageOn == 0) {
  598. var isNew = !haveGroupOnServer(e, parseInt(config.registerGroupId));
  599.  
  600. if (isNew && haveGroupFromArray(e, helpGroupsId) == false) {
  601. var message = config.registerWelcomeMessage;
  602. if (config.registerMessageType == 0) {
  603. poke(e.clientId, message);
  604. } else {
  605. chatPrivate(e.clientId, message);
  606. }
  607. }
  608. }
  609. });
  610.  
  611. /*
  612. Information event for online users channel updates and max online record
  613. */
  614. sinusbot.on('clientMove', function (e) {
  615. if (e.oldChannel == 0 || e.newChannel == 0) {
  616. var clients = getClientsNumber();
  617. onlineClientsChannel(clients);
  618. sinusbot.setVar("onlineClients", clients);
  619.  
  620. if (sinusbot.getVar("maxOnlineRecord") < clients) {
  621. maxOnlineClientsChannel(clients);
  622. sinusbot.setVar("maxOnlineRecord", clients);
  623. }
  624.  
  625. var maxOnlineChannel = getChannelParams(config.maxOnlineUsersChannel);
  626. if(!isUndefined(maxOnlineChannel.name)) {
  627. var wasUpdated = maxOnlineChannel.name.indexOf(sinusbot.getVar('maxOnlineRecord')) == -1;
  628. if (wasUpdated) {
  629. maxOnlineClientsChannel(sinusbot.getVar("maxOnlineRecord"));
  630. }
  631. }
  632. }
  633.  
  634. //Staff Groups bypass
  635. if (haveGroupFromArray(e, helpGroupsId) != false) {
  636. staffOnlineChannel(sinusbot.getVar('staff').length, sinusbot.getVar('staff'));
  637. }
  638. });
  639.  
  640. /*
  641. Logging event to track channels users activity
  642. */
  643. sinusbot.on('clientMove', function (e) {
  644. var timeNow = new Date().getTime();
  645. var channelLogNewChannel = [];
  646. var channelLogOldChannel = [];
  647. var entryTypeOld = 0;
  648. var entryTypeNew = 0;
  649.  
  650. if (isUndefined(sinusbot.getVar(e.newChannel))) {
  651. channelLogNewChannel = [];
  652. entryTypeNew = (e.newChannel == 0) ? 3 : 1;
  653. channelLogNewChannel.push([timeNow, e.clientUid, e.clientNick, e.oldChannel, e.newChannel, entryTypeNew]);
  654. sinusbot.setVar(e.newChannel, channelLogNewChannel);
  655. } else {
  656. channelLogNewChannel = sinusbot.getVar(e.newChannel);
  657. entryTypeNew = (e.newChannel == 0) ? 3 : 1;
  658. channelLogNewChannel.push([timeNow, e.clientUid, e.clientNick, e.oldChannel, e.newChannel, entryTypeNew]);
  659. sinusbot.setVar(e.newChannel, channelLogNewChannel);
  660. }
  661.  
  662. if (isUndefined(sinusbot.getVar(e.oldChannel))) {
  663. channelLogOldChannel = [];
  664. entryTypeOld = (e.oldChannel == 0) ? 4 : 2;
  665. channelLogOldChannel.push([timeNow, e.clientUid, e.clientNick, e.oldChannel, e.newChannel, entryTypeOld]);
  666. sinusbot.setVar(e.oldChannel, channelLogOldChannel);
  667. } else {
  668. channelLogOldChannel = sinusbot.getVar(e.oldChannel);
  669. entryTypeOld = (e.oldChannel == 0) ? 4 : 2;
  670. channelLogOldChannel.push([timeNow, e.clientUid, e.clientNick, e.oldChannel, e.newChannel, entryTypeOld]);
  671. sinusbot.setVar(e.oldChannel, channelLogOldChannel);
  672. }
  673. });
  674.  
  675. /*
  676. Logging event to clear channel log activity on channel delete
  677. */
  678. sinusbot.on('channelDelete', function (channel) {
  679. sinusbot.unsetVar(channel.id.toString());
  680. });
  681.  
  682. /*
  683. Command event for getting channel activity log
  684. */
  685. sinusbot.on('chat', function (chat) {
  686. if (getNick() != chat.clientNick && chat.mode == 1 && haveGroupFromArray(chat, helpGroupsId) != false) {
  687. if (chat.msg == 'info' || chat.msg == 'info server' || chat.msg == 'info all' || new RegExp('info [0-9]+').test(chat.msg)) {
  688. if (chat.msg == 'info' || chat.msg == 'info all') {
  689. var channelLog = sinusbot.getVar(chat.channel);
  690. } else if (new RegExp('info [0-9]+').test(chat.msg)) {
  691. var channelLog = sinusbot.getVar(parseInt(chat.msg.split(' ')[1]));
  692. } else if (chat.msg == 'info server') {
  693. var channelLog = sinusbot.getVar(0);
  694. }
  695.  
  696. if (isUndefined(channelLog) || channelLog.length <= 0) {
  697. chatPrivate(chat.clientId, 'No entry logs for this channel!');
  698. } else {
  699. if (channelLog.length < 50) {
  700. var history = 0;
  701. } else {
  702. if(chat.msg == 'info all') {
  703. var history = 0;
  704. } else {
  705. var history = channelLog.length - 50;
  706. }
  707. }
  708. for (var i = history; i < channelLog.length; i++) {
  709. var logEntry = channelLog[i];
  710. var entryType = 'error';
  711.  
  712. switch (logEntry[5]) {
  713. case 1:
  714. entryType = 'entered';
  715. break;
  716. case 2:
  717. entryType = 'leaved';
  718. break;
  719. case 3:
  720. entryType = 'disconnected from server';
  721. break;
  722. case 4:
  723. entryType = 'joined to server';
  724. break;
  725. }
  726.  
  727. chatPrivate(chat.clientId, 'Date: ' + new Date(logEntry[0]).toISOString() + '/ClientId: '
  728. + logEntry[1] + '/ClientName: ' + logEntry[2] + '/OldChannel: '
  729. + logEntry[3] + '/NewChannel: ' + logEntry[4] + '/' + entryType);
  730. }
  731. chatPrivate(chat.clientId, 'All records - ' + channelLog.length);
  732. }
  733. }
  734. }
  735. });
  736.  
  737. /*
  738. Web Data API Event
  739. */
  740. sinusbot.on('api:web', function (data) {
  741. return sinusbot.getVar('staff').length;
  742. });
  743.  
  744. /*
  745. Event will handle bot joining to channel and change codec automatically if autoMusicCodecBot is On
  746. */
  747. sinusbot.on('botMove', function (info) {
  748. if (config.autoMusicCodecBot == 0) {
  749. var channelCodec = sinusbot.getVar('channelCodec');
  750. var botMove = sinusbot.getVar('botMove' + self);
  751. if (info.newChannel != 0) {
  752. if (isEmpty(botMove)) {
  753. botMove = {newChannel: info.newChannel, oldChannel: 0};
  754. } else {
  755. botMove = {newChannel: info.newChannel, oldChannel: botMove.newChannel};
  756. }
  757.  
  758. var channel = getChannelParams(info.newChannel);
  759. channelCodec.push({id: info.newChannel, codec: channel.codec, quality: channel.quality});
  760. channelUpdate(info.newChannel, {
  761. codec: parseInt(autoMusicCodecNew[0]),
  762. quality: parseInt(autoMusicCodecNew[1])
  763. });
  764. }
  765. if (botMove.oldChannel != 0) {
  766. var codec = 4;
  767. var quality = 6;
  768. for (var i = 0; i < channelCodec.length; i++) {
  769. if (channelCodec[i].id == botMove.oldChannel) {
  770. codec = channelCodec[i].codec;
  771. quality = channelCodec[i].quality;
  772. break;
  773. }
  774. }
  775. channelUpdate(botMove.oldChannel, {codec: codec, quality: quality});
  776. channelCodec = removeFromArray(channelCodec, {
  777. id: botMove.oldChannel,
  778. codec: codec,
  779. quality: quality
  780. });
  781. }
  782.  
  783.  
  784. sinusbot.setVar('botMove' + self, botMove);
  785. sinusbot.setVar('channelCodec', channelCodec);
  786. }
  787. });
  788.  
  789. /*
  790. Update clients online information channel
  791. */
  792. function onlineClientsChannel(online) {
  793. if (!isUndefined(config.onlineUsersChannel) || !isUndefined(config.onlineUsersChannelId)) {
  794. var channel = getChannelParams(parseInt(config.onlineUsersChannelId));
  795. if (channel != false) {
  796. channel.name = replaceSNVariables(config.onlineUsersChannel, online);
  797. channelUpdate(channel.id, {name: channel.name});
  798. }
  799. }
  800. }
  801.  
  802. /*
  803. Update max clients online information channel
  804. */
  805. function maxOnlineClientsChannel(maxOnline) {
  806. if (!isUndefined(config.maxOnlineUsersChannel) || !isUndefined(config.maxOnlineUsersChannelId)) {
  807. var channel = getChannelParams(parseInt(config.maxOnlineUsersChannelId));
  808. if (channel != false) {
  809. var date = new Date().toISOString();
  810. channel.name = replaceSNVariables(config.maxOnlineUsersChannel, maxOnline);
  811. channel.description = replaceSNVariables(config.maxOnlineUsersChannelDesc, date);
  812. channelUpdate(channel.id, {name: channel.name, description: channel.description});
  813. }
  814. }
  815. }
  816.  
  817. /*
  818. Update staff online information channel
  819. */
  820. function staffOnlineChannel(staffOnline, staffList) {
  821. if (!isUndefined(config.staffOnlineChannelName) || !isUndefined(config.staffOnlineChannelId)) {
  822. var channel = getChannelParams(parseInt(config.staffOnlineChannelId));
  823. if (channel != false) {
  824. if(channel.name.indexOf(staffOnline) == -1) {
  825. channel.name = replaceSNVariables(config.staffOnlineChannelName,
  826. (staffOnline != 0 ? staffOnline.toString() : config.staffOnlineChannelZero));
  827. var parsedList = '';
  828. for (var i = 0; i < staffList.length; i++) {
  829. if(staffList.length != 0) {
  830. var member = staffList[i];
  831. var text = "\n" + replaceSNVariables(config.staffOnlineChannelDesc,
  832. '[URL=client://0/' + member.uuid + ']' + member.nick + '[/URL]', member.groups.n);
  833. parsedList += text;
  834. }
  835.  
  836. }
  837.  
  838. channelUpdate(channel.id, {name: channel.name, description: parsedList.toString()});
  839. }
  840. }
  841. }
  842. }
  843.  
  844. /*
  845. Function with will send notification poke or chat message
  846. */
  847. function sendUserNotification(notificationType, user, message) {
  848. if (notificationType == 0)
  849. chatPrivate(user, message);
  850. else if (notificationType == 1)
  851. poke(user, message);
  852. }
  853.  
  854. /*
  855. If user have specific group in client server groups array
  856. */
  857. function haveGroupOnServer(e, group) {
  858. if (typeof(group) != 'number') {
  859. group = parseInt(group);
  860. }
  861.  
  862. var result = false;
  863. for (var i = 0; i < e.clientServerGroups.length; i++) {
  864. if (e.clientServerGroups[i].i == group) {
  865. return result = e.clientServerGroups[i];
  866. }
  867. }
  868.  
  869. return result;
  870. }
  871.  
  872. /*
  873. If user have specific group of clientServerGroups from input array
  874. */
  875. function haveGroupFromArray(e, arrayGroups) {
  876. var result = false;
  877.  
  878. for (var i = 0; i < arrayGroups.length; i++) {
  879. var group = arrayGroups[i];
  880. if (typeof(group) != 'number') {
  881. group = parseInt(group);
  882. }
  883. var groupOnServer = haveGroupOnServer(e, group);
  884. if (groupOnServer != false) {
  885. return result = groupOnServer;
  886. }
  887. }
  888.  
  889. return result;
  890. }
  891.  
  892. /*
  893. If user have specific group from input array
  894. */
  895. function haveSpecificGroupFromArray(groupId, arrayGroups) {
  896. var result = false;
  897. for (var i = 0; i < arrayGroups.length; i++) {
  898. var group = arrayGroups[i];
  899. if (typeof(group) != 'number') {
  900. group = parseInt(group);
  901. }
  902. if (groupId == group) {
  903. return result = group;
  904. }
  905. }
  906.  
  907. return result;
  908. }
  909.  
  910. /*
  911. If user have specific group from user groups array
  912. */
  913. function haveSpecificGroupFromUserGroups(groupId, arrayGroups) {
  914. var result = false;
  915. if(isUndefined(arrayGroups))
  916. return false;
  917. for (var i = 0; i < arrayGroups.length; i++) {
  918. var group = arrayGroups[i];
  919. sinusbot.log('te' + groupId + 'f: ' + group.i);
  920. if (groupId == group.i) {
  921. return result = group;
  922. }
  923. }
  924.  
  925. return result;
  926. }
  927.  
  928. /*
  929. Generate random hash with specific length and chars selected
  930. */
  931. function randomString(length, chars) {
  932. var mask = '';
  933. if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz';
  934. if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  935. if (chars.indexOf('#') > -1) mask += '0123456789';
  936. var result = '';
  937. for (var i = length; i > 0; --i) result += mask[Math.round(Math.random() * (mask.length - 1))];
  938.  
  939. return result;
  940. }
  941.  
  942. /*
  943. Function to get the channelId based on the channelName and the parentId
  944. */
  945. function getChannelId(channelName, parentId) {
  946. var channels = getChannels();
  947. for (var i = 0; i < channels.length; i++) {
  948. if (channels[i].name == channelName && channels[i].parent == parentId) {
  949. return channels[i].id;
  950. }
  951. }
  952. return false;
  953. }
  954.  
  955. /*
  956. Function to get the channelParams based on the channelName and the parentId or channelId
  957. */
  958. function getChannelParams(channelId, channelName, parentId) {
  959. var channels = getChannels();
  960. for (var i = 0; i < channels.length; i++) {
  961. var channel = channels[i];
  962. if (channel.id == channelId || (channel.name == channelName && channel.parent == parentId)) {
  963. return channel;
  964. }
  965. }
  966. return false;
  967. }
  968.  
  969. /*
  970. Function return status of new user channel if it is one from array
  971. */
  972. function isChannelInArray(channel, array) {
  973. var result = false;
  974.  
  975. for (var i = 0; i < array.length; i++) {
  976. var id = array[i];
  977. if (typeof(id) != 'number') {
  978. id = parseInt(id);
  979. }
  980.  
  981. if (channel == id) {
  982. result = true;
  983. break;
  984. }
  985. }
  986. return result;
  987. }
  988.  
  989. /*
  990. Function return array of all clients connected to server or channel
  991. */
  992. function getClients(channelId) {
  993. var channel, channels, clients = [];
  994. channels = getChannels();
  995. if (typeof channelId == 'undefined') {
  996. for (var i = 0; i < channels.length; i++) {
  997. channel = channels[i];
  998. for (var i2 = 0; i2 < channel.clients.length; i2++) {
  999. clients.push(channel.clients[i2]);
  1000. }
  1001. }
  1002. return clients;
  1003. } else {
  1004. channel = getChannel(channelId);
  1005. if (isEmpty(channel.clients)) {
  1006. return false;
  1007. } else {
  1008. return channel.clients;
  1009. }
  1010. }
  1011. return false;
  1012. }
  1013.  
  1014. /*
  1015. Function return number of users online total or channel based
  1016. */
  1017. function getClientsNumber(channelId) {
  1018. var channel, channels = [];
  1019. var clients = 0;
  1020.  
  1021. channels = getChannels();
  1022. if (typeof channelId == 'undefined') {
  1023. for (var i = 0; i < channels.length; i++) {
  1024. channel = channels[i];
  1025. clients += channel.clients.length;
  1026. }
  1027. return clients;
  1028. } else {
  1029. channel = getChannel(channelId);
  1030. if (isEmpty(channel.clients)) {
  1031. return 0;
  1032. } else {
  1033. return channel.clients.length;
  1034. }
  1035. }
  1036. return 0;
  1037. }
  1038.  
  1039. /*
  1040. Function get id of channel where specific user is
  1041. */
  1042. function getUserChannelId(clientId) {
  1043. var channel, channels = [];
  1044.  
  1045. channels = getChannels();
  1046.  
  1047. for (var i = 0; i < channels.length; i++) {
  1048. channel = channels[i];
  1049. if (!isEmpty(channel.clients)) {
  1050. for (var i2 = 0; i2 < channel.clients.length; i2++) {
  1051. if (channel.clients[i2].id == clientId) {
  1052. return channel.id;
  1053. }
  1054. }
  1055. }
  1056. }
  1057.  
  1058. return 0;
  1059. }
  1060.  
  1061. /*
  1062. Check if object is empty
  1063. */
  1064. function isEmpty(myObject) {
  1065. for (var key in myObject) {
  1066. if (myObject.hasOwnProperty(key)) {
  1067. return false;
  1068. }
  1069. }
  1070. return true;
  1071. }
  1072.  
  1073. /*
  1074. Function find and replace specific char in string
  1075. */
  1076. function replaceChar(str, find, replace) {
  1077. return str.replace(find, replace);
  1078. }
  1079.  
  1080. /*
  1081. Function replace as many 'sN' variables in string as needed
  1082. */
  1083. function replaceSNVariables(string) {
  1084. for (var i = 1; i < arguments.length; i++) {
  1085. var snI = i - 1;
  1086. var sn = 's' + snI;
  1087. string = replaceChar(string, sn, arguments[i].toString());
  1088. }
  1089. return string;
  1090. }
  1091.  
  1092. /*
  1093. Function remove specific element from array
  1094. */
  1095. function removeFromArray(array, item) {
  1096. if(isUndefined(array) || isUndefined(item))
  1097. return false;
  1098. var index = array.indexOf(item);
  1099. if (index > -1) {
  1100. array.splice(index, 1);
  1101. }
  1102. return array;
  1103. }
  1104.  
  1105. /*
  1106. Filter object in array
  1107. */
  1108. function getObjectIdArray(array, id) {
  1109. for (var i = 0, len = array.length; i < len; i++) {
  1110. if (array[i].id === id) {
  1111. return i;
  1112. }
  1113. }
  1114. return -1;
  1115. }
  1116.  
  1117. // -> isUndefined(variable)
  1118. function isUndefined(variable) {
  1119. return typeof variable == "undefined";
  1120. }
  1121.  
  1122. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement