Advertisement
Guest User

Untitled

a guest
May 15th, 2016
358
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var fs = require('fs');
  2. var crypto = require('crypto');
  3. var console = process.console;
  4. var config = require('./config.js');
  5. var Steam = require('steam');
  6. var SteamWebLogOn = require('steam-weblogon');
  7. var getSteamAPIKey = require('steam-web-api-key');
  8. var SteamTradeOffers = require('steam-tradeoffers');
  9. var SteamCommunity = require('steamcommunity');
  10. var SteamcommunityMobileConfirmations = require('steamcommunity-mobile-confirmations');
  11. var SteamTotp = require('steam-totp');
  12. var redisClient, io, requestify;
  13.  
  14. module.exports.init = function (redis, ioSocket, requestifyCore) {
  15.     io = ioSocket;
  16.     redisClient = redis.createClient();
  17.     requestify = requestifyCore;
  18. }
  19.  
  20. var details = {
  21.     account_name: config.bot.username,
  22.     password: config.bot.password,
  23.     two_factor_code: generatekey(config.bot.secret)
  24. };
  25.  
  26. var steamClient = new Steam.SteamClient();
  27. var steamUser = new Steam.SteamUser(steamClient);
  28. var steamFriends = new Steam.SteamFriends(steamClient);
  29. var steamWebLogOn = new SteamWebLogOn(steamClient, steamUser);
  30. var offers = new SteamTradeOffers();
  31.  
  32. // Generation Device_ID
  33. var hash = require('crypto').createHash('sha1');
  34. hash.update(Math.random().toString());
  35. hash = hash.digest('hex');
  36. var device_id = 'android:' + hash;
  37.  
  38. var checkingOffers = [],
  39.     WebCookies = [],
  40.     WebSession = false,
  41.     globalSession;
  42.  
  43. const redisChannels = {
  44.     checkItemsList: 'checkItems.list',
  45.     checkList: 'check.list',
  46.     checkedList: 'checked.list',
  47.     betsList: 'bets.list',
  48.     sendOffersList: 'send.offers.list',
  49.     tradeoffersList: 'tradeoffers.list',
  50.     declineList: 'decline.list',
  51.     usersQueue: 'usersQueue.list'
  52. }
  53.  
  54. function steamBotLogger(log) {
  55.     console.tag('SteamBot').log(log);
  56. }
  57.  
  58. function EscrowLogger(log) {
  59.     console.tag('EscrowBot').info(log);
  60. }
  61.  
  62. function generatekey(secret) {
  63.     code = SteamTotp.generateAuthCode(secret);
  64.     EscrowLogger('Generated Code : ' + code);
  65.     return code;
  66. }
  67.  
  68. steamClient.connect();
  69. steamClient.on('debug', steamBotLogger);
  70. steamClient.on('connected', function () {
  71.     steamUser.logOn(details);
  72. });
  73.  
  74. steamClient.on('logOnResponse', function (logonResp) {
  75.     if (logonResp.eresult === Steam.EResult.OK) {
  76.         steamBotLogger('Logged in!');
  77.         steamFriends.setPersonaState(Steam.EPersonaState.Online);
  78.  
  79.         steamWebLogOn.webLogOn(function (sessionID, newCookie) {
  80.             getSteamAPIKey({
  81.                 sessionID: sessionID,
  82.                 webCookie: newCookie
  83.             }, function (err, APIKey) {
  84.                 offers.setup({
  85.                     sessionID: sessionID,
  86.                     webCookie: newCookie,
  87.                     APIKey: APIKey
  88.                 }, function (err) {
  89.                     WebSession = true;
  90.                     globalSession = sessionID;
  91.                     WebCookies = newCookie;
  92.                     redisClient.lrange(redisChannels.tradeoffersList, 0, -1, function (err, offers) {
  93.                         offers.forEach(function (offer) {
  94.                             checkingOffers.push(offer);
  95.                         });
  96.                         handleOffers();
  97.                         AcceptMobileOffer();
  98.                     });
  99.                     steamBotLogger('Setup Offers!');
  100.                 });
  101.  
  102.             });
  103.         });
  104.     }
  105. });
  106.  
  107. function reWebLogon() {
  108.     steamWebLogOn.webLogOn(function (sessionID, newCookie) {
  109.         getSteamAPIKey({
  110.             sessionID: sessionID,
  111.             webCookie: newCookie
  112.         }, function (err, APIKey) {
  113.             offers.setup({
  114.                 sessionID: sessionID,
  115.                 webCookie: newCookie,
  116.                 APIKey: APIKey
  117.             }, function (err) {
  118.                 WebSession = true;
  119.                 globalSession = sessionID;
  120.                 WebCookies = newCookie;
  121.                 steamBotLogger('WebSession Reloaded !');
  122.             });
  123.         });
  124.     });
  125. }
  126.  
  127. function handleOffers() {
  128.     offers.getOffers({
  129.         get_received_offers: 1,
  130.         active_only: 1
  131.     }, function (error, body) {
  132.         if (
  133.             body
  134.             && body.response
  135.             && body.response.trade_offers_received
  136.         ) {
  137.             body.response.trade_offers_received.forEach(function (offer) {
  138.                 if (offer.trade_offer_state == 2) {
  139.                     if (is_checkingOfferExists(offer.tradeofferid)) return;
  140.  
  141.                     if (offer.items_to_give != null && config.admins.indexOf(offer.steamid_other) != -1) {
  142.                         console.tag('SteamBot', 'TradeOffer').log('TRADE OFFER #' + offer.tradeofferid + ' FROM: Admin ' + offer.steamid_other);
  143.                         offers.acceptOffer({tradeOfferId: offer.tradeofferid});
  144.                         return;
  145.                     }
  146.                     if (offer.items_to_give != null) {
  147.                         offers.declineOffer({tradeOfferId: offer.tradeofferid});
  148.                         return;
  149.                     }
  150.                     offers.getTradeHoldDuration({tradeOfferId: offer.tradeofferid}, function (err, hold) {
  151.                         if (err) {
  152.                             reWebLogon();
  153.                             steamBotLogger('Check hold error: ' + err);
  154.                             setTimeout(function () {
  155.                                 offers.getTradeHoldDuration({tradeOfferId: offer.tradeofferid}, function (err, hold) {
  156.                                     if (err) {
  157.                                         offers.declineOffer({tradeOfferId: offer.tradeofferid});
  158.                                         reWebLogon();
  159.                                         steamBotLogger('Check hold error: ' + err);
  160.                                     } else {
  161.                                         if (hold.their != 0) {
  162.                                             offers.declineOffer({tradeOfferId: offer.tradeofferid});
  163.                                             steamBotLogger('Escrow offer declined: ' + offer.tradeofferid);
  164.                                         }
  165.                                     }
  166.                                 });
  167.                             }, 5000);
  168.                         } else {
  169.                             if (hold.their != 0) {
  170.                                 offers.declineOffer({tradeOfferId: offer.tradeofferid});
  171.                                 steamBotLogger('Escrow offer declined: ' + offer.tradeofferid);
  172.                             }
  173.                         }
  174.                     });
  175.                     if (offer.items_to_receive != null && offer.items_to_give == null) {
  176.                         checkingOffers.push(offer.tradeofferid);
  177.                         console.tag('SteamBot', 'TradeOffer').log('TRADE OFFER #' + offer.tradeofferid + ' FROM: ' + offer.steamid_other);
  178.                         redisClient.multi([
  179.                             ['rpush', redisChannels.tradeoffersList, offer.tradeofferid],
  180.                             ['rpush', redisChannels.checkItemsList, JSON.stringify(offer)],
  181.                             ['rpush', redisChannels.usersQueue, offer.steamid_other]
  182.                         ]).exec(function () {
  183.                             redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
  184.                                 io.sockets.emit('queue', queues);
  185.                             });
  186.                         });
  187.                         return;
  188.                     }
  189.                 }
  190.             });
  191.         }
  192.     });
  193. }
  194.  
  195. steamUser.on('tradeOffers', function (number) {
  196.     if (number > 0) {
  197.         handleOffers();
  198.     }
  199. });
  200.  
  201.  
  202. var parseOffer = function (offer, offerJson) {
  203.     offers.loadPartnerInventory({
  204.         partnerSteamId: offer.steamid_other,
  205.         appId: 730,
  206.         contextId: 2,
  207.         tradeOfferId: offer.tradeofferid,
  208.         language: "russian"
  209.     }, function (err, hitems) {
  210.         if (err) {
  211.             redisClient.multi([
  212.                 ['rpush', redisChannels.declineList, offer.tradeofferid],
  213.                 ['lrem', redisChannels.checkItemsList, 0, offerJson],
  214.                 ['lrem', redisChannels.usersQueue, 1, offer.steamid_other]
  215.             ])
  216.                 .exec(function (err, replies) {
  217.                     parseItemsProcceed = false;
  218.                     return;
  219.                 });
  220.             return;
  221.         }
  222.         var items = offer.items_to_receive;
  223.         var items_to_check = [], num = 0;
  224.         for (var i = 0; i < items.length; i++) {
  225.             for (var j = 0; j < hitems.length; j++) {
  226.                 if (items[i].assetid == hitems[j].id) {
  227.                     items_to_check[num] = {
  228.                         appid: hitems[j].appid,
  229.                         name: hitems[j].market_name,
  230.                         market_hash_name: hitems[j].market_hash_name,
  231.                         classid: hitems[j].classid
  232.                     };
  233.                     var type = hitems[j].type;
  234.                     var rarity = '';
  235.                     var arr = type.split(',');
  236.                     if (arr.length == 2) type = arr[1].trim();
  237.                     if (arr.length == 3) type = arr[2].trim();
  238.                     if (arr.length && arr[0] == 'Нож') type = '★';
  239.                     switch (type) {
  240.                         case 'Армейское качество':
  241.                             rarity = 'milspec';
  242.                             break;
  243.                         case 'Запрещенное':
  244.                             rarity = 'restricted';
  245.                             break;
  246.                         case 'Засекреченное':
  247.                             rarity = 'classified';
  248.                             break;
  249.                         case 'Тайное':
  250.                             rarity = 'covert';
  251.                             break;
  252.                         case 'Ширпотреб':
  253.                             rarity = 'common';
  254.                             break;
  255.                         case 'Промышленное качество':
  256.                             rarity = 'common';
  257.                             break;
  258.                         case '★':
  259.                             rarity = 'rare';
  260.                             break;
  261.                     }
  262.                     items_to_check[num].rarity = rarity;
  263.                     num++;
  264.                     break;
  265.                 }
  266.             }
  267.         }
  268.         var value = {
  269.             offerid: offer.tradeofferid,
  270.             accountid: offer.steamid_other,
  271.             items: JSON.stringify(items_to_check)
  272.         };
  273.  
  274.         console.tag('SteamBot', 'Offer #' + value.offerid).log(value);
  275.  
  276.         redisClient.multi([
  277.             ['rpush', redisChannels.checkList, JSON.stringify(value)],
  278.             ['lrem', redisChannels.checkItemsList, 0, offerJson]
  279.         ])
  280.             .exec(function (err, replies) {
  281.                 parseItemsProcceed = false;
  282.             });
  283.  
  284.     });
  285. }
  286.  
  287. var checkOfferPrice = function () {
  288.     requestify.post('http://' + config.domain + '/api/checkOffer', {
  289.         secretKey: config.secretKey
  290.     })
  291.         .then(function (response) {
  292.             var answer = JSON.parse(response.body);
  293.  
  294.             if (answer.success) {
  295.                 checkProcceed = false;
  296.             }
  297.         }, function (response) {
  298.             console.tag('SteamBot').error('Something wrong with check offers. Retry...');
  299.             setTimeout(function () {
  300.                 checkOfferPrice()
  301.             }, 1000);
  302.         });
  303.  
  304. }
  305.  
  306. var checkNewBet = function () {
  307.     requestify.post('http://' + config.domain + '/api/newBet', {
  308.         secretKey: config.secretKey
  309.     })
  310.         .then(function (response) {
  311.             var answer = JSON.parse(response.body);
  312.             if (answer.success) {
  313.                 betsProcceed = false;
  314.             }
  315.         }, function (response) {
  316.             console.tag('SteamBot').error('Something wrong with send a new bet. Retry...');
  317.             setTimeout(function () {
  318.                 checkNewBet()
  319.             }, 1000);
  320.         });
  321. }
  322.  
  323. var checkArrGlobal = [];
  324.  
  325. var sendTradeOffer = function (appId, partnerSteamId, accessToken, sendItems, message, game, offerJson) {
  326.     try {
  327.         offers.loadMyInventory({
  328.             appId: appId,
  329.             contextId: 2
  330.         }, function (err, items) {
  331.             if (err) {
  332.                 console.log(err);
  333.                 sendProcceed = false;
  334.                 return;
  335.             }
  336.             var itemsFromMe = [],
  337.                 checkArr = [],
  338.                 num = 0;
  339.             var i = 0;
  340.             for (var i = 0; i < sendItems.length; i++) {
  341.                 for (var j = 0; j < items.length; j++) {
  342.                     if (items[j].tradable && (items[j].classid == sendItems[i])) {
  343.                         if ((checkArr.indexOf(items[j].id) == -1) && (checkArrGlobal.indexOf(items[j].id) == -1)) {
  344.                             checkArr[i] = items[j].id;
  345.                             itemsFromMe[num] = {
  346.                                 appid: 730,
  347.                                 contextid: 2,
  348.                                 amount: items[j].amount,
  349.                                 assetid: items[j].id
  350.                             };
  351.                             num++;
  352.                             break;
  353.                         }
  354.                     }
  355.                 }
  356.             }
  357.             if (num > 0) {
  358.                 offers.makeOffer({
  359.                     partnerSteamId: partnerSteamId,
  360.                     accessToken: accessToken,
  361.                     itemsFromMe: itemsFromMe,
  362.                     itemsFromThem: [],
  363.                     message: 'Поздравляем с победой на сайте ' + config.nameSite + ' | В игре #' + game
  364.                 }, function (err, response) {
  365.                     if (err) {
  366.                         console.tag('SteamBot', 'SendPrize').error('Error to send offer:' + err.message);
  367.                         getErrorCode(err.message, function (errCode) {
  368.                             if (errCode == 15 || errCode == 25 || err.message.indexOf('an error sending your trade offer.  Please try again later.')) {
  369.                                 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
  370.                                     setPrizeStatus(game, 2);
  371.                                     sendProcceed = false;
  372.                                 });
  373.                                 sendProcceed = false;
  374.                             }
  375.                             sendProcceed = false;
  376.                         });
  377.                         return;
  378.                     }
  379.                     checkArrGlobal = checkArrGlobal.concat(checkArr);
  380.                     redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
  381.                         setPrizeStatus(game, 1);
  382.                         sendProcceed = false;
  383.                     });
  384.                     console.tag('SteamBot', 'SendPrize').log('TradeOffer #' + response.tradeofferid + ' send!');
  385.                     AcceptMobileOffer();
  386.                 });
  387.             } else {
  388.                 console.tag('SteamBot', 'SendPrize').log('Items not found!');
  389.                 redisClient.lrem(redisChannels.sendOffersList, 0, offerJson, function (err, data) {
  390.                     setPrizeStatus(game, 1);
  391.                     sendProcceed = false;
  392.                 });
  393.             }
  394.         });
  395.  
  396.     } catch (ex) {
  397.         console.tag('SteamBot').error('Error to send the bet');
  398.         setPrizeStatus(game, 2);
  399.         sendProcceed = false;
  400.     }
  401. };
  402.  
  403. var setPrizeStatus = function (game, status) {
  404.     requestify.post('http://' + config.domain + '/api/setPrizeStatus', {
  405.         secretKey: config.secretKey,
  406.         game: game,
  407.         status: status
  408.     })
  409.         .then(function (response) {
  410.  
  411.         }, function (response) {
  412.             console.tag('SteamBot').log('Something wrong with set prize status. Retry...');
  413.             setTimeout(function () {
  414.                 setPrizeStatus()
  415.             }, 1000);
  416.         });
  417. }
  418.  
  419. var is_checkingOfferExists = function (tradeofferid) {
  420.     for (var i = 0, len = checkingOffers.length; i < len; ++i) {
  421.         var offer = checkingOffers[i];
  422.         if (offer == tradeofferid) {
  423.             return true;
  424.             break;
  425.         }
  426.     }
  427.     return false;
  428. }
  429.  
  430. var checkedOffersProcceed = function (offerJson) {
  431.     var offer = JSON.parse(offerJson);
  432.     if (offer.success) {
  433.         console.tag('SteamBot').log('Procceding accept: #' + offer.offerid);
  434.         offers.acceptOffer({tradeOfferId: offer.offerid}, function (err, body) {
  435.             if (!err) {
  436.                 redisClient.multi([
  437.                     ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
  438.                     ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
  439.                     ["rpush", redisChannels.betsList, offerJson],
  440.                     ["lrem", redisChannels.checkedList, 0, offerJson]
  441.                 ])
  442.                     .exec(function (err, replies) {
  443.                         redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
  444.                             io.sockets.emit('queue', queues);
  445.                             console.tag('SteamBot').log("New bet Accepted!");
  446.                             checkedProcceed = false;
  447.                         });
  448.                     });
  449.                 AcceptMobileOffer();
  450.             } else {
  451.                 console.tag('SteamBot').error('Error. With accept tradeoffer #' + offer.offerid);
  452.                 offers.declineOffer({tradeOfferId: offer.offerid});
  453.  
  454.                 offers.getOffer({tradeOfferId: offer.offerid}, function (err, body) {
  455.                     if (body.response.offer) {
  456.                         var offerCheck = body.response.offer;
  457.                         if (offerCheck.trade_offer_state == 2) {
  458.                             checkedProcceed = false;
  459.                             return;
  460.                         }
  461.                         if (offerCheck.trade_offer_state == 3) {
  462.                             redisClient.multi([
  463.                                 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
  464.                                 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
  465.                                 ["rpush", redisChannels.betsList, offerJson],
  466.                                 ["lrem", redisChannels.checkedList, 0, offerJson]
  467.                             ])
  468.                                 .exec(function (err, replies) {
  469.                                     redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
  470.                                         io.sockets.emit('queue', queues);
  471.                                         checkedProcceed = false;
  472.                                     });
  473.                                 });
  474.                         } else {
  475.                             redisClient.multi([
  476.                                 ["lrem", redisChannels.tradeoffersList, 0, offer.offerid],
  477.                                 ["lrem", redisChannels.usersQueue, 1, offer.steamid64],
  478.                                 ["lrem", redisChannels.checkedList, 0, offerJson]
  479.                             ])
  480.                                 .exec(function (err, replies) {
  481.                                     redisClient.lrange(redisChannels.usersQueue, 0, -1, function (err, queues) {
  482.                                         io.sockets.emit('queue', queues);
  483.                                         checkedProcceed = false;
  484.                                     });
  485.                                 });
  486.                         }
  487.                     }
  488.                 })
  489.             }
  490.         });
  491.     }
  492. }
  493.  
  494. function AcceptMobileOffer() {
  495.     // Информация для мобильных подтверждений
  496.     var steamcommunityMobileConfirmations = new SteamcommunityMobileConfirmations(
  497.         {
  498.             steamid: config.bot.steamid,
  499.             identity_secret: config.bot.identity_secret,
  500.             device_id: device_id,
  501.             webCookie: WebCookies,
  502.         });
  503.  
  504.     steamcommunityMobileConfirmations.FetchConfirmations((function (err, confirmations) {
  505.         if (err) {
  506.             console.log(err);
  507.             return;
  508.         }
  509.         console.tag('SteamBot', 'MobileTrades').log('Wait Offers: ' + confirmations.length);
  510.         if (!confirmations.length) {
  511.             return;
  512.         }
  513.         steamcommunityMobileConfirmations.AcceptConfirmation(confirmations[0], (function (err, result) {
  514.             if (err) {
  515.                 console.log(err);
  516.                 return;
  517.             }
  518.             console.tag('SteamBot', 'MobileTrades').log('Accept result: ' + result);
  519.         }).bind(this));
  520.     }).bind(this));
  521. }
  522.  
  523. var declineOffersProcceed = function (offerid) {
  524.     console.tag('SteamBot').log('Procceding decline: #' + offerid);
  525.     offers.declineOffer({tradeOfferId: offerid}, function (err, body) {
  526.         if (!err) {
  527.             console.tag('SteamBot').log('Offer #' + offerid + ' Decline!');
  528.             redisClient.lrem(redisChannels.declineList, 0, offerid);
  529.             declineProcceed = false;
  530.         } else {
  531.             console.tag('SteamBot').error('Error. With decline tradeoffer #' + offer.offerid)
  532.                 .tag('SteamBot').log(err);
  533.             declineProcceed = false;
  534.         }
  535.     });
  536. }
  537.  
  538. var queueProceed = function () {
  539.     redisClient.llen(redisChannels.checkList, function (err, length) {
  540.         if (length > 0 && !checkProcceed) {
  541.             console.tag('SteamBot', 'Queues').info('CheckOffers:' + length);
  542.             checkProcceed = true;
  543.             checkOfferPrice();
  544.         }
  545.     });
  546.     redisClient.llen(redisChannels.checkedList, function (err, length) {
  547.         if (length > 0 && !checkedProcceed && WebSession) {
  548.             console.tag('SteamBot', 'Queues').info('CheckedOffers:' + length);
  549.             checkedProcceed = true;
  550.             redisClient.lindex(redisChannels.checkedList, 0, function (err, offer) {
  551.                 checkedOffersProcceed(offer);
  552.             });
  553.         }
  554.     });
  555.     redisClient.llen(redisChannels.declineList, function (err, length) {
  556.         if (length > 0 && !declineProcceed && WebSession) {
  557.             console.tag('SteamBot', 'Queues').info('DeclineOffers:' + length);
  558.             declineProcceed = true;
  559.             redisClient.lindex(redisChannels.declineList, 0, function (err, offer) {
  560.                 declineOffersProcceed(offer);
  561.             });
  562.         }
  563.     });
  564.     redisClient.llen(redisChannels.betsList, function (err, length) {
  565.         if (length > 0 && !betsProcceed && !delayForNewGame) {
  566.             console.tag('SteamBot', 'Queues').info('Bets:' + length);
  567.             betsProcceed = true;
  568.             checkNewBet();
  569.         }
  570.     });
  571.     redisClient.llen(redisChannels.sendOffersList, function (err, length) {
  572.         if (length > 0 && !sendProcceed && WebSession) {
  573.             console.tag('SteamBot', 'Queues').info('Send winner offers:' + length);
  574.             sendProcceed = true;
  575.             redisClient.lindex(redisChannels.sendOffersList, 0, function (err, offerJson) {
  576.                 offer = JSON.parse(offerJson);
  577.                 sendTradeOffer(offer.appId, offer.steamid, offer.accessToken, offer.items, '', offer.game, offerJson);
  578.             });
  579.         }
  580.     });
  581.     redisClient.llen(redisChannels.checkItemsList, function (err, length) {
  582.         if (length > 0 && !parseItemsProcceed && WebSession) {
  583.             console.tag('SteamBot', 'Queues').info('Parse items:' + length);
  584.             parseItemsProcceed = true;
  585.             redisClient.lindex(redisChannels.checkItemsList, 0, function (err, offerJson) {
  586.                 offer = JSON.parse(offerJson);
  587.                 parseOffer(offer, offerJson);
  588.             });
  589.         }
  590.     });
  591. }
  592. var parseItemsProcceed = false;
  593. var checkProcceed = false;
  594. var checkedProcceed = false;
  595. var declineProcceed = false;
  596. var betsProcceed = false;
  597. var sendProcceed = false;
  598. var delayForNewGame = false;
  599. setInterval(queueProceed, 1500);
  600.  
  601. module.exports.handleOffers = handleOffers;
  602. module.exports.delayForNewGame = function (value) {
  603.     delayForNewGame = value;
  604. };
  605.  
  606. function getErrorCode(err, callback) {
  607.     var errCode = 0;
  608.     var match = err.match(/\(([^()]*)\)/);
  609.     if (match != null && match.length == 2) errCode = match[1];
  610.     callback(errCode);
  611. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement