public void main(string[] args)
        {
            // ============================================================================
            // http://stackoverflow.com/questions/5624934/convert-string-into-mongodb-bsondocument
            string json_str = @"{ 
                'some_str' : 'bar', 
                'int_arr' : [1,2,3,4,5],
                'int_val' : 1,
                'decimal_val' : 99.99,
                'double_val' : 88.88
            }";

            // case 1 of 2: we convert json string to bson document
            MongoDB.Bson.BsonDocument bson1
                = BsonSerializer.Deserialize <BsonDocument>(json_str);

            // case 2 of 2: we convert json string to bson document (same, but more elegant)
            //
            BsonDocument bson2 = BsonDocument.Parse(json_str);

            // now we extract values from bson document. Below you'll find several examples (by different data types)
            //
            string some_str3 = BsonSerializer.Deserialize <string>(bson2["some_str"].ToJson());
            string some_str  = BsonSerializer.Deserialize <string>(bson2["some_str"].ToJson());

            int[]   int_arr     = BsonSerializer.Deserialize <int[]>(bson2["int_arr"].ToJson());
            int     int_val     = BsonSerializer.Deserialize <int>(bson2["int_val"].ToJson());
            decimal decimal_val = BsonSerializer.Deserialize <decimal>(bson2["decimal_val"].ToJson());
            double  double_val  = BsonSerializer.Deserialize <double>(bson2["double_val"].ToJson());

            // now same action, but using Json.NET (imho this way is better (more readable and not mongo-library dependant)
            // todo: if we choose this way make sure it's bson docs are really compatible with mongo bson docs.
            // OR may be I like the 1st way better now ...  ;)
            //
            JToken root = JObject.Parse(json_str);

            JToken some_str2_token = root["some_str"];
            string some_str2       = some_str2_token.ToString();

            JToken int_arr_token = root["int_arr"];

            int[] int_arr2 = JsonConvert.DeserializeObject <int[]>(int_arr_token.ToString());

            JToken int_val_token = root["int_val"];
            int    int_val2      = JsonConvert.DeserializeObject <int>(int_val_token.ToString());

            JToken  decimal_val_token = root["decimal_val"];
            decimal decimal_val2      = JsonConvert.DeserializeObject <decimal>(decimal_val_token.ToString());

            JToken double_val_token = root["double_val"];
            double double_val2      = JsonConvert.DeserializeObject <double>(double_val_token.ToString());

            // noop just for breakpoint ;)
            ((Action)(() => { }))();

            //
            // ============================================================================
            // [on topic of Query Mongo]
            // How to deserialize a BsonDocument object back to class
            // http://stackoverflow.com/questions/9478613/how-to-deserialize-a-bsondocument-object-back-to-class
            //
            //QueryDocument _document = new QueryDocument("key", "value");

            //MongoCursor<BsonDocument> _documentsReturned =
            //                          _collection.FindAs<BsonDocument>(_document);

            //foreach (BsonDocument _document1 in _wordOntologies)
            //{
            //    //deserialize _document1
            //    //?
            //}
            // ============================================================================
            // [q] how to create new BsonDocument?
            // [a]
            //var document = new BsonDocument {
            //    { "author", "joe" },
            //    { "title", "yet another blog post" },
            //    { "text", "here is the text..." },
            //    { "tags", new BsonArray { "example", "joe" } },
            //    { "comments", new BsonArray {
            //        new BsonDocument { { "author", "jim" }, { "comment", "I disagree" } },
            //        new BsonDocument { { "author", "nancy" }, { "comment", "Good post" } }
            //    }}
            //};
            //// ============================================================================
            // MongoDB C# - Getting BsonDocument for an Element that doesn't exist
            // http://stackoverflow.com/questions/6628794/mongodb-c-sharp-getting-bsondocument-for-an-element-that-doesnt-exist
            // There is also an overload that lets you provide a default value:
            //
            // BsonDocument document;
            // var firstName = (string)document["FirstName", null];
            // // or
            // var firstName = (string)document["FirstName", "N/A"];
            //
            // OR
            //
            // var b = new BsonDocument();
            // var exists = b.Contains("asdfasdf");
            //// ============================================================================

            //MyGlobals.args = args;
            // .... and then in any other place in app we can access global args:
            //string[] args = MyGlobals.args;

            string storage_service_config_json = "";
            string rabbitmq_config_json        = "";
            string mongodb_config_json         = "";

            var p = new OptionSet()
            {
                { "c|storage-service-config=", "path to storage_service json configuration file",
                  v => storage_service_config_json = v },
                { "r|rabbitmq-config=", "path to rabbitmq json configuration file",
                  v => rabbitmq_config_json = v },
                { "m|mongodb-config=", "path to mongodb json configuration file",
                  v => mongodb_config_json = v }
            };

            // parse  cmd-line args
            List <string> extra;

            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `--help' for more information.");
                return;
            }

            // get parameters documents
            if (storage_service_config_json != "")
            {
                parameters_holder = new ResponseParametersHolder();
                parameters_holder.parse_json_file(storage_service_config_json);
                storage_service_parameters = parameters_holder.response_parameters;

                parameters_holder = new ResponseParametersHolder();
                parameters_holder.parse_json_file(rabbitmq_config_json);
                rabbitmq_parameters = parameters_holder.response_parameters;

                parameters_holder = new ResponseParametersHolder();
                parameters_holder.parse_json_file(mongodb_config_json);
                mongodb_parameters = parameters_holder.response_parameters;

                //_ema_bar = Convert.ToInt32(storage_service_parameters["_ema_bar"]);
                //_response_barsize_s = Convert.ToInt32(storage_service_parameters["_response_barsize_s"]);
                //_stop_k = Convert.ToDouble(storage_service_parameters["_stop_k"]);
                //_target_price_k = Convert.ToDouble(storage_service_parameters["_target_price_k"]);

                // Custom name of response set by you
                //Name = storage_service_parameters["name"];
            }



            // extract individual rabbitmq parameters
            //
            string            exchange_name = rabbitmq_parameters["exchange_name"];
            string            exchange_type = rabbitmq_parameters["exchange_type"];
            ConnectionFactory conn_factory  = new ConnectionFactory();

            conn_factory.HostName = rabbitmq_parameters["host_name"];
            conn_factory.UserName = rabbitmq_parameters["user_name"];
            conn_factory.Password = rabbitmq_parameters["password"];

            // extract storage_service parameters
            //
            string queue_name  = storage_service_parameters["queue_name"];
            string routing_key = storage_service_parameters["routing_key"];   // no need to provide routing key for 'fanout' exchange. "rout";


            // extract mongodb parameters
            //
            mongodb_connection_string = mongodb_parameters["mongodb_connection_string"];
            mongodb_database_name     = mongodb_parameters["mongodb_database_name"];
            mongodb_collection_name   = mongodb_parameters["mongodb_collection_name"];

            //---------------------------------------------------------------- progress bar end --------------
            // Create the thread object. This does not start the thread.
            Worker_console_hartbeat_progressbar worker_console_hartbeat_progressbar = new Worker_console_hartbeat_progressbar();
            Thread workerThread = new Thread(worker_console_hartbeat_progressbar.DoWork);

            // Start the worker thread.
            workerThread.Start();
            //---------------------------------------------------------------- progress bar end --------------

            System.Console.WriteLine("Welcome to storage_service (part of tradelink.afterlife)!");
            System.Console.WriteLine("---------------------------------------------------------");
            System.Console.WriteLine("connecting to mongodb...");


            // prepare mongo
            MongoClient   client   = new MongoClient(mongodb_connection_string);
            MongoServer   server   = client.GetServer();
            MongoDatabase database = server.GetDatabase(mongodb_database_name); // "test" is the name of the database

            mongodb_collection = database.GetCollection <BsonDocument>(mongodb_collection_name);

            System.Console.WriteLine("connecting to rabbitmq... wwarning: sometimes it hungs here");

            // create rabbitmq connection
            IConnection conn = conn_factory.CreateConnection();
            // create channel
            IModel chan = conn.CreateModel();

            chan.ExchangeDeclare(exchange_name,
                                 exchange_type,
                                 false, // durable
                                 false, // autodelete
                                 null); // args
            chan.QueueDeclare(queue_name,
                              false,    // durable
                              false,    // exclusive
                              true,     // autodelete
                              null);    // args
            chan.QueueBind(queue_name, exchange_name, routing_key);

            EventingBasicConsumer c_consumer = new EventingBasicConsumer {
                Model = chan
            };

            c_consumer.Received += my_callback;
            System.Console.WriteLine("ready to consume messages...");

            // blocking call:
            chan.BasicConsume(queue_name,
                              false,
                              c_consumer);

            /*
             * EventingBasicConsumer r_consumer = new EventingBasicConsumer {Model = chan};
             * r_consumer.Received += rate_limit_notify;
             * chan.BasicConsume("rate_limit",
             *                false,
             *                r_consumer);
             */
        }
        string debug_message_from_constructor = ""; // need to store it and show on 1st tick, otherwise debug messages are wiped out when ticks start to arrive
        public _TS_step_by_step()
            : base()
        {
            System.Diagnostics.Debug.WriteLine("class _TS_step_by_step constructor entry point");
            string[] args = MyGlobals.args;     // extract main(args) from MyGlobals (we store main(args) in Kadina Program.cs, ASP, etc.)
            if (args == null)
            {
                throw new Exception("you forgot to set MyGlobals.args (in Kadina or asp or in whatever you use)");
            }

            string response_config = "";
            //string storage_service_config_jsonfile = "";
            string rabbitmq_config_jsonfile = "";

            var p = new OptionSet()
            {
                { "a|response-config=", "response json configuration file",
                  v => response_config = v },
                //{ "c|storage-service-config=", "path to storage_service json configuration file",
                //  v => storage_service_config_jsonfile = v},
                { "r|rabbitmq-config=", "path to rabbitmq json configuration file",
                  v => rabbitmq_config_jsonfile = v }
            };

            // parse  cmd-line args
            List <string> extra;

            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
                System.Diagnostics.Debug.WriteLine("Try `--help' for more information.");
                return;
            }

            // get settings from json file
            if (response_config != "")
            {
                response_parameters_holder = new ResponseParametersHolder();
                response_parameters_holder.parse_json_file(response_config);
                bson = response_parameters_holder.bson;

                //_ema_bar = Convert.ToInt32(bson["_ema_bar"]);
                _ema_bar            = BsonSerializer.Deserialize <int>(bson["_ema_bar"].ToJson());
                _response_barsize_s = BsonSerializer.Deserialize <int>(bson["_response_barsize_s"].ToJson());
                _stop_k             = BsonSerializer.Deserialize <double>(bson["_stop_k"].ToJson());
                _target_price_k     = BsonSerializer.Deserialize <double>(bson["_target_price_k"].ToJson());

                //_target_price_k = Convert.ToDouble(bson["_target_price_k"]);

                // Custom name of response set by you
                Name = BsonSerializer.Deserialize <string>(bson["name"].ToJson());

                //debug_message_from_constructor = "parsed json file - OK (set slow_ma=" + _slow_ma_bar + " fast_ma=" + _fast_ma_bar;
                //D(debug_message_from_constructor); // wtf? why this message never showed up? seems messages are cleaned right before 1st GotTick();

                //ResponseParametersHolder storage_service_parameters_holder = new ResponseParametersHolder();
                //storage_service_parameters_holder.parse_json_file(storage_service_config_jsonfile);
                //storage_service_parameters_bson = storage_service_parameters_holder.bson;

                ResponseParametersHolder rabbitmq_parameters_holder = new ResponseParametersHolder();
                rabbitmq_parameters_holder.parse_json_file(rabbitmq_config_jsonfile);
                rabbitmq_parameters_bson = rabbitmq_parameters_holder.bson;
                call_me_from_child_constructor();
            }


            // track_symbols_NewTxt() called when new text label is added
            track_symbols.NewTxt += new TextIdxDelegate(track_symbols_NewTxt);

            //     Names of the indicators used by your response.  Length must correspond to
            //     actual indicator values send with SendIndicators event
            Indicators = GenericTracker.GetIndicatorNames(gens());

            //[_response_barsize_s, 22]
            track_barlists            = new BarListTracker(new int[] { _response_barsize_s, 22 }, new BarInterval[] { BarInterval.CustomTime, BarInterval.CustomTime });
            track_barlists.GotNewBar += new SymBarIntervalDelegate(GotNewBar);
        }
        public void main(string[] args)
        {

            // ============================================================================
            // http://stackoverflow.com/questions/5624934/convert-string-into-mongodb-bsondocument
            string json_str = @"{ 
                'some_str' : 'bar', 
                'int_arr' : [1,2,3,4,5],
                'int_val' : 1,
                'decimal_val' : 99.99,
                'double_val' : 88.88
            }";
            // case 1 of 2: we convert json string to bson document
            MongoDB.Bson.BsonDocument bson1
                = BsonSerializer.Deserialize<BsonDocument>(json_str);

            // case 2 of 2: we convert json string to bson document (same, but more elegant)
            //
            BsonDocument bson2 = BsonDocument.Parse(json_str);

            // now we extract values from bson document. Below you'll find several examples (by different data types)
            //
            string some_str3 = BsonSerializer.Deserialize<string>(bson2["some_str"].ToJson());
            string some_str = BsonSerializer.Deserialize<string>(bson2["some_str"].ToJson());
            int[] int_arr = BsonSerializer.Deserialize<int[]>(bson2["int_arr"].ToJson());
            int int_val = BsonSerializer.Deserialize<int>(bson2["int_val"].ToJson());
            decimal decimal_val = BsonSerializer.Deserialize<decimal>(bson2["decimal_val"].ToJson());
            double double_val = BsonSerializer.Deserialize<double>(bson2["double_val"].ToJson());

            // now same action, but using Json.NET (imho this way is better (more readable and not mongo-library dependant)
            // todo: if we choose this way make sure it's bson docs are really compatible with mongo bson docs.
            // OR may be I like the 1st way better now ...  ;)
            //
            JToken root = JObject.Parse(json_str);

            JToken some_str2_token = root["some_str"];
            string some_str2 = some_str2_token.ToString();

            JToken int_arr_token = root["int_arr"];
            int[] int_arr2 = JsonConvert.DeserializeObject<int[]>(int_arr_token.ToString());

            JToken int_val_token = root["int_val"];
            int int_val2 = JsonConvert.DeserializeObject<int>(int_val_token.ToString());

            JToken decimal_val_token = root["decimal_val"];
            decimal decimal_val2 = JsonConvert.DeserializeObject<decimal>(decimal_val_token.ToString());

            JToken double_val_token = root["double_val"];
            double double_val2 = JsonConvert.DeserializeObject<double>(double_val_token.ToString());

            // noop just for breakpoint ;)
            ((Action)(() => { }))();

            //
            // ============================================================================
            // [on topic of Query Mongo]
            // How to deserialize a BsonDocument object back to class
            // http://stackoverflow.com/questions/9478613/how-to-deserialize-a-bsondocument-object-back-to-class
            //
            //QueryDocument _document = new QueryDocument("key", "value");

            //MongoCursor<BsonDocument> _documentsReturned =
            //                          _collection.FindAs<BsonDocument>(_document);

            //foreach (BsonDocument _document1 in _wordOntologies)
            //{
            //    //deserialize _document1
            //    //?
            //}
            // ============================================================================
            // [q] how to create new BsonDocument?
            // [a]
            //var document = new BsonDocument {
            //    { "author", "joe" },
            //    { "title", "yet another blog post" },
            //    { "text", "here is the text..." },
            //    { "tags", new BsonArray { "example", "joe" } },
            //    { "comments", new BsonArray {
            //        new BsonDocument { { "author", "jim" }, { "comment", "I disagree" } },
            //        new BsonDocument { { "author", "nancy" }, { "comment", "Good post" } }
            //    }}
            //};
            //// ============================================================================
            // MongoDB C# - Getting BsonDocument for an Element that doesn't exist
            // http://stackoverflow.com/questions/6628794/mongodb-c-sharp-getting-bsondocument-for-an-element-that-doesnt-exist
            // There is also an overload that lets you provide a default value:
            //
            // BsonDocument document;
            // var firstName = (string)document["FirstName", null];
            // // or
            // var firstName = (string)document["FirstName", "N/A"];
            //
            // OR
            //
            // var b = new BsonDocument();
            // var exists = b.Contains("asdfasdf");
            //// ============================================================================

            //MyGlobals.args = args;
            // .... and then in any other place in app we can access global args:
            //string[] args = MyGlobals.args;

            string storage_service_config_json = "";
            string rabbitmq_config_json = "";
            string mongodb_config_json = "";

            var p = new OptionSet() {
               { "c|storage-service-config=", "path to storage_service json configuration file",
                  v => storage_service_config_json = v},
               {"r|rabbitmq-config=", "path to rabbitmq json configuration file",
                  v => rabbitmq_config_json = v},
               {"m|mongodb-config=", "path to mongodb json configuration file",
                  v => mongodb_config_json = v}
            };

            // parse  cmd-line args
            List<string> extra;
            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `--help' for more information.");
                return;
            }

            // get parameters documents
            if (storage_service_config_json != "")
            {
                parameters_holder = new ResponseParametersHolder();
                parameters_holder.parse_json_file(storage_service_config_json);
                storage_service_parameters = parameters_holder.response_parameters;

                parameters_holder = new ResponseParametersHolder();
                parameters_holder.parse_json_file(rabbitmq_config_json);
                rabbitmq_parameters = parameters_holder.response_parameters;

                parameters_holder = new ResponseParametersHolder();
                parameters_holder.parse_json_file(mongodb_config_json);
                mongodb_parameters = parameters_holder.response_parameters;

                //_ema_bar = Convert.ToInt32(storage_service_parameters["_ema_bar"]);
                //_response_barsize_s = Convert.ToInt32(storage_service_parameters["_response_barsize_s"]);
                //_stop_k = Convert.ToDouble(storage_service_parameters["_stop_k"]);
                //_target_price_k = Convert.ToDouble(storage_service_parameters["_target_price_k"]);

                // Custom name of response set by you
                //Name = storage_service_parameters["name"];

            }






            // extract individual rabbitmq parameters
            //
            string exchange_name = rabbitmq_parameters["exchange_name"];
            string exchange_type = rabbitmq_parameters["exchange_type"];
            ConnectionFactory conn_factory = new ConnectionFactory();
            conn_factory.HostName = rabbitmq_parameters["host_name"];
            conn_factory.UserName = rabbitmq_parameters["user_name"];
            conn_factory.Password = rabbitmq_parameters["password"];

            // extract storage_service parameters
            //
            string queue_name = storage_service_parameters["queue_name"];
            string routing_key = storage_service_parameters["routing_key"];   // no need to provide routing key for 'fanout' exchange. "rout";


            // extract mongodb parameters
            //
            mongodb_connection_string = mongodb_parameters["mongodb_connection_string"];
            mongodb_database_name = mongodb_parameters["mongodb_database_name"];
            mongodb_collection_name = mongodb_parameters["mongodb_collection_name"];
            
            //---------------------------------------------------------------- progress bar end --------------
            // Create the thread object. This does not start the thread.
            Worker_console_hartbeat_progressbar worker_console_hartbeat_progressbar = new Worker_console_hartbeat_progressbar();
            Thread workerThread = new Thread(worker_console_hartbeat_progressbar.DoWork);

            // Start the worker thread.
            workerThread.Start();
            //---------------------------------------------------------------- progress bar end --------------

            System.Console.WriteLine("Welcome to storage_service (part of tradelink.afterlife)!");
            System.Console.WriteLine("---------------------------------------------------------");
            System.Console.WriteLine("connecting to mongodb...");


            // prepare mongo
            MongoClient client = new MongoClient(mongodb_connection_string);
            MongoServer server = client.GetServer();
            MongoDatabase database = server.GetDatabase(mongodb_database_name); // "test" is the name of the database
            mongodb_collection = database.GetCollection<BsonDocument>(mongodb_collection_name);

            System.Console.WriteLine("connecting to rabbitmq... wwarning: sometimes it hungs here");

            // create rabbitmq connection
            IConnection conn = conn_factory.CreateConnection();
            // create channel
            IModel chan = conn.CreateModel();
            chan.ExchangeDeclare(exchange_name,
                     exchange_type,
                     false, // durable
                     false, // autodelete
                     null); // args
            chan.QueueDeclare(queue_name,
                              false,    // durable
                              false,    // exclusive
                              true,     // autodelete
                              null);    // args
            chan.QueueBind(queue_name, exchange_name, routing_key);

            EventingBasicConsumer c_consumer = new EventingBasicConsumer { Model = chan };
            c_consumer.Received += my_callback;
            System.Console.WriteLine("ready to consume messages...");

            // blocking call:
            chan.BasicConsume(queue_name,
                              false,
                              c_consumer);

            /*
            EventingBasicConsumer r_consumer = new EventingBasicConsumer {Model = chan};
            r_consumer.Received += rate_limit_notify;
            chan.BasicConsume("rate_limit",
                              false,
                              r_consumer);
             */

        }