├── .gitignore
├── package.json
├── .idea
├── derweili-fb-chat-plugin.iml
├── modules.xml
└── workspace.xml
├── .editorconfig
├── .distignore
├── readme.txt
├── Gruntfile.js
├── assets
├── css
│ └── derweili-chat-plugin.css
└── js
│ └── derweili-chat-plugin.js
└── derweili-fb-chat-plugin.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | phpcs.xml
3 | phpunit.xml
4 | Thumbs.db
5 | wp-cli.local.yml
6 | node_modules/
7 | *.sql
8 | *.tar.gz
9 | *.zip
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "name": "derweili-fb-chat-plugin",
4 | "version": "0.1.0",
5 | "main": "Gruntfile.js",
6 | "author": "derweili",
7 | "devDependencies": {
8 | "grunt": "~0.4.5",
9 | "grunt-wp-i18n": "~0.5.0",
10 | "grunt-wp-readme-to-markdown": "~1.0.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.idea/derweili-fb-chat-plugin.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 |
4 | # WordPress Coding Standards
5 | # https://make.wordpress.org/core/handbook/coding-standards/
6 |
7 | root = true
8 |
9 | [*]
10 | charset = utf-8
11 | end_of_line = lf
12 | insert_final_newline = true
13 | trim_trailing_whitespace = true
14 | indent_style = tab
15 | indent_size = 4
16 |
17 | [{.jshintrc,*.json,*.yml}]
18 | indent_style = space
19 | indent_size = 2
20 |
21 | [{*.txt,wp-config-sample.php}]
22 | end_of_line = crlf
23 |
--------------------------------------------------------------------------------
/.distignore:
--------------------------------------------------------------------------------
1 | # A set of files you probably don't want in your WordPress.org distribution
2 | .distignore
3 | .editorconfig
4 | .git
5 | .gitignore
6 | .gitlab-ci.yml
7 | .travis.yml
8 | .DS_Store
9 | Thumbs.db
10 | behat.yml
11 | bin
12 | circle.yml
13 | composer.json
14 | composer.lock
15 | Gruntfile.js
16 | package.json
17 | package-lock.json
18 | phpunit.xml
19 | phpunit.xml.dist
20 | multisite.xml
21 | multisite.xml.dist
22 | phpcs.xml
23 | phpcs.xml.dist
24 | README.md
25 | wp-cli.local.yml
26 | yarn.lock
27 | tests
28 | vendor
29 | node_modules
30 | *.sql
31 | *.tar.gz
32 | *.zip
33 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === Facebook Chat Opt-In ===
2 | Contributors: derweili
3 | Donate link: https://example.com/
4 | Tags: sp
5 | Requires at least: 4.4
6 | Tested up to: 4.9.4
7 | Stable tag: 0.1.0
8 | License: GPLv2 or later
9 | License URI: https://www.gnu.org/licenses/gpl-2.0.html
10 |
11 | Here is a short description of the plugin. This should be no more than 150 characters. No markup here.
12 |
13 | == Description ==
14 |
15 | This plugin implements the Facebook Chat with an Opt-In Function to comply with German law.
16 | https://developers.facebook.com/docs/messenger-platform/discovery/customer-chat-plugin
17 |
18 |
19 |
20 | == Installation ==
21 |
22 | 1. Upload `derweili-fb-chat-plugin.php` to the `/wp-content/plugins/` directory
23 | 2. Activate the plugin through the 'Plugins' menu in WordPress
24 | 3. Go to Customizer and add your Facebook APP ID and your Facebook Page ID
25 |
26 | == Frequently Asked Questions ==
27 |
28 | = Where do I find more Information about the Facebook Chat =
29 |
30 | An answer to that question.
31 |
32 | = What about foo bar? =
33 |
34 | https://developers.facebook.com/docs/messenger-platform/discovery/customer-chat-plugin
35 |
36 | == Screenshots ==
37 |
38 |
39 |
40 | == Changelog ==
41 |
42 | = 0.1 =
43 | * First plugin version
44 |
45 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function( grunt ) {
2 |
3 | 'use strict';
4 |
5 | // Project configuration
6 | grunt.initConfig( {
7 |
8 | pkg: grunt.file.readJSON( 'package.json' ),
9 |
10 | addtextdomain: {
11 | options: {
12 | textdomain: 'derweili-fb-chat-plugin',
13 | },
14 | update_all_domains: {
15 | options: {
16 | updateDomains: true
17 | },
18 | src: [ '*.php', '**/*.php', '!\.git/**/*', '!bin/**/*', '!node_modules/**/*', '!tests/**/*' ]
19 | }
20 | },
21 |
22 | wp_readme_to_markdown: {
23 | your_target: {
24 | files: {
25 | 'README.md': 'readme.txt'
26 | }
27 | },
28 | },
29 |
30 | makepot: {
31 | target: {
32 | options: {
33 | domainPath: '/languages',
34 | exclude: [ '\.git/*', 'bin/*', 'node_modules/*', 'tests/*' ],
35 | mainFile: 'derweili-fb-chat-plugin.php',
36 | potFilename: 'derweili-fb-chat-plugin.pot',
37 | potHeaders: {
38 | poedit: true,
39 | 'x-poedit-keywordslist': true
40 | },
41 | type: 'wp-plugin',
42 | updateTimestamp: true
43 | }
44 | }
45 | },
46 | } );
47 |
48 | grunt.loadNpmTasks( 'grunt-wp-i18n' );
49 | grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' );
50 | grunt.registerTask( 'default', [ 'i18n','readme' ] );
51 | grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] );
52 | grunt.registerTask( 'readme', ['wp_readme_to_markdown'] );
53 |
54 | grunt.util.linefeed = '\n';
55 |
56 | };
57 |
--------------------------------------------------------------------------------
/assets/css/derweili-chat-plugin.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Fake messenger icon
3 | */
4 | #derweili-fb-chat-icon{
5 | width: 60px;
6 | height: 60px;
7 | border-radius: 50%;
8 | /*background-color: rgb(0, 132, 255);*/
9 | background-color: rgba(46, 157, 255, 0.51);
10 | display: block;
11 | position: fixed;
12 | z-index: 99999;
13 | bottom: 24px;
14 | right: 24px;
15 | -webkit-box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 2px rgba(0,0,0,0.12), 0 5px 5px -3px rgba(0,0,0,0.3);
16 | box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 2px rgba(0,0,0,0.12), 0 5px 5px -3px rgba(0,0,0,0.3);
17 | cursor: pointer;
18 | }
19 |
20 | #derweili-fb-chat-opt-in-message{
21 | display: none;
22 | width: 100%;
23 | width: calc(100% - 20px);
24 | max-width: 300px;
25 | position: fixed;
26 | bottom: 108px;
27 | right: 24px;
28 | background-color: white;
29 | z-index: 99999;
30 | -webkit-box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 2px rgba(0,0,0,0.12), 0 5px 5px -3px rgba(0,0,0,0.3);
31 | box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 2px rgba(0,0,0,0.12), 0 5px 5px -3px rgba(0,0,0,0.3);
32 | border-radius: 3px;
33 |
34 | }
35 |
36 | #derweili-fb-chat-opt-in-message.active{
37 | display: block;
38 | }
39 |
40 | #derweili-fb-chat-opt-in-message .inner{
41 | padding: 20px;
42 | }
43 |
44 | #derweili-fb-chat-opt-in-message a {
45 | text-align: center;
46 | display: block;
47 | font-size: 0.8em;
48 | }
49 |
50 | /* Accept Button Style */
51 | #derweili-fb-chat-opt-in-message .button{
52 | -webkit-box-shadow: 0 4px 5px 0 rgba(0,0,0,0.14), 0 1px 10px 0 rgba(0,0,0,0.12), 0 2px 4px -1px rgba(0,0,0,0.3);
53 | box-shadow: 0 4px 5px 0 rgba(0,0,0,0.14), 0 1px 10px 0 rgba(0,0,0,0.12), 0 2px 4px -1px rgba(0,0,0,0.3);
54 | padding: 10px 10px;
55 | background: #4267b2;
56 | text-align: center;
57 | color: white;
58 | border-radius: 3px;
59 | margin-bottom: 10px;
60 | font-size: 1em;
61 | cursor: pointer;
62 | }
63 |
64 | #derweili-fb-chat-opt-in-message .close {
65 | position: absolute;
66 | top: 18px;
67 | right: 20px;
68 | width: 15px;
69 | cursor: pointer;
70 | }
71 | .derweili-fb-hidden {
72 |
73 | }
74 |
75 | /*
76 | * Chrome auto scroll-down bugfix
77 | * https://stackoverflow.com/questions/47959861/facebook-customer-chat-plugin-auto-scroll-to-bottom
78 | */
79 | .fb_dialog, .fb_reset {position: fixed !important;z-index: 10000 !important;}
--------------------------------------------------------------------------------
/assets/js/derweili-chat-plugin.js:
--------------------------------------------------------------------------------
1 | (function($){
2 |
3 | var $chatIcon = $('#derweili-fb-chat-icon'),
4 | $optInMessage = $('#derweili-fb-chat-opt-in-message'),
5 | $acceptButton = $($optInMessage).find('#accept'),
6 | $closeButton = $($optInMessage).find('.close'),
7 | $optOutLink = $('.derweili-fb-opt-out-link'),
8 | appId = $($optInMessage).attr('data-app-id'),
9 | cookieName = $($optInMessage).attr('data-cookie-name');
10 | console.log('cookie name', cookieName);
11 |
12 | console.log($chatIcon);
13 |
14 | $($chatIcon).on('click', function(e){
15 | e.preventDefault();
16 | $optInMessage.toggleClass('active');
17 | });
18 | $($closeButton).on('click', function(e){
19 | e.preventDefault();
20 | $optInMessage.toggleClass('active');
21 | });
22 |
23 |
24 | $($acceptButton).on('click', function(e){
25 | e.preventDefault();
26 | loadFbStuff();
27 | hideOptInStuff();
28 | setCookieOptInCookie();
29 | })
30 |
31 |
32 | function loadFbStuff(){
33 | console.log('loadFbStuff');
34 | window.fbAsyncInit = function() {
35 | console.log('fbAsyncInit');
36 | FB.init({
37 | appId : appId,
38 | autoLogAppEvents : true,
39 | xfbml : true,
40 | version : 'v2.12'
41 | });
42 | };
43 | (function(d, s, id){
44 | var js, fjs = d.getElementsByTagName(s)[0];
45 | if (d.getElementById(id)) {return;}
46 | js = d.createElement(s); js.id = id;
47 | js.src = "https://connect.facebook.net/de_DE/sdk.js";
48 | fjs.parentNode.insertBefore(js, fjs);
49 | }(document, 'script', 'facebook-jssdk'));
50 |
51 |
52 | }
53 | 1
54 | function setCookieOptInCookie()
55 | {
56 | var expires = new Date();
57 | expires.setTime(expires.getTime() + (1 * 24 * 60 * 60 * 1000));
58 |
59 | var value = 1;
60 |
61 | document.cookie = cookieName + '=' + value +';path=/'+ ';expires=' + expires.toUTCString();
62 | }
63 |
64 | function hideOptInStuff(){
65 | $optInMessage.fadeOut('200');
66 | $chatIcon.fadeOut('200');
67 | }
68 |
69 | // opt out link
70 | $optOutLink.on('click', function(e){
71 | console.log('opt-out');
72 |
73 | var cookieName = $(this).attr('data-cookie-name');
74 |
75 | e.preventDefault();
76 |
77 | var expires = new Date();
78 | expires.setTime(expires.getTime() + (1 * 24 * 60 * 60 * 1000));
79 |
80 | var value = 0;
81 |
82 | document.cookie = cookieName + '=' + value +';path=/'+ ';expires=' + expires.toUTCString();
83 | });
84 |
85 |
86 |
87 |
88 |
89 |
90 | })(jQuery);
91 |
--------------------------------------------------------------------------------
/derweili-fb-chat-plugin.php:
--------------------------------------------------------------------------------
1 | version;
40 | }
41 |
42 | public function get_slug(){
43 | return $this->slug;
44 | }
45 |
46 | public function run(){
47 |
48 | $this->load_dependencies();
49 |
50 |
51 |
52 | }
53 |
54 | private function load_dependencies(){
55 |
56 | add_action('wp_enqueue_scripts', array(&$this, 'enqueue_scripts') );
57 | add_action('wp_head', array(&$this, 'load_fb_code'), 10000);
58 | add_action('customize_register',array(&$this, 'register_customizer_settings'));
59 |
60 | }
61 |
62 |
63 | public function enqueue_scripts(){
64 |
65 | wp_enqueue_script( 'derweili_fb_chat_plugin', plugin_dir_url($this->plugin_dir) . 'assets/js/derweili-chat-plugin.js', array('jquery'), '0.1', true );
66 | wp_enqueue_style( 'derweili_fb_chat_plugin', plugin_dir_url($this->plugin_dir) . 'assets/css/derweili-chat-plugin.css', [], '0.1' );
67 |
68 | }
69 |
70 | private function is_cookie_set(){
71 | return isset( $_COOKIE[Derweili_FB_Chat_Plugin::$cookie_name] ) && $_COOKIE[Derweili_FB_Chat_Plugin::$cookie_name];
72 | }
73 |
74 |
75 | public function load_fb_code(){
76 |
77 | if( ! get_theme_mod('derweili_fb_chat_app_id', null) || ! get_theme_mod('derweili_fb_chat_page_id', null) ) return;
78 |
79 | if( $this->is_cookie_set() ):
80 |
81 | ?>
82 |
83 |
101 |
102 |
105 |
106 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
135 |
136 |
140 | logged_in_greeting=""
141 |
142 |
143 | logged_out_greeting=""
144 |
145 | >
146 |
147 |
148 | " . $content . "";
156 |
157 | }
158 |
159 |
160 |
161 | public function register_customizer_settings($wp_customize){
162 |
163 |
164 | $wp_customize->add_section( 'derweili_fb_chat_settings_section', array(
165 | 'title' => __( 'Facebook Chat Settings' ),
166 | 'priority' => 100,
167 | ) );
168 |
169 | $wp_customize->add_setting(
170 | 'derweili_fb_chat_app_id',
171 | array(
172 | 'default' => '',
173 | 'transport' => 'refresh'
174 | )
175 | );
176 | $wp_customize->add_setting(
177 | 'derweili_fb_chat_page_id',
178 | array(
179 | 'default' => '',
180 | 'transport' => 'refresh'
181 | )
182 | );
183 | $wp_customize->add_setting(
184 | 'derweili_fb_chat_theme_color',
185 | array(
186 | 'default' => '',
187 | 'transport' => 'refresh'
188 | )
189 | );
190 | $wp_customize->add_setting(
191 | 'derweili_fb_chat_logged_in_greeting',
192 | array(
193 | 'default' => '',
194 | 'transport' => 'refresh'
195 | )
196 | );
197 | $wp_customize->add_setting(
198 | 'derweili_fb_chat_logged_out_greeting',
199 | array(
200 | 'default' => '',
201 | 'transport' => 'refresh'
202 | )
203 | );
204 | $wp_customize->add_setting(
205 | 'derweili_fb_chat_infotext_headline',
206 | array(
207 | 'default' => '',
208 | 'transport' => 'refresh'
209 | )
210 | );
211 | $wp_customize->add_setting(
212 | 'derweili_fb_chat_infotext',
213 | array(
214 | 'default' => '',
215 | 'transport' => 'refresh'
216 | )
217 | );
218 | $wp_customize->add_setting(
219 | 'derweili_fb_chat_privacy_link',
220 | array(
221 | 'default' => '',
222 | 'transport' => 'refresh'
223 | )
224 | );
225 |
226 | $wp_customize->add_setting(
227 | 'derweili_fb_chat_start_chat_button_text',
228 | array(
229 | 'default' => 'Start chat',
230 | 'transport' => 'refresh'
231 | )
232 | );
233 |
234 | $wp_customize->add_setting(
235 | 'derweili_fb_chat_privacy_policy_link',
236 | array(
237 | 'default' => __('Privacy Policy'),
238 | 'transport' => 'refresh'
239 | )
240 | );
241 |
242 | $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'derweili_fb_chat_app_id', array(
243 | 'label' => __('Facebook App ID'),
244 | 'section' => 'derweili_fb_chat_settings_section',
245 | 'settings' => 'derweili_fb_chat_app_id',
246 | ) ) );
247 |
248 |
249 | $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'derweili_fb_chat_page_id', array(
250 | 'label' => __('Page ID'),
251 | 'section' => 'derweili_fb_chat_settings_section',
252 | 'settings' => 'derweili_fb_chat_page_id',
253 | ) ) );
254 |
255 |
256 | $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'derweili_fb_chat_theme_color', array(
257 | 'label' => __('Theme Color'),
258 | 'section' => 'derweili_fb_chat_settings_section',
259 | 'settings' => 'derweili_fb_chat_theme_color',
260 | ) ) );
261 |
262 |
263 | $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'derweili_fb_chat_logged_in_greeting', array(
264 | 'label' => __('Logged in greeting'),
265 | 'section' => 'derweili_fb_chat_settings_section',
266 | 'settings' => 'derweili_fb_chat_logged_in_greeting',
267 | ) ) );
268 |
269 | $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'derweili_fb_chat_logged_out_greeting', array(
270 | 'label' => __('Logged out greeting'),
271 | 'section' => 'derweili_fb_chat_settings_section',
272 | 'settings' => 'derweili_fb_chat_logged_out_greeting',
273 | ) ) );
274 |
275 |
276 | $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'derweili_fb_chat_infotext_headline', array(
277 | 'label' => __('Infotext Headline'),
278 | 'section' => 'derweili_fb_chat_settings_section',
279 | 'settings' => 'derweili_fb_chat_infotext_headline',
280 | ) ) );
281 |
282 | $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'derweili_fb_chat_start_chat_button_text', array(
283 | 'label' => __('Start chat button text'),
284 | 'section' => 'derweili_fb_chat_settings_section',
285 | 'settings' => 'derweili_fb_chat_start_chat_button_text',
286 | ) ) );
287 |
288 |
289 |
290 |
291 | $wp_customize->add_control( 'derweili_fb_chat_infotext', array(
292 | 'type' => 'textarea',
293 | 'priority' => 10, // Within the section.
294 | 'section' => 'derweili_fb_chat_settings_section', // Required, core or custom.
295 | 'label' => __( 'Infotext' ),
296 | // 'description' => __( 'This is a date control with a red border.' ),
297 | 'setting' => 'derweili_fb_chat_infotext'
298 | ) );
299 |
300 |
301 | $wp_customize->add_control( 'derweili_fb_chat_privacy_link', array(
302 | 'type' => 'dropdown-pages',
303 | 'priority' => 10, // Within the section.
304 | 'section' => 'derweili_fb_chat_settings_section', // Required, core or custom.
305 | 'label' => __( 'Privacy Link' ),
306 | // 'description' => __( 'This is a date control with a red border.' ),
307 | 'setting' => 'derweili_fb_chat_privacy_link'
308 | ) );
309 |
310 |
311 | $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'derweili_fb_chat_privacy_policy_link', array(
312 | 'label' => __('Privacy Policy Linktext'),
313 | 'section' => 'derweili_fb_chat_settings_section',
314 | 'settings' => 'derweili_fb_chat_privacy_policy_link',
315 | ) ) );
316 |
317 | }
318 |
319 |
320 |
321 |
322 | }
323 |
324 | $chat_plugin = new Derweili_FB_Chat_Plugin();
325 | $chat_plugin->run();
326 |
327 |
328 | add_shortcode( 'fb-chat-plugin', array( 'Derweili_FB_Chat_Plugin', 'opt_out_cookie' ) );
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | $cookie_name
103 | cookie_name
104 |
105 |
106 |
107 |
108 |
109 |
110 |
118 |
119 |
120 |
121 |
122 |
123 |
124 | true
125 | DEFINITION_ORDER
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | 1519824209352
207 |
208 |
209 | 1519824209352
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
--------------------------------------------------------------------------------