123 |
124 |
125 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/user_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
27 |
28 |
29 |
38 |
39 |
45 |
46 |
47 |
48 |
59 |
60 |
61 |
72 |
73 |
74 |
85 |
86 |
87 |
88 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sent_chat_file_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
13 |
14 |
17 |
18 |
21 |
22 |
23 |
28 |
29 |
30 |
38 |
39 |
40 |
53 |
54 |
68 |
69 |
70 |
85 |
86 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/privacy_policy:
--------------------------------------------------------------------------------
1 | Privacy Policy
2 | amr mohammed ali built the OurChat app as a Free app. This SERVICE is provided by amr mohammed ali at no cost and is intended for use as is.
3 |
4 | This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use my Service.
5 |
6 | If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that I collect is used for providing and improving the Service. I will not use or share your information with anyone except as described in this Privacy Policy.
7 |
8 | The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which is accessible at OurChat unless otherwise defined in this Privacy Policy.
9 |
10 | Information Collection and Use
11 |
12 | For a better experience, while using our Service, I may require you to provide us with certain personally identifiable information. The information that I request will be retained on your device and is not collected by me in any way.
13 |
14 | The app does use third party services that may collect information used to identify you.
15 |
16 | Link to privacy policy of third party service providers used by the app
17 |
18 | Google Play Services
19 | Log Data
20 |
21 | I want to inform you that whenever you use my Service, in a case of an error in the app I collect data and information (through third party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other statistics.
22 |
23 | Cookies
24 |
25 | Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.
26 |
27 | This Service does not use these “cookies” explicitly. However, the app may use third party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this Service.
28 |
29 | Service Providers
30 |
31 | I may employ third-party companies and individuals due to the following reasons:
32 |
33 | To facilitate our Service;
34 | To provide the Service on our behalf;
35 | To perform Service-related services; or
36 | To assist us in analyzing how our Service is used.
37 | I want to inform users of this Service that these third parties have access to your Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.
38 |
39 | Security
40 |
41 | I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and I cannot guarantee its absolute security.
42 |
43 | Links to Other Sites
44 |
45 | This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.
46 |
47 | Children’s Privacy
48 |
49 | These Services do not address anyone under the age of 13. I do not knowingly collect personally identifiable information from children under 13. In the case I discover that a child under 13 has provided me with personal information, I immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact me so that I will be able to do necessary actions.
50 |
51 | Changes to This Privacy Policy
52 |
53 | I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.
54 |
55 | Contact Us
56 |
57 | If you have any questions or suggestions about my Privacy Policy, do not hesitate to contact me at afoda50@gmail.com.
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Our Chat
2 |
3 | A modern Android chat application with real-time messaging, push notifications, and support for audio messages, image sharing, and file sharing. Built with Kotlin and following MVVM architecture patterns.
4 |
5 | ## Setup Instructions
6 |
7 | ### Prerequisites
8 | - Android Studio Hedgehog (2023.1.1) or later
9 | - JDK 17 or later
10 | - Android SDK 34
11 | - Firebase project
12 |
13 | ### Configuration
14 |
15 | #### 1. Firebase Setup
16 | 1. Create a Firebase project at [Firebase Console](https://console.firebase.google.com/)
17 | 2. Add an Android app to your Firebase project
18 | 3. Download the `google-services.json` file
19 | 4. Place `google-services.json` in the `app/` directory
20 | 5. **Configure Firestore Security Rules**:
21 | - Go to Firebase Console > Firestore Database > Rules
22 | - Deploy the security rules from `firestore.rules` file in this project
23 | - The rules allow authenticated users to:
24 | - Read any user document
25 | - Create/update/delete their own user document
26 | - Read/create/update/delete messages they are part of
27 | - **Important**: Without proper security rules, the app will crash with permission errors
28 |
29 |
30 | ### Building the Project
31 |
32 | 1. Clone the repository
33 | 2. Open the project in Android Studio
34 | 3. Sync Gradle files
35 | 4. Ensure all prerequisites are met
36 | 5. Add `google-services.json` to the `app/` directory
37 | 6. Build and run the project
38 |
39 |
40 |
41 |
42 | ## Technology Stack
43 |
44 | ### Architecture & Design Patterns
45 | - **MVVM (Model-View-ViewModel)** - Clean architecture pattern
46 | - **Single Activity Architecture** - Multiple fragments with Navigation Component
47 | - **ViewBinding & DataBinding** - Type-safe view references and declarative layouts
48 | - **Lifecycle-Aware Components** - AndroidX Lifecycle 2.7.0
49 |
50 | ### Libraries & Frameworks
51 | - **AndroidX Navigation 2.7.7** - Type-safe navigation with Safe Args
52 | - **Material Design Components 1.11.0** - Modern Material 3 UI components
53 | - **AndroidX Lifecycle 2.7.0** - ViewModel, LiveData, and lifecycle management
54 | - **Glide 4.16.0** - Image loading and caching
55 | - **EventBus 3.3.1** - Event-driven communication
56 | - **Gson 2.10.1** - JSON serialization
57 | - **Dexter 6.2.3** - Runtime permissions handling
58 |
59 | ### Firebase Services
60 | - **Firebase Authentication** - Email/password authentication
61 | - **Cloud Firestore** - Real-time NoSQL database
62 | - **Firebase Storage** - File and media storage
63 | - **Firebase Cloud Messaging (FCM)** - Push notifications
64 | - **Firebase Analytics** - User analytics and insights
65 | - **Firebase Crashlytics** - Crash reporting and monitoring
66 | - **Firebase BoM 32.8.0** - Dependency version management
67 |
68 | ### Android System Services
69 | - **Download Manager** - File downloads
70 | - **Media Recorder** - Audio recording
71 | - **Notification Manager** - Push notifications
72 |
73 | ## Features
74 |
75 | | Feature | Description | Screenshots |
76 | |---------|-------------|-------------|
77 | | **Messages List** | View all your conversations in one place with real-time updates | |
78 | | **Chatting** | Send and receive messages in real-time with rich media support | |
79 | | **User Profile** | Update your profile information and pictures from camera or gallery | |
80 | | **Find Friends** | Search for users to connect with | |
81 | | **Incoming Friend Requests** | View and manage friend requests from other users | |
82 | | **Contacts List** | Access your contacts and start conversations | |
83 |
84 | ## Project Structure
85 |
86 | ```
87 | app/src/main/java/com/ganainy/ourchat/
88 | ├── data/
89 | │ └── model/ # Data models (User, Message, ChatParticipant, etc.)
90 | ├── service/ # Background services (FCM, etc.)
91 | ├── ui/ # UI components organized by feature
92 | │ ├── chat/ # Chat functionality
93 | │ ├── contacts/ # Contacts management
94 | │ ├── findUser/ # User search and discovery
95 | │ ├── home/ # Home screen with chat previews
96 | │ ├── login/ # Authentication
97 | │ ├── profile/ # User profile management
98 | │ └── ...
99 | └── Utils/ # Utility classes and helpers
100 | ```
101 |
102 | ## Minimum Requirements
103 |
104 | - **Minimum SDK**: 23 (Android 6.0 Marshmallow)
105 | - **Target SDK**: 34 (Android 14)
106 | - **Compile SDK**: 34
107 |
108 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/incoming_chat_file_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
19 |
20 |
21 |
22 |
26 |
27 |
36 |
37 |
38 |
55 |
56 |
69 |
70 |
71 |
85 |
86 |
92 |
93 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/contact_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
11 |
12 |
23 |
24 |
28 |
29 |
38 |
39 |
55 |
56 |
72 |
73 |
82 |
83 |
94 |
95 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
15 |
19 |
20 |
24 |
28 |
31 |
32 |
37 |
41 |
44 |
47 |
50 |
53 |
56 |
57 |
61 |
64 |
67 |
71 |
72 |
77 |
80 |
81 |
82 |
83 |
87 |
91 |
95 |
98 |
101 |
102 |
106 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/home_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
13 |
14 |
15 |
25 |
26 |
27 |
28 |
29 |
35 |
36 |
37 |
49 |
50 |
51 |
67 |
68 |
69 |
83 |
84 |
85 |
86 |
87 |
100 |
101 |
102 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sent_audio_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
13 |
14 |
17 |
18 |
21 |
22 |
23 |
28 |
29 |
36 |
37 |
51 |
52 |
61 |
62 |
72 |
73 |
82 |
83 |
93 |
94 |
102 |
103 |
104 |
105 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/received_audio_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
13 |
14 |
17 |
18 |
21 |
22 |
23 |
28 |
29 |
36 |
37 |
51 |
52 |
61 |
62 |
72 |
73 |
82 |
83 |
93 |
94 |
102 |
103 |
104 |
105 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/received_request_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
21 |
22 |
26 |
27 |
28 |
36 |
37 |
44 |
45 |
46 |
47 |
63 |
64 |
65 |
83 |
84 |
85 |
94 |
95 |
96 |
111 |
112 |
113 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/chat_outer_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
26 |
27 |
28 |
37 |
38 |
44 |
45 |
46 |
53 |
54 |
55 |
56 |
67 |
68 |
69 |
81 |
82 |
83 |
94 |
95 |
96 |
97 |
98 |
108 |
109 |
110 |
119 |
120 |
121 |
134 |
135 |
136 |
137 |
138 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Our chat
3 | Enter your email address
4 | Enter your password
5 | Enter your user name
6 | Don\'t have an account?
7 | Create an account
8 | Login
9 | Welcome back!
10 | Log in to your account to continue
11 | Create an account
12 | Sign up to get started
13 | Email
14 | Password
15 | Username
16 | Register
17 | Already have an account?
18 | Log in
19 | Social login
20 | Wrong email format
21 | Password must be at least 6 characters
22 | Settings
23 | Logout
24 | Add friend
25 | Search
26 | Bio
27 | Edit
28 | Friends
29 | Select profile picture
30 | Take new profile picture
31 | Uploading...
32 | Type something to let your friends know you better
33 | Submit
34 | Cancel request
35 | Send friend request
36 | Confirm
37 | Delete
38 | Incoming requests
39 | No incoming requests
40 | No friends yet
41 | Find friends
42 | Profile
43 | No chat history yet, Click chat button to start chatting
44 | No chat history yet
45 | Click chat button to start chatting
46 | No one to chat with yet, Add friends to get going!
47 | Type a message
48 | Can\'t send empty message
49 |
50 |
51 |
52 |
53 | You: %1$s
54 | %1$s: %2$s
55 | %1$s sent an image
56 | %1$s sent a file
57 | No users to add yet.
58 | You sent an image
59 | Send file
60 | Send picture
61 | you sent a file
62 | you sent a voice record
63 | %1$s sent a voice record
64 | Remove from friends
65 | User has no friends yet
66 | SEARCH RESULTS
67 | No users found
68 | Try a different name or check your spelling.
69 | Search by name or username
70 | Check back later for new friend requests
71 | Messages
72 | Account
73 | Open navigation drawer
74 | Close navigation drawer
75 | My profile
76 | No bio yet
77 | %1$s\'s profile
78 | Search for friends
79 | Chatting with %1$s
80 | Contacts
81 | Received friend requests
82 | RECENTLY ACTIVE
83 | Active %1$sm ago
84 | Active %1$sh ago
85 | Active %1$sd ago
86 | Just now
87 | Login
88 | Sign Up
89 | Profile
90 | Find Friends
91 | User Profile
92 | Chat
93 | Chat
94 | 0
95 | Error while loading incoming friend requests
96 | Request deleted
97 | Do you want to download clicked file?
98 | Finished recording
99 | Recording
100 | Yes
101 | Cancel
102 | No suitable file manager was found on this device
103 | Select Picture
104 | Permission is needed for this feature to work
105 | Grant
106 | Sign up successful
107 | Check email and password then retry.
108 | Login successful
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/chat_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
13 |
14 |
19 |
20 |
33 |
34 |
35 |
47 |
48 |
57 |
58 |
73 |
74 |
85 |
86 |
87 |
88 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
119 |
120 |
121 |
122 |
123 |
124 |
131 |
132 |
133 |
134 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/find_user_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
24 |
25 |
32 |
33 |
39 |
40 |
50 |
51 |
52 |
53 |
54 |
68 |
69 |
70 |
82 |
83 |
84 |
94 |
95 |
96 |
105 |
106 |
107 |
118 |
119 |
130 |
131 |
132 |
148 |
149 |
150 |
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------