• 0
daziplqa

سُبات: أداة ORM

سؤال

السلام عليكم و رحمة الله و بركاته,

بسم الله الرحمن الرحيم

لقد قمت بالأيام الماضيه في المحاوله لبناء أداة ORM, و قد أسميتها "سُبات" (Sobat).(أي النوم العميق) (كمشروع على googlecode.com)

في الحقيقه لم أقم بالكثير من العمل, فالأداه مازالت بدائيه جدا و ينقصا الكثير و الكثير, فأنا أحتاج مساعدتكم في القيام بهذا الأمر, و سأستعرض هنا ما تقوم به هذه الأداه.

1- لكي تقوم بتجربة "سُبات" فيجب عليك تنصيب MySQL عندك, فهي حاليا تعمل معه فقط (ولكن ليس من الصعب أن نجعلها تعمل مع قواعد بيانات أخري) كل ماعليك هو أن ترث الواجهه (implements) :

com.googlecode.sobat.ql.dialect.Dialect

و تقوم بالتعديل على الدالة :

com.googlecode.sobat.configuration.Bootstrap.getDialect()

2- بعد أن تنصب MySQL قم بتنفيذ الإسكربت التالي في قاعدة بياناتك :

-- MySQL v5.x

create database IF NOT EXISTS mahmood;

CREATE TABLE IF NOT EXISTS `question_deatil` (
`id` bigint(20) NOT NULL auto_increment,
`quest` varchar(100) collate utf8_unicode_ci default NULL,
`QA` varchar(100) collate utf8_unicode_ci default NULL,
`QB` varchar(100) collate utf8_unicode_ci default NULL,
`QC` varchar(100) collate utf8_unicode_ci default NULL,
`QD` varchar(100) collate utf8_unicode_ci default NULL,
`correctAns` varchar(100) collate utf8_unicode_ci default NULL,
`image` varbinary(20000) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;


truncate table `question_deatil` ;

ملحوظه: لقد إستعرت قاعدة البيانات هذه من الأخ محمود سامي أعانه الله ووفقه.

3-إفتح بيئة التطوير التي تستخدما (إكليبس, نتبينز , ...) و إنشأ مشروعا جديدا ثم ضع الملف sobat.1.0.0.jar في ال classpath (لاتنسي ال JDBC Driver الخاص ب MySQL )

4- قم بإنشاء حزمة جديده و لتكن : com.my.sobattest

5 - قم بإنشاء ملف إكس إم إل التالي و سمه "mapping.xml” و ضعه بجانب الحزمه (أي ليس بداخلها ) :

<?xml version="1.0" encoding="UTF-8"?>
<mapping>

<!-- You can specify a DataSource (In Java EE env): -->
<!--
<datasource jndi="jdbc/test" >
<initial-context-factory>com.sun.jndi.rmi.registry.RegistryContextFactory</initial-context-factory>
<provider-url>rmi://localhost:1099</provider-url>
</datasource>
-->

<!-- Or use plain JDBC -->
<driver-manager>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<connection-url>jdbc:mysql://localhost:3306/mahmood</connection-url>
<user-name>root</user-name> <!-- your username -->
<password>system</password> <!-- your password -->
<dialect>MySQLDialect</dialect>
</driver-manager>

<class path="com/my/sobattest/QuestionDetail.xml" />
</mapping>

فيكون بذلك شكل المسارات عندك كالتالي :

+com
+my
+sobattest
+mapping.xml

6- قم إنشاء فئة لتمثيل الجدول "question_deatil” ولتكن إسمها QuestionDetail

package com.my.sobattest;

public class QuestionDetail {
private long id;
private String question;
private String correctAnswer;
private String AnswerA;
private String AnswerB;
private String AnswerC;
private String AnswerD;
private byte[] image;

private void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getCorrectAnswer() {
return correctAnswer;
}
public void setCorrectAnswer(String correctAnswer) {
this.correctAnswer = correctAnswer;
}
public String getAnswerA() {
return AnswerA;
}
public void setAnswerA(String answerA) {
AnswerA = answerA;
}
public String getAnswerB() {
return AnswerB;
}
public void setAnswerB(String answerB) {
AnswerB = answerB;
}
public String getAnswerC() {
return AnswerC;
}
public void setAnswerC(String answerC) {
AnswerC = answerC;
}
public String getAnswerD() {
return AnswerD;
}
public void setAnswerD(String answerD) {
AnswerD = answerD;
}
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
}

7- قم بإضافة ملف ال إكس إم إل التالي بجانب الفئة التي تم إنشاؤها بالخطوه السابقه و سمه "QuestionDetail.xml" :


<?xml version="1.0" encoding="UTF-8"?>
<class name="QuestionDetail" table="question_deatil" dynamic-update="true"> <!-- dynamic-update: default is true -->
<id name="id" column="id" type="bigint" /> <!-- type takes values from java.sql.Types members - case insensitive -->
<property name="question" type="varchar" column="quest" />
<property name="correctAnswer" type="varchar" column="correctAns" />
<property name="AnswerA" type="varchar" column="QA" />
<property name="AnswerB" type="varchar" column="QB" />
<property name="AnswerC" type="varchar" column="QC" />
<property name="AnswerD" type="varchar" column="QD" />
<property name="image" type="varbinary" column="image" />
</class>

8- قم بإضافه فئه و سمها مثلا Test و ضع بها الكود التالي :

package com.my.sobattest;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;

import com.googlecode.sobat.Query;
import com.googlecode.sobat.Session;
import com.googlecode.sobat.SessionManager;
import com.googlecode.sobat.ql.From;
import com.googlecode.sobat.ql.OrderBy;
import com.googlecode.sobat.ql.Projection;
import com.googlecode.sobat.ql.Where;
import com.googlecode.sobat.ql.OrderBy.Order;
import com.googlecode.sobat.ql.condition.Conditions;
import com.googlecode.sobat.ql.condition.CreateCondition.Type;

public class Test {

public static void main(String[] args) throws Exception{

CRUDExample1();
CRUDExample2();
CRUDExample3();
CRUDExample4();
CRUDExample1();
CRUDExample5();
QLExample1();
QLExample2();
createSQLQueryExample1();
createSQLQueryExample2();
}

public static void CRUDExample1() throws SQLException, IOException{
SessionManager mgr = SessionManager.getSessionManager();
Session session = mgr.newSession();
session.beginTransaction();

QuestionDetail qd = new QuestionDetail();
qd.setQuestion("How are you ? ");
qd.setAnswerA("AA");
qd.setAnswerB("answerB");
qd.setAnswerD("DDX");
qd.setCorrectAnswer("Fine");
InputStream imageStream = Test.class.getClassLoader().getResourceAsStream("com/googlecode/sobat/examples/image.png");

ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int b = 0;
while ( (b = imageStream.read()) != -1)
byteStream.write(b);
byte[] image = byteStream.toByteArray();
qd.setImage(image);
session.save(qd);

session.commitTransaction();
session.close();
}

public static void CRUDExample2() throws SQLException{
SessionManager mgr = SessionManager.getSessionManager();
Session session = mgr.newSession();
session.beginTransaction();

QuestionDetail qd = session.get(QuestionDetail.class, new Long(1));
qd.setAnswerB("Fine");
session.update(qd);

session.commitTransaction();
session.close();
}

/**
* Dirty checking
* @throws SQLException
*/
public static void CRUDExample3() throws SQLException{
SessionManager mgr = SessionManager.getSessionManager();
Session session = mgr.newSession();
session.beginTransaction();

QuestionDetail qd = session.get(QuestionDetail.class, new Long(1));

session.commitTransaction();
session.close();

// update the detached object out of any session
qd.setAnswerC("Answer C");

Session session2 = SessionManager.getSessionManager().newSession();
session2.beginTransaction();
// the second session determined that the detached object has changed (became dirty) and it updated it
session2.update(qd);

session2.commitTransaction();
session2.close();
}

/**
* Delete
* @throws SQLException
*/
public static void CRUDExample4() throws SQLException{
SessionManager mgr = SessionManager.getSessionManager();
Session session = mgr.newSession();
session.beginTransaction();

QuestionDetail qd = session.get(QuestionDetail.class, new Long(1));
session.delete(qd);

session.commitTransaction();
session.close();
}

/**
* Get All
* @throws SQLException
*/
public static void CRUDExample5() throws SQLException{
SessionManager mgr = SessionManager.getSessionManager();
Session session = mgr.newSession();
session.beginTransaction();

List<QuestionDetail> qdList = session.get(QuestionDetail.class);
printObjectList(qdList);

session.commitTransaction();
session.close();
}

/**
* Query Language Example1 <br />
* It illustrates basic usage of Sobat Query Language (actually it is an API rather than a Language)
*/
public static void QLExample1(){

From from = new From(QuestionDetail.class);
Conditions conditions = new Conditions(from);
conditions.addCondition(Type.Equals, "AnswerA", "AA");
Where where = new Where(from , conditions);
OrderBy orderBy = new OrderBy(where, "id", Order.ASC);
OrderBy orderBy2 = new OrderBy(orderBy, "question", Order.DESC);

List<QuestionDetail> result = orderBy2.execute();
printObjectList(result);
}

/**
* Query Language Example2 <br />
* Its usage Illustrate projection
*/
public static void QLExample2() {

From from = new From(QuestionDetail.class);
Projection projection = new Projection(from, new String[] {"question", "correctAnswer", "AnswerA", "AnswerB", "AnswerA"});
OrderBy orderBy = new OrderBy(projection, "id", Order.DESC);

List<Object[]> result = orderBy.execute();
printArrayList(result);
}

/**
* Native SQLQuery Example1 <br />
* shows how to use native SQL Queries (MYSQL, M$ SQL Server, Oracle, etc), although, this usage reduces application portability across
* Databases
* @throws Exception
*/
public static void createSQLQueryExample1() throws Exception{
SessionManager mgr = SessionManager.getSessionManager();
Session session = mgr.newSession();
session.beginTransaction();

Query query = session.createSQLQuery("SELECT quest, correctAns, QA, QB, QA FROM question_deatil WHERE QA = 'AA' ORDER BY id ASC",
null);
List<Object[]> list = query.execute();
printArrayList(list);

session.commitTransaction();
session.close();
}

public static void createSQLQueryExample2() throws Exception{

SessionManager mgr = SessionManager.getSessionManager();
Session session = mgr.newSession();
session.beginTransaction();

Query query = session.createSQLQuery("SELECT * FROM question_deatil WHERE QA = 'AA' ORDER BY id ASC",
QuestionDetail.class);
List<QuestionDetail> result = query.execute();
printObjectList(result);

session.commitTransaction();
session.close();
}

public static void printObjectList(List<QuestionDetail> qdList) {
for (QuestionDetail obj: qdList)
System.out.println(obj.getQuestion() + "\t-\t" + obj.getCorrectAnswer() + "\t-\t" + obj.getAnswerA() + "\t-\t" + obj.getAnswerB()
+ "\t-\t" + obj.getAnswerC() +"\t-\t" + obj.getAnswerD());
}

public static void printArrayList(List<Object[]> qdList) {
for (Object[] arr : qdList) {
for (Object obj : arr)
System.out.print(obj + "\t-\t");
System.out.println();
}
}

}

10- قم بتنفيذ الفئه Test وراقب النتائج.

Feb 28, 2010 5:30:03 PM com.googlecode.sobat.configuration.Bootstrap <clinit>
INFO: Initializing sobat..
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doSave
INFO: SOBAT: INSERT INTO question_deatil (quest, correctAns, QA, QB, QD, image ) VALUES ( ?, ?, ?, ?, ?, ? )
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doGet
INFO: SOBAT: SELECT * FROM question_deatil WHERE id = 1
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doUpdate
INFO: SOBAT: UPDATE question_deatil SET QB = ?, image = ? WHERE id = 1
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doGet
INFO: SOBAT: SELECT * FROM question_deatil WHERE id = 1
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doUpdate
INFO: SOBAT: UPDATE question_deatil SET QC = ?, image = ? WHERE id = 1
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doGet
INFO: SOBAT: SELECT * FROM question_deatil WHERE id = 1
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doDelete
INFO: SOBAT: DELETE FROM question_deatil WHERE id = 1
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doSave
INFO: SOBAT: INSERT INTO question_deatil (quest, correctAns, QA, QB, QD, image ) VALUES ( ?, ?, ?, ?, ?, ? )
Feb 28, 2010 5:30:03 PM com.googlecode.sobat.SessionImpl doGet
INFO: SOBAT: SELECT * FROM question_deatil
How are you ? - Fine - AA - answerB - null - DDX
Feb 28, 2010 5:30:04 PM com.googlecode.sobat.SQLQuery execute
INFO: Sobat : SELECT * FROM question_deatil WHERE QA = 'AA' ORDER BY quest DESC
How are you ? - Fine - AA - answerB - null - DDX
Feb 28, 2010 5:30:04 PM com.googlecode.sobat.SQLQuery execute
INFO: Sobat : SELECT quest, correctAns, QA, QB, QA FROM question_deatil ORDER BY id DESC
How are you ? - Fine - AA - answerB - AA -
Feb 28, 2010 5:30:04 PM com.googlecode.sobat.SQLQuery execute
INFO: Sobat : SELECT quest, correctAns, QA, QB, QA FROM question_deatil WHERE QA = 'AA' ORDER BY id ASC
How are you ? - Fine - AA - answerB - AA -
Feb 28, 2010 5:30:04 PM com.googlecode.sobat.SQLQuery execute
INFO: Sobat : SELECT * FROM question_deatil WHERE QA = 'AA' ORDER BY id ASC
How are you ? - Fine - AA - answerB - null - DDX

ملحوظه, إن لم تستطع تطبق المثال السابق, فقم بتنفيذ الفئة :

com.googlecode.sobat.examples.Test 

فإن بها نفس المثال.

و في النهايه, أريد أراءكم في فكره بناء ORM جديده, و أريد مقتراحاتكم و مساهمتكم,

دمتم بخير.

تم تعديل بواسطه {هويدي}
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

8 إجابة على هذا السؤال .

  • 0

السلام عليكم ورحمة الله وبركاته

اخي العزيز هويدي :blush:

طبعا اشكرك على الدعاء :wub:

وكذلك إن شاء الله انت وبقية اخوتي اعضاء المنتدى مخولين باخذ اشياء من عملي خدمة للاسلام والمسلمين وجعلنا الله من جنوده :ph34r:

اخي ما هي أداة ORM

بصراحة لم توضح لي الفكرة واقصد ليس في البرمجة انما (أداة ORM) ماهو عملها :blink: واين تكمن فائدتها ؟

سلامي

اخوك

محمود سامي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

سلام عليكم

شكرا على المجهود

فى شوية اسئلة زى ايه الميزة مقارنة ب iBATIS مثلا ؟ او Hibernate ؟او شئ قياسى مثل JPA ؟

بما انك عرضت موضوع ال xml فاقترح شئ بردو زى iBator

بخصوص اسلوب الإستخدام انا افضل يكون شئ مشابه للتالى اذا اسلوب الإستخدام قابل للنقاش :)


db.select(COLUMNSLIST);
db.where(COND);
db.orderby(ORDERING);
db.get/db.update,db.delete//db.insert

اومشابه لكدا


db.select( ).from().where().orderby()

امكانية استخدام ال annotations ؟

العلاقات بين الجداول المختلفة ؟

تم تعديل بواسطه ahmed_youssef
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جميل جداً يا حج هويدي

أعجبني اسم سبات بالمناسبة

لماذا قررت أن تعمل على هذه الحزمة

مع أن حزم مثل Hibernate تقوم بالمطلوب وكفاية

هل هناك مفاهيم جديدة تريد أن تضيفها

ثم لو كان هذا الكلام صحيحاً فلماذا لا تعتمد Hibernate كنقطة بداية

هل الهدف تعليمي مثلاً؟

(لا تعتقد أني أقلل من قيمة الهدف التعليمي بل أنا أجد الكثير من الناس تعمل من أجل الهدف التعليمي)

تحياتي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أخي : محمود سامي, جزاك الله خيرا , كذا إنظر يا أخي هذا الرابط

أخي : أحمد يوسف :

بالنسبه لأسلوب إستخدام ال Query API , فهو ليس حكرا, أنا أرحب بكل أفكار جديده و مساهمات من الأخوه كل ما فكرت به أن أجعل الQuery API تبدوا ك Decorator pattern (تماما مثل Java io)

بالنسبه لإستخدام ال annotations فالموضوع يسير, و أنا حاليا أعمل عليه و قاربت من الإنتهاء إن شاء الله

العلاقات بين الجداول المختلفة :unsure: هذا هو مربط الفرس, لم أسطر سطر واحد فيها !!!

أخي علاء :

لقد أخترت إسم سُبات خصيصا :)

حقيقة كل ما أحاول أن أفعله هو أن أقلد Hibernate و JPA ! للأسف !

حقا نحتاج لفكر جديد, و لذا لجأت لكم إخوتي في الله لتتكامل أفكارنا و نخرج بشئ جديد ممكن أن ينافس.

نعم الهدف ينقسم إلي شقين, و ليس أكبرهما الشق التعليمي, و لكن أكبرهما هو أن نخرج نحن العرب شئ إلي النور يكون عربي 100% (قد أبدو عنصريا أو متعصبا و لكن هذا أنا :) )

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أولاً: بارك الله بجهودك وأعاننا وإياك على نفع الأمة

ثانياً: هل هناك أية فائدة من إنشاء تحقيق implementation أخرى من JPA ؟!

لا أظن ذلك، بل أظن أنه جهد مكرر وهدر لوقتك ... والأنفع تعلم وإتقان كيفية استخدام هذه التقنيات بدلاً من إنشاء نسخة "مخففة" منها !

هل تعلم كم أداة ORM متوافرة لجافا ؟! إذاً انظر هنا:

http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software#Java

ما هو الأفضل عمله إذاً ؟

أنا من أكبر مؤيدي إنتاج برامج وحزم عربية 100% ... لكني ضد إعادة اختراع العجلة !

حتى إنها عجلة غير مستوية !

فكما تعلم كل تقنيات ORM تستخدم لردم الفجوة بين النموذج الغرضي التوجه والنموذج العلائقي ... أما إذا كنت ستصنع برنامجاً جديداً وليس من المطلوب توافقه مع قواعد بيانات علائقية قديمة فالأفضل استخدام قاعدة بيانات غرضية التوجه (مثل db4o)

كما أن تقنيات مثل JDO أكثر عمومية من JPA وقليلة الاستخدام عربياً رغم فوائدها الجمة !

تقديم دروس في هذه المواضيع أكثر فائدة بكثير !

أما إذا كنت ترغب بإنشاء برامج وحزم عريبة 100% فلماذا لا نتساعد في إنتاج برامج عربية فريدة ويوجد حاجة كبيرة لها ونقص كبير فيها مثل: OCR أو TTS عربي ! أعلم أن الموضوع صعب، لكنه مجرد اقتراح !

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

موضوع اختراع العجلة هذا موضوع مبالغ فيه قليلاً أو قل كثيراً

انظر حولك أخي Speed_Of_Light وأشر لي على شركة محترمة واحدة لم تعد اختراع العجلة

الكل يقوم بإعادة العجلة وعندما نقرر نحن المسلمون أن نعيد اختراعها تجد ألف ناعق (لا أقصدك أخي في الله ولكن أقصد من زرع الفكرة في رؤوسنا)

كلهم يقول لك يا غبي لا تخترع العجلة يا غبي لا تخترع العجلة نحن نقدمها لك بسعر زهيد

فتأتي أنت يا مسكين وتقول أه فعلاً هم يعطوني اياها بسعر زهيد

ثم إذ فجأة تجده بنى على العجلة سيارة كبيرة شامخة

طبعاً هو يجيد البناء عليها بشكل جيد أما أنت يا مسكين فستعاني الأمرين

لي وجهة نظر مخالفة في موضوع اختراع العجلة وأراها في وضع الأمة الإسلامية واجب على كل مسلم

أعد اختراع العجلة فنحن بحاجة لعجلات من إنتاجنا سواءاً كانت معاد اختراعها أو مستصلحة أو حتى مكسرة

امضي أخي هويدي

تحياتي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أخي علاء أحترم وجهة نظرك، لكن دعني أوضح وجهة نظري:

كلهم يقول لك يا غبي لا تخترع العجلة يا غبي لا تخترع العجلة نحن نقدمها لك بسعر زهيد

فتأتي أنت يا مسكين وتقول أه فعلاً هم يعطوني اياها بسعر زهيد

أنا لم أقصد العجلات ذات السعر الزهيد، قصدت العجلات المجانية تماماً والتي يمكنك الإطلاع على مخططات تصميمها (مفتوحة المصدر) ويمكنك المشاركة في بنائها من حيث وصلوا، وليس من البداية !!

الكل يقوم بإعادة العجلة وعندما نقرر نحن المسلمون أن نعيد اختراعها تجد ألف ناعق (لا أقصدك أخي في الله ولكن أقصد من زرع الفكرة في رؤوسنا)

كل من يقوم باختراع العجلة لديه سبب يقنعه!

جماعة المصادر المفتوحة يمكن أن يعيدو اختراع العجلة فقط لتوفير رخصة أكثر انفتاحاً ...

أما نحن فلدينا نقص في الكثير من الأمور والتي سبقنا العالم فيها أشواطاً بعيدة !

كما أنك تعلم مقدار الارتباك الذي يمكن أن تسببه كثرة الأدوات والخيارات والمواصفات القياسية للمبرمج -وخاصة في الـ ORM في جافا ! JPA/JDO/Hibernate/TopLink/EclipseLink/accessplatform/EJB2-

المسألة ليست مسألة "نعق" ... لا

بل المسألة هي مراعات الأولويات، والاهتمام بالأهم

فمن المعروف وجود نقص حاد في كثير من البرمجيات "ذات الخصوصية" العربية. هذه بعض الأمثلة في الذكاء الصنعي (TTS / OCR / Voice Recognition)

طبعاً النقص موجود في كافة فروع التكنولوجيا، ليس أبسطها دعم اللغة العربية في كثير من البرامج المفتوحة المصدر، أو القيام بتعريبها ... إلخ

المشكلة الحقيقية ليس في إعادة اختراع العجلة، نعم من المفيد أن نعرف كيف نخترع العجلة، لكن الأهم بكثير أن نعرف أن نستخدم العجلة !

حيث تجد عندنا أيضاً نقص معرفي كبير في اتقان استخدام التقنيات الموجودة أصلاً والتي لها دور وفعالية كبيرة في العالم، ومجرّبة ومثبتة الفعالية !

وكما يمكنك أن تري في ردي، أنا لست مثبطاً للهمم، بل على العكس، أنا أشجع على توجيه هذا الجهد في المسار الصحيح، حيث يوجد النقص، وبإذن الله سأبذل قصارى جهدي في دعم ومساعدة أي برنامج عربي مفتوح المصدر أجد أنه نافع ومفيد.

إذاً الفكرة هي ترشيد هذا الجهد الرائع واستخدامه في موطن الحاجة.

أتمنى أن تكون الفكرة وصلت

سلام

تم تعديل بواسطه Speed_Of_Light
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

وصلت وجهة نظرك واقتنعت بها :)

تحياتي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
زوار
This topic is now closed to further replies.

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .