diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c2a6bcf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules/
+logs/log.*
diff --git a/README b/README
new file mode 100644
index 0000000..8ce97e7
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+YM Center for ST24
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..be5a094
--- /dev/null
+++ b/index.js
@@ -0,0 +1,144 @@
+var http = require('http');
+var url = require('url');
+var winston = require('winston');
+var strftime = require('strftime');
+var strptime = require('micro-strptime').strptime;
+var request = require('request');
+var striptags = require('striptags');
+var fs = require('fs');
+var ini = require('ini');
+
+var config = ini.parse(fs.readFileSync(__dirname + '/config.ini', 'utf-8'));
+
+var keepalive_interval = 60 * 1000;
+var last_message_hash = '';
+var log_level = 'info';
+
+if (config.globals.log_level) {
+    log_level = config.globals.log_level;
+}
+
+var logger = new (winston.Logger)({
+  transports: [
+    new (winston.transports.Console)({
+      timestamp: function() {
+        return strftime('%F %T', new Date());
+      },
+      level: log_level
+    }),
+    new (winston.transports.DailyRotateFile)({
+      filename: __dirname + '/logs/log',
+      timestamp: function() {
+        return strftime('%F %T', new Date());
+      },
+      level: log_level
+    })
+  ]
+});
+
+
+var ym = require('yahoomessenger');
+ym.newInstance();
+
+function onReady(){
+  ym.login(config.globals.username, config.globals.password);
+}
+
+function onLoginSuccessful(data) {
+    logger.info('Login successful as ' + data.firstname + ' ' + data.lastname + ' (' + data.user_id + ')', {data: data});
+}
+
+function sendIgnoreResponse(destination, message) {
+    ym.sendPM(destination, "Pesan anda diabaikan, silahkan diulang beberapa saat lagi jika diperlukan: " + message);
+}
+
+function onPm(data) {
+    logger.info('onPM()', {data: data});
+    
+    var message = striptags(data.message);
+    
+    var message_hash = data.sender + ': ' + data.message;
+    if (message_hash == last_message_hash) {
+        logger.info('Ignoring duplicate message', {data: data});
+        return;
+    }
+    last_message_hash = message_hash;
+    
+    var greeting_prefix = "Pesan anda telah diterima dan akan segera diproses:";
+    if (config.globals.greeting_prefix) {
+        greeting_prefix = config.globals.greeting_prefix;
+    }
+
+    ym.sendPM(data.sender, greeting_prefix + ' ' + message);
+    
+    forwardMessageToAAA(data.sender, message);
+}
+
+function onOfflinePM(data) {
+    logger.verbose('onOfflinePM()', {data: data});
+    sendIgnoreResponse(data.sender, data.message);
+}
+
+function onBuddyAddRequest(data) {
+    logger.info('onBuddyAddRequest()', {data: data});
+    ym.acceptAddBuddy(data.username);
+    logger.info('Accept buddy add request: ' + data.username, {data: data});
+}
+
+function onHttpIncomingMessage(request, response) {
+    var qs = url.parse(request.url, true).query;
+    logger.info("onHttpIncomingMessage()", {qs: qs});
+    response.end('OK');
+    
+    logger.info('Sending message to ' + qs.PhoneNumber + ': ' + qs.text);
+    ym.sendPM(qs.to, qs.msg);
+    
+}
+
+function formatTimestamp(ts) {
+    var _ts = strptime(ts, '%A %b %d %Y %H:%M:%S GMT%z');
+    return strftime('%F %T', _ts);
+}
+
+function forwardMessageToAAA(sender, message) {
+    var request_opts = {
+        url: config.globals.aaa,
+        qs: {
+            PhoneNumber: sender,
+            Text: message,
+            Res_Port: config.globals.listen_port,
+            SMSCID: config.globals.smscid
+        }
+    };
+    
+    request(request_opts, function(err, response, body) {
+        if (err) {
+            logger.info('Request error: ' + err);
+            return;
+        }
+        
+        logger.info('Response: ' + response);
+        logger.info('Body: ' + body);
+        
+    });
+}
+
+function createHttpServer() {
+    logger.verbose('createHttpServer()');
+    
+    var httpServer = http.createServer(onHttpIncomingMessage);
+    httpServer.listen(config.globals.listen_port, function(){
+        logger.info("HTTP server listening on " + config.globals.listen_port);
+    });
+}
+
+createHttpServer();
+ym.on('ready', onReady);
+ym.on('loginSuccessful', onLoginSuccessful);
+ym.on('pm', onPm);
+ym.on('buddyAddRequest', onBuddyAddRequest);
+
+setInterval(function() { 
+    logger.info('Sending keepalive packet');
+    ym.keepAlive();
+}, keepalive_interval);
diff --git a/logs/empty b/logs/empty
new file mode 100644
index 0000000..e69de29
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..c552f63
--- /dev/null
+++ b/package.json
@@ -0,0 +1,33 @@
+{
+  "name": "evo-ym-center",
+  "version": "0.0.1",
+  "description": "EVO YM Center",
+  "main": "index.js",
+  "scripts": {
+    "test": "mocha test"
+  },
+  "repository": {
+    "type": "git",
+    "url": "http://gitlab.kodesumber.com/adhisimon/evo-ym-center.git"
+  },
+  "keywords": [
+    "evo",
+    "guchi",
+    "gentong",
+    "yahoo",
+    "ym",
+    "ppob"
+  ],
+  "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>",
+  "license": "BSD",
+  "dependencies": {
+    "ini": "~1.3.4",
+    "yahoomessenger": "~0.1.3-Beta",
+    "url": "~0.11.0",
+    "winston": "~1.1.1",
+    "strftime": "~0.9.2",
+    "micro-strptime": "~0.2.2",
+    "request": "~2.65.0",
+    "striptags": "~2.0.4"
+  }
+}