User Tag List

Ցույց են տրվում 1 համարից մինչև 10 համարի արդյունքները՝ ընդհանուր 10 հատից

Թեմա: BatutConnector - SQL աղյուսակների կառավարման framework

  1. #1
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    BatutConnector - SQL աղյուսակների կառավարման framework

    Այստեղ գրառումներս զուտ մասնագիտական են լինելու։
    Նշեմ, որ framework-ը դեռ developing-ի փուլում է և այս օրագրում, կնշեմ ընթացքում ինձ հանդիպած խնդիրները, լուծումները և այլն։
    Հետագայում, պլանավորում եմ, այս framewok-ի կոդը ազատ դնել համացանցում, ինչպես նաև սրա միջոցով կայք ստեղծել, որտեղ ծրագրավորողները կկարողանան կիսվել իրենց պրոյեկտներով, ինչպես ես հիմա անում եմ այստեղ։

    Framework—ը գրում եմ C#-ով։ Իմ առաջին փորձն է էս լեզվով ինչ որ բան գրելու։ Ցուցադրված կոդերի մեջ թերություն գտնելուց, շատ շնորհակալ կլինեմ, եթե ինձ տեղեկացնեք։

    Թե ինչու միտք ծագեց այսպիսի framework գրելու, չեմ կարող բացատրել․․․կարճ ասած ցանկացած ծրագրավորղի խելքը իրանը չի, երբ գործը հասնում ա հեծանիվ հորինելուն։

    Հուսով, թե այստեղիս գրառումները, թե հետագայում framework—ը ինչ որ բանով օգտակար կլինի։
    Վերջին խմբագրող՝ Արամ: 23.02.2015, 21:41:

  2. Գրառմանը 2 հոգի շնորհակալություն են հայտնել.

    Chuk (23.02.2015), Աթեիստ (23.02.2015)

  3. #2
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    Գրառում

    Նախ ծանոթանանք սկզբնական արխիտեկտուռայի հետ՝

    Հիշենք այս "դիագռամանմանը": Հետագա 1-2 պոստերի ընթացքում սա մեզ պետք կգա։
    Սկսենք sysInfSchema-ից։ Այս օբյեկտը նախատեսված է INFORMATION_SCHEMA-ից, որտեղ SQL Server-ում պահվում են ընդհանուր Database-ի մասին տեղեկությունները, կոնկրետ աղուսյակի, որը նշվել է sysMain-ը ժառանգած կլասի միջոցով(cMainTable փոփախական), սյուների արժեքները ստանալու համար։
    Ինչպե՞ս ենք մենք ստանում կոնկրետ աղյուսակիի սյուների անունները։
    Կոդը՝
    Կոդ:
     static public List<String> GetTableColumns(string tableName) {           
                List<String> retVal;
                String tmpTableName = tableName.ToUpper();
                if (!TableColumnsCache.ContainsKey(tmpTableName)) { // If table not found in cache
                    retVal = new List<String>();
                    string tmpQueryString = "SELECT name FROM sys.columns WHERE object_id = OBJECT_ID(@TableName)";
                    SqlCommand tmpSqlCommand = new SqlCommand(tmpQueryString, sysDataBaseConnect.SQLConnection);
                    tmpSqlCommand.Parameters.AddWithValue("@TableName", tableName);
                    SqlDataReader columnsReaded = sysDataBaseConnect.executeQuery(tmpSqlCommand);
                    if (columnsReaded.HasRows) {
                        while (columnsReaded.Read()) {
                            retVal.Add(columnsReaded["name"].ToString());
                        }
                        TableColumnsCache.Add(tmpTableName, retVal); // Add to columns catch
                    }
                    else {
                        LastErrorMsg = "Table Not Found";
                    }
                    columnsReaded.Close();
                }
                else {
                    retVal = TableColumnsCache[tmpTableName];
                }
                return retVal;
    Եթե 1 անգամ սեսիայի ընթացքում աղյուսակի սյուների անուները ստացել ենք, ապա էլ կարիք չկա նորից ստանալու, դրա համար ստանալուց հետ պահում ենք TableColumnsCache օբյեկտի մեջ, որը հայտարարված է այսպես՝ Dictionary<string, List<string>>, հետագայում, եթե ուրիշ օբյեկտ այդ թեյբլի աղյուսակները ուզի, իրեն միանգամից կվերադարձնենք Cache-ից, ոչ թե նորից հարցում կկազմենք դրանք ստանալու համար։ (sysInfSchema օբյեկտը static է)

    Այս ֆունկցաին կանչվում է sysMain-ի Init() - ֆունկցիաից, որի միջոցով էլ ստեղծվում են մեր հիմնական 2 dictionary-ների key-երը կոդը՝
    Կոդ:
              cTableColumnsList = sysInfSchema.GetTableColumns(this.cMainTable);
                    if (cTableColumnsList.Any()) {
                        foreach (string colName in cTableColumnsList) { // Loop through Columns list
                            this.cPhysicalRec.Add(colName, "");
                        }
                        this.cCurrentRec = new Dictionary<string, string>(this.cPhysicalRec);
                        retVal = true;
                    }
    Ինչպես երևում է Diagram—ից մեր sysMain օբյեկտը ունի 2 Dictionary օբյեկտներ՝
    Կոդ:
    protected Dictionary<string, string> cPhysicalRec; // Physical Rec ('column' => 'value' )
    protected Dictionary<string, string> cCurrentRec; // Current Record ('column' => 'value' )
    cPhysicalRec-ի մեջ, երբ կանչվում է SetId(string uniqueID) ֆունկցիան (որի մասին հետո կխոսենք) համապատասխանաբար լցվում են table-ի աղյուսակների արժեքները, հետո
    նույն արժեքները copy են լինում cCurrentRec-Ի մեջ, որի հետ էլ հետագայում աշխատում ենք՝
    SetValue, GetValue, SetRecord...սրանից մասին հետո։
    Վերջին խմբագրող՝ Արամ: 23.02.2015, 22:54:

  4. #3
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    sysMain class-ը

    Ինպես տեսնում ենք դիագռամից, sysMain-ը ունի հետևյալ ֆունկցիաները՝
    int SetID(string uniqueID)
    վերադարձնում է
    (սրանք կոնստանտներ են հայտարարված sysConstant կլասում)
    edtNone-եթե ինչ որ խնդիր է առաջացել (0)
    edtExist-եթե տողը գոյություն ունեղող ա (1)
    edtNew-եթե տողը նոր է (2)
    bool SetValue(string columnName, string value)
    false - եթե validation-ը չի անցել (սրա մասին մի քիչ հետո)
    true - եթե ամեն ինչ անցել է
    string GetValue(string columnName)
    վերադարձնում է սյունի արժեքը, եթե չկա ապա դատարկ
    bool Delete()
    bool Write()
    սխալ վերադարձնելու դեպքում սխալի մասին ավելի ինֆորմացիա կարող ենք ստանալ
    public int LastErrorNum
    public string LastErrorMsg
    փոփոխականների միջոցով

    Հիմա ամեն ֆունկցիայի մասին ավելի մանրամասն
    1.SetID
    Կոդը՝
    Կոդ:
     // Set Records to current row
            virtual public int SetId(string uniqueId) {
                int retVal = sysConstant.edtNone;
                this.EditState = sysConstant.edtNone;
                retVal = this.FindId(uniqueId); // from sysMainView
                if (retVal != sysConstant.edtNone) {
                    if (this.cSecurityAccess > sysConstant.securityView) {
                        this.Clear(); // For be sure that memmory is clear
                        // No need to add ID to physical file
                        if (this.SetValue(cTableUniqueCol, uniqueId)) { // Add to current Rec
                            retVal = sysConstant.edtNew;
                            this.EditState = sysConstant.edtNew;
                        }
                    }
                }
                return retVal;
            }
    Վերցնում ենք ստացված արժեքը, փոխանցում FindID—ին, որը հայտարարված է sysMainView կլասում։
    Այնտեղ էդ Id-ով select ենք կազմում Main աղուսյակի վրա, կոդի մաս՝
    Կոդ:
                          string tmpQueryString = "SELECT * FROM @MainTable WHERE @TableUniqCol = @uniqueID;";                        
                           SqlCommand tmpSqlCommand = new SqlCommand(tmpQueryString, sysDataBaseConnect.SQLConnection);
                            tmpSqlCommand.Parameters.AddWithValue("@uniqueID", uniqueId);
                            tmpSqlCommand.Parameters.AddWithValue("@MainTable", cMainTable);
                            tmpSqlCommand.Parameters.AddWithValue("@TableUniqCol", cTableUniqueCol);
                            SqlDataReader resultRec = sysDataBaseConnect.executeQuery(tmpSqlCommand);
                            if (ReadFromTableToRec(resultRec)) {
                                retVal = sysConstant.edtExist;
                            }
    Եթե գոյություն ունի, արժեքները լցնում ենք cCurrentRec-ի և cPhysicalRec-ի մեջ։
    Եթե գոյություն չունի, ապա տողը նոր է, և միայն ավելացնում ենք ID-ն cCurrentRec-ում և թողնում, որպեսզի իր հետ աշխատեն։

    2. SetValue
    Կոդը՝
    Կոդ:
          virtual public bool SetValue(string colName, string value) {            
                 bool retVal = false;
                this.ClearErrors(); // Need to Clear Errors
                value = value.Trim(); // Strip off Spaces
                if (this.cCurrentRec.ContainsKey(colName)) {
                    // validation !!!
                    int tmpRetVal = sysConstant.retValidationNone;
                    if (!cSkipValidation) {
                       tmpRetVal = this.ExecuteValidationFunction(colName, value);
                    }
                    if (tmpRetVal == sysConstant.retValidationSuccess || tmpRetVal == sysConstant.retValidationNone) {
                        this.cCurrentRec[colName] = value;
                        retVal = true;
                    }
                }
                else {
                    this.LastErrorNum = sysConstant.REC_ERROR;
                    this.LastErrorMsg = sysConstant.REC_COLUMN_INVALID;
                }
                return retVal;
            }
    ExecuteValidationFunction - ֆունկցաի համար առանձին պոստ կտարամդրենք, իսկ հիմա ինչպես տեսնում ենք, մուտքագրված արժեքը վերցնում ենք և
    cCurrentRec dictionary-ի մեջ մուտքագրված սյունի համար ավելացնում։
    Այս ֆունկցիաի նման է SetValueNoValidation-ը որ առանց validation է setValue անում։

    3․ GetValue
    Էլ մի միանգամից փակի էջը, էս ֆունկցիան կարճ ա
    Կոդ:
       virtual public string GetValue(string colName) {            
                this.ClearErrors(); // Need to Clear Errors
                string retVal = "";
                if (this.cCurrentRec.ContainsKey(colName)) {
                    retVal = this.cCurrentRec[colName];
                }
                else {
                    this.LastErrorNum = sysConstant.REC_ERROR;
                    this.LastErrorMsg = sysConstant.REC_COLUMN_INVALID;
                }
                return retVal;
            }
    Ինձ թվում է պարզ է կարիք չկա մանրամասնելու։
    Ունենք նաև GetOldValue ֆունկցիան, որը cCurrentRec-ի փոխարեն օգտագործում է cPhysicalRec-ը։

    4. Delete
    Delete-ի մի կտոր՝
    Կոդ:
                 bool preDeleteRetVal = this.PreDeleteRec(uniqueId);
                        if (preDeleteRetVal) {
                            string tmpQueryString = "DELETE FROM @MainTable WHERE @TableUniqCol = @uniqueID;";
                            SqlCommand tmpSqlCommand = new SqlCommand(tmpQueryString, sysDataBaseConnect.SQLConnection);
                            tmpSqlCommand.Parameters.AddWithValue("@uniqueID", uniqueId);
                            tmpSqlCommand.Parameters.AddWithValue("@MainTable", cMainTable);
                            tmpSqlCommand.Parameters.AddWithValue("@TableUniqCol", cTableUniqueCol);
                            int rowsAffected = sysDataBaseConnect.executeNonQuery(tmpSqlCommand);
                            if (rowsAffected == 0) {
                                retVal = false;
                                this.LastErrorNum = sysConstant.SQL_ERROR;
                                this.LastErrorMsg = sysDataBaseConnect.LastErrorMsg;
                            }
                            else {
                                bool postDeleteRetVal = this.PostDeleteRec(uniqueId);
                            }
                        }
    Այստեղ հետաքրքիր է այն, որ delete-ից հետո և առաջ կանչում ենք, postDeleteRec, preDeleteRec ֆունկցիաները, որոնք հայտարարված են virtual և թույլ կտան այս կլասը ժառանգողին առանց delete-ի հիմնական կոդին կպնելու ինչ որ լոգիկաներ ավելացնել։

    Write-ը առանձին թեմա է ու իմ կարծիքով արժանի է, որ իր մասին հետո մի քիչ երկար խոսենք։

  5. #4
    Ուշադիր
    Chuk-ի ավատար
    Գրանցման ամսաթիվ
    17.03.2006
    Հասցե
    Երևան
    Տարիք
    40
    Գրառումներ
    25,245
    Բլոգի գրառումներ
    31
    Mentioned
    82 Post(s)
    Tagged
    1 Thread(s)
    Թեման «Օրագրեր» բաժնից եկավ «Ծրագրավորում» բաժին: Այ հիմա որ չալարենք կարդանք, կարող ենք նաև քննարկել, հարցեր տալ և այլն

    Քայլ առ քայլ՝ դարից դար

    Խենթ եմ

  6. Գրառմանը 1 հոգի շնորհակալություն է հայտնել.

    Աթեիստ (24.02.2015)

  7. #5
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Write-Ֆունկցիան՝

    Մի փոքր պարզաբանեմ՝
    Սկսում ենք հերթով համեմատել ըստ սյուների հին արժեքը և նոր արժեքը, եթե տարբեր են ապա մեր կազմած հարցման մեջ ավելացնում ենք
    դրա SET-ը։
    Եթե աղյուսակի մեջ մեր SetID-ի արած ID-ն կար, այսինքն այդ տողը գոյություն ուներ ապա հարցումը կազմվում է, որպես UPDATE, եթե ոչ ապա INSERT:
    Նրբություն, քանի որ այդ արժեքները գալիս են user-ից հնարավոր Injection-ից խուսափելու համար հարկավոր է, որպեսզի արժեքները որպես պարամետր փոխանցենք հարցմանը։ Դրա համար երբ արդեն իմանում ենք տարբերվող սյուների քանակը(N), մեր հարցմանը ավելացնում ենք param1,param2,...paramN, և զուգահեռաբար զանգված ենք ստեղծում, որի էլեմենտների ինդեկսները համընկնում են param1, param2, param3-ի․․․․ հետ։
    Կոդի հատված՝
    Կոդ:
        foreach (KeyValuePair<string, string> entry in this.cCurrentRec) {                  
      if (entry.Value != this.cPhysicalRec[entry.Key]) {
                            tmpExistQueryValuesAssig += entry.Key + " = @param" + tmpCountOfCols.ToString() + ",";
                            tmpValues[tmpCountOfCols] = entry.Value;
                            tmpCountOfCols++;
                        }
                    }
    Իսկ վերջում, երբ արդեն պարզ է թե հարցումը INSERT INTO է, թե UPDATE, ավելացնում ենք արժեքները՝
    Կոդի հատված՝
    Կոդ:
                for (int i = 0; i < tmpCountOfCols; i++) {                
    tmpSqlCommand.Parameters.AddWithValue("@param" + i.ToString(), tmpValues[i]);
                }
    Հաջորդ գրառումը կլինի սյուների validation—ների կազմակերպան մասին, որից հետո կամփոփենք ունեցածը, որպեսզի շարժվենք առաջ։

  8. Գրառմանը 1 հոգի շնորհակալություն է հայտնել.

    Աթեիստ (25.02.2015)

  9. #6
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Ինչպես խոսք էի տվել, սյուների Validation:

    Գաղտնիք չէ, որ DataBase-ի հետ աշխատելու ընթացքում, երբ սյուներին արժեքներ ենք տալիս, պետք է ինչ որ բան ստուգենք, համեմատենք, ինչ որ պայմանների դեպքում նոր թույլ տանք։ Օրինակ ունենք 2 սյուն` StartingDate, EndingDate, երբ StartingDate-ը 02/25/2015 է, մենք պետք է թույլ չտանք, որպեսզի EndingDate-ը լինի 02/24/2015, ասյինքն ավելի շուտ։

    Քանի որ ինտերֆեյսեր ենք տրամադրում, այսինքն մենք կոնկրետ օբյեկտի մեջ դեռ չգիտենք, թե ի՞նչ թեյբլի հետ ենք աշխատելու, ի՞նչ սյուններ է ունենալու այդ թեյբլը, ինչ տիպի օբյեկտ է մեզ ժառանգել և այլն․․․դրա համար որոշեցի, sysMain-ում պահենք ժառանգած օբյեկտի տիպը, որը ժառանգված օբյեկտը կփոխանցի։
    Այսպես, կոդ՝
    Կոդ:
    this.cInhertedClassType = typeof(this);
    Հիմա հարց կարջանա, թե ինչի համար է այն մեզ պետք․․․պարզաբանեմ․․․
    երկար մտածելուց հետո որոշեցի, որ ամեն սյունի validation-ի համար պատասխան է տալու համապատասխան ֆունկցիան, օրինակ՝
    Կոդ:
    bool Validate_ColumnName(string value)
    Այս ֆունկցաին գրելու է ժառանգված կլասում, ինչպե՞ս մենք իմանաք այս ֆունկցիա-ի մասին վերևի կլասից, մեզ կօգնի reflection-ը։
    Այսինքն, երբ մենք SetValue ենք անում ինչ որ սյունի արժեք, մենք այդ մուտք եղած արժեքը փոխանցում ենք այ էս ֆունկցիաին, կոդի հատված՝
    Կոդ:
     MethodInfo methodInfo = this.cInhertedClassType.GetMethod(tmpFunctionName, BindingFlags.NonPublic | BindingFlags.Instance);               
     if (methodInfo != null) {
         bool tmpRetBool = (bool)methodInfo.Invoke(this, new object[] { arg_value });
            if(tmpRetBool) {
                retVal = sysConstant.retValidationSuccess;
             } else {
                 retVal = sysConstant.retValidationFail;
              }
    }
    Սրանով օգտվելով տիպ-ից կարողանում ենք պարզել արդյոք մեր գրած ֆունկցաին գոյություն ունի, ինչպե՞ս ենք իմանում ֆունկցիաի անունը, շատ պարզ՝
    Կոդ:
    string tmpFunctionName = sysConstant.VALIDATION_FUNCTION_PREFIX + colName;
    VALIDATION_FUNCTION_PREFIX -ը դիֆայն է արված որպես "Validate_":
    Այսինքն արդյունքում մենք կունենաք, օրինակ Validate_StartingDate:

    Եթե չենք գտնում նման ֆունկցիա, ուրեմն մենք առանց validation կարող ենք արժեքը հանգիստ սրտով տեղադրել։

    Հուսով եմ հետաքրքիր էր:

  10. Գրառմանը 1 հոգի շնորհակալություն է հայտնել.

    Աթեիստ (25.02.2015)

  11. #7
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Այսոր վերջապես ահագին բան վերջացրեցի, եկեք տեսնենք թե ինչպես կարող ենք օգտագործել մեր framework-ը և ի՞նչ կարող ենք անել։
    Նախ և առաջ պետք է ժառանգենք մեր հիմնական կլասից և տանք մեր աղուսյակի ու օբյեկտի տվյալները։ Կոդ՝
    Կոդ:
    namespace Batut {    
       class TestPost : Main {
            public TestPost() {
                this.m_InhertedClassType = typeof(TestPost);
                this.m_MainTable = "Post";
                this.m_TableUniqueCol = "PostID";
                this.m_SecurityAccess = Constant.securityWrite;
                this.Init();
            }
            private bool Validate_LongPost(string value) {
              return false;
            }
    
        }
    }
    Մանրամասն ամեն տողը՝
    this.m_InhertedClassType = typeof(TestPost); - եթե հիշում եք սա մեզ անհրաժեշտ էր որպեսզի պարզեինք թե կոնկրետ մեր օբյեկտը validation-ի function-ներ ունի թե չէ
    this.m_MainTable = "Post"; - աղուսյակի անունը
    this.m_TableUniqueCol = "PostID"; - աղուսյակի կլաստերեդ ինդեքսը
    this.m_SecurityAccess = Constant.securityWrite; - եսիմ խի եմ արել, հետագայում կպարզեմ ։Դ
    this.Init(); - init—ը մեր տված արժեքների հիման վրա կլցնի մեր currentRec, physicalRec dictionary—ները

    հիմա եկեք ստեղծենք մեր օբյեկտը և նոր տող ավելացնենք՝
    Կոդ:
    TestPost model = new TestPost(); // ստեղծում ենք մեր օբյեկտը
    int retVal = model.SetId("1"); // Ավելացնում ենք նոր տող 1 ID-ով
    if (retVal == Constant.edtNew) { // ստուգում ենք, որ տողը նոր լինի
        model.SetValue("ShortPost","karch");
        model.SetValue("LongPost","erkar"); // այս արժեքը չի ավելանա, որովհետև վերևում վալիդեյշն ենք գրել, որը false է վերադարձնում
        model.Write(); 
    }
    Շատ ուրախ կլինեմ, որ ներկայացրածս կոդերի մեջ թերացումներս ցույց տաք։ (առաջին փորձս է C#-ով ինչ որ բան գրելու)
    Նաև ուրախ կլինեմ, եթե ինչ որ հարցեր լինեն, խոսենք, քննարկենք, ինչ որ նոր բաններ ավելացնենք։
    Թույալտրվում ա ))

  12. #8
    Պատվավոր անդամ Lusina-ի ավատար
    Գրանցման ամսաթիվ
    06.12.2010
    Տարիք
    34
    Գրառումներ
    1,186
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Մեջբերում Արամ-ի խոսքերից Նայել գրառումը
    Շատ ուրախ կլինեմ, որ ներկայացրածս կոդերի մեջ թերացումներս ցույց տաք։ (առաջին փորձս է C#-ով ինչ որ բան գրելու)
    Նաև ուրախ կլինեմ, եթե ինչ որ հարցեր լինեն, խոսենք, քննարկենք, ինչ որ նոր բաններ ավելացնենք։
    Թույալտրվում ա ))
    Նկար

    Արի կլինի տեղափոխվի ձախ ճամբար էլի

    Հ.Գ. Ներող, չդիմացա, "Թույալտրվում ա "-ն չլիներ, չէի գրի

  13. Գրառմանը 1 հոգի շնորհակալություն է հայտնել.

    Աթեիստ (07.03.2015)

  14. #9
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Մեջբերում Lusina-ի խոսքերից Նայել գրառումը
    Նկար

    Արի կլինի տեղափոխվի ձախ ճամբար էլի

    Հ.Գ. Ներող, չդիմացա, "Թույալտրվում ա "-ն չլիներ, չէի գրի
    Հետագայում, երբ որ կոդը դնեմ համացանցում, կփոխեմ։

  15. Գրառմանը 1 հոգի շնորհակալություն է հայտնել.

    Lusina (07.03.2015)

  16. #10
    ^ ^ Արամ-ի ավատար
    Գրանցման ամսաթիվ
    29.10.2006
    Հասցե
    Երևան
    Գրառումներ
    4,981
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Ձեր արձագանքերը այդքան էլ հուսադրող չեն, բայց դե այսօր մի քիչ բզբզացի, կոդերը գցեցի github, կարող եք նայել, ուսումնասիրել, ուղղել և այլն․․
    Հա՛, թույլատրվում ա ))

    https://github.com/AramKocharyan/BatutConnector

Թեմայի մասին

Այս թեման նայող անդամներ

Այս պահին թեմայում են 1 հոգի. (0 անդամ և 1 հյուր)

Համանման թեմաներ

  1. Գրառումներ: 29
    Վերջինը: 10.07.2012, 13:26
  2. Երկաթուղին կտան օտարերկրյա կառավարման
    Հեղինակ՝ Marduk, բաժին` Քաղաքականություն
    Գրառումներ: 42
    Վերջինը: 18.06.2011, 10:25
  3. Սևանա լճի ջրային ռեսուրների կառավարման մոդել
    Հեղինակ՝ Adriano, բաժին` Մարդ և շրջակա միջավայր
    Գրառումներ: 7
    Վերջինը: 26.08.2010, 18:12
  4. Կառավարման, որ ձևն է ընդունելի Հայաստանի համար?
    Հեղինակ՝ Adriano, բաժին` Քաղաքականություն
    Գրառումներ: 1
    Վերջինը: 02.02.2010, 08:24

Էջանիշներ

Էջանիշներ

Ձեր իրավունքները բաժնում

  • Դուք չեք կարող նոր թեմաներ ստեղծել
  • Դուք չեք կարող պատասխանել
  • Դուք չեք կարող կցորդներ տեղադրել
  • Դուք չեք կարող խմբագրել ձեր գրառումները
  •