├── README.md
└── glow-shader
├── .idea
├── earthThree.iml
├── modules.xml
└── workspace.xml
├── bg1.png
├── bg2.png
├── build
├── TrackballControls.js
└── three.js
└── glow.html
/README.md:
--------------------------------------------------------------------------------
1 | # ThreeJSGlow-Atmosphere
2 | show the glow and atmosphere by threejs
3 | effort:
4 | 
5 | 
6 |
--------------------------------------------------------------------------------
/glow-shader/.idea/earthThree.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/glow-shader/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/glow-shader/.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 | PlaneBufferGeometry
38 | coeficient
39 | PlaneGeometry
40 | depthWrite
41 | renderOrder
42 | controls
43 | depth
44 | mesh
45 | material_glow
46 | material
47 | exchangeShader
48 |
49 |
50 |
51 |
56 |
57 |
58 |
59 |
60 | true
61 | DEFINITION_ORDER
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 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
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 | project
152 |
153 |
154 | true
155 |
156 |
157 |
158 | DIRECTORY
159 |
160 | false
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | 1509007569147
171 |
172 |
173 | 1509007569147
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 |
207 |
208 |
209 |
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 |
--------------------------------------------------------------------------------
/glow-shader/bg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StringKun/ThreeJSGlow-Atmosphere/6901d970a04ffe9ba3ea0a8d9e71ade5d53f2514/glow-shader/bg1.png
--------------------------------------------------------------------------------
/glow-shader/bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StringKun/ThreeJSGlow-Atmosphere/6901d970a04ffe9ba3ea0a8d9e71ade5d53f2514/glow-shader/bg2.png
--------------------------------------------------------------------------------
/glow-shader/build/TrackballControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eberhard Graether / http://egraether.com/
3 | * @author Mark Lundin / http://mark-lundin.com
4 | * @author Simone Manini / http://daron1337.github.io
5 | * @author Luca Antiga / http://lantiga.github.io
6 | */
7 |
8 | THREE.TrackballControls = function ( object, domElement ) {
9 |
10 | var _this = this;
11 | var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };
12 |
13 | this.object = object;
14 | this.domElement = ( domElement !== undefined ) ? domElement : document;
15 |
16 | // API
17 |
18 | this.enabled = true;
19 |
20 | this.screen = { left: 0, top: 0, width: 0, height: 0 };
21 |
22 | this.rotateSpeed = 1.0;
23 | this.zoomSpeed = 1.2;
24 | this.panSpeed = 0.3;
25 |
26 | this.noRotate = false;
27 | this.noZoom = false;
28 | this.noPan = false;
29 |
30 | this.staticMoving = false;
31 | this.dynamicDampingFactor = 0.2;
32 |
33 | this.minDistance = 0;
34 | this.maxDistance = Infinity;
35 |
36 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
37 |
38 | // internals
39 |
40 | this.target = new THREE.Vector3();
41 |
42 | var EPS = 0.000001;
43 |
44 | var lastPosition = new THREE.Vector3();
45 |
46 | var _state = STATE.NONE,
47 | _prevState = STATE.NONE,
48 |
49 | _eye = new THREE.Vector3(),
50 |
51 | _movePrev = new THREE.Vector2(),
52 | _moveCurr = new THREE.Vector2(),
53 |
54 | _lastAxis = new THREE.Vector3(),
55 | _lastAngle = 0,
56 |
57 | _zoomStart = new THREE.Vector2(),
58 | _zoomEnd = new THREE.Vector2(),
59 |
60 | _touchZoomDistanceStart = 0,
61 | _touchZoomDistanceEnd = 0,
62 |
63 | _panStart = new THREE.Vector2(),
64 | _panEnd = new THREE.Vector2();
65 |
66 | // for reset
67 |
68 | this.target0 = this.target.clone();
69 | this.position0 = this.object.position.clone();
70 | this.up0 = this.object.up.clone();
71 |
72 | // events
73 |
74 | var changeEvent = { type: 'change' };
75 | var startEvent = { type: 'start' };
76 | var endEvent = { type: 'end' };
77 |
78 |
79 | // methods
80 |
81 | this.handleResize = function () {
82 |
83 | if ( this.domElement === document ) {
84 |
85 | this.screen.left = 0;
86 | this.screen.top = 0;
87 | this.screen.width = window.innerWidth;
88 | this.screen.height = window.innerHeight;
89 |
90 | } else {
91 |
92 | var box = this.domElement.getBoundingClientRect();
93 | // adjustments come from similar code in the jquery offset() function
94 | var d = this.domElement.ownerDocument.documentElement;
95 | this.screen.left = box.left + window.pageXOffset - d.clientLeft;
96 | this.screen.top = box.top + window.pageYOffset - d.clientTop;
97 | this.screen.width = box.width;
98 | this.screen.height = box.height;
99 |
100 | }
101 |
102 | };
103 |
104 | this.handleEvent = function ( event ) {
105 |
106 | if ( typeof this[ event.type ] == 'function' ) {
107 |
108 | this[ event.type ]( event );
109 |
110 | }
111 |
112 | };
113 |
114 | var getMouseOnScreen = ( function () {
115 |
116 | var vector = new THREE.Vector2();
117 |
118 | return function getMouseOnScreen( pageX, pageY ) {
119 |
120 | vector.set(
121 | ( pageX - _this.screen.left ) / _this.screen.width,
122 | ( pageY - _this.screen.top ) / _this.screen.height
123 | );
124 |
125 | return vector;
126 |
127 | };
128 |
129 | }() );
130 |
131 | var getMouseOnCircle = ( function () {
132 |
133 | var vector = new THREE.Vector2();
134 |
135 | return function getMouseOnCircle( pageX, pageY ) {
136 |
137 | vector.set(
138 | ( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ),
139 | ( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional
140 | );
141 |
142 | return vector;
143 |
144 | };
145 |
146 | }() );
147 |
148 | this.rotateCamera = ( function() {
149 |
150 | var axis = new THREE.Vector3(),
151 | quaternion = new THREE.Quaternion(),
152 | eyeDirection = new THREE.Vector3(),
153 | objectUpDirection = new THREE.Vector3(),
154 | objectSidewaysDirection = new THREE.Vector3(),
155 | moveDirection = new THREE.Vector3(),
156 | angle;
157 |
158 | return function rotateCamera() {
159 |
160 | moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 );
161 | angle = moveDirection.length();
162 |
163 | if ( angle ) {
164 |
165 | _eye.copy( _this.object.position ).sub( _this.target );
166 |
167 | eyeDirection.copy( _eye ).normalize();
168 | objectUpDirection.copy( _this.object.up ).normalize();
169 | objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize();
170 |
171 | objectUpDirection.setLength( _moveCurr.y - _movePrev.y );
172 | objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x );
173 |
174 | moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) );
175 |
176 | axis.crossVectors( moveDirection, _eye ).normalize();
177 |
178 | angle *= _this.rotateSpeed;
179 | quaternion.setFromAxisAngle( axis, angle );
180 |
181 | _eye.applyQuaternion( quaternion );
182 | _this.object.up = new THREE.Vector3(0,1,0);
183 |
184 | _lastAxis.copy( axis );
185 | _lastAngle = angle;
186 |
187 | } else if ( ! _this.staticMoving && _lastAngle ) {
188 |
189 | _lastAngle *= Math.sqrt( 1.0 - _this.dynamicDampingFactor );
190 | _eye.copy( _this.object.position ).sub( _this.target );
191 | quaternion.setFromAxisAngle( _lastAxis, _lastAngle );
192 | _eye.applyQuaternion( quaternion );
193 | // _this.object.up.applyQuaternion( quaternion );
194 | _this.object.up = new THREE.Vector3(0,1,0);
195 |
196 | }
197 |
198 | _movePrev.copy( _moveCurr );
199 |
200 | };
201 |
202 | }() );
203 |
204 |
205 | this.zoomCamera = function () {
206 |
207 | var factor;
208 |
209 | if ( _state === STATE.TOUCH_ZOOM_PAN ) {
210 |
211 | factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
212 | _touchZoomDistanceStart = _touchZoomDistanceEnd;
213 | _eye.multiplyScalar( factor );
214 |
215 | } else {
216 |
217 | factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
218 |
219 | if ( factor !== 1.0 && factor > 0.0 ) {
220 |
221 | _eye.multiplyScalar( factor );
222 |
223 | }
224 |
225 | if ( _this.staticMoving ) {
226 |
227 | _zoomStart.copy( _zoomEnd );
228 |
229 | } else {
230 |
231 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
232 |
233 | }
234 |
235 | }
236 |
237 | };
238 |
239 | this.panCamera = ( function() {
240 |
241 | var mouseChange = new THREE.Vector2(),
242 | objectUp = new THREE.Vector3(),
243 | pan = new THREE.Vector3();
244 |
245 | return function panCamera() {
246 |
247 | mouseChange.copy( _panEnd ).sub( _panStart );
248 |
249 | if ( mouseChange.lengthSq() ) {
250 |
251 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
252 |
253 | pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );
254 | pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );
255 |
256 | _this.object.position.add( pan );
257 | _this.target.add( pan );
258 |
259 | if ( _this.staticMoving ) {
260 |
261 | _panStart.copy( _panEnd );
262 |
263 | } else {
264 |
265 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
266 |
267 | }
268 |
269 | }
270 |
271 | };
272 |
273 | }() );
274 |
275 | this.checkDistances = function () {
276 |
277 | if ( ! _this.noZoom || ! _this.noPan ) {
278 |
279 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {
280 |
281 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );
282 | _zoomStart.copy( _zoomEnd );
283 |
284 | }
285 |
286 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {
287 |
288 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );
289 | _zoomStart.copy( _zoomEnd );
290 |
291 | }
292 |
293 | }
294 |
295 | };
296 |
297 | this.update = function () {
298 |
299 | _eye.subVectors( _this.object.position, _this.target );
300 |
301 | if ( ! _this.noRotate ) {
302 |
303 | _this.rotateCamera();
304 |
305 | }
306 |
307 | if ( ! _this.noZoom ) {
308 |
309 | _this.zoomCamera();
310 |
311 | }
312 |
313 | if ( ! _this.noPan ) {
314 |
315 | _this.panCamera();
316 |
317 | }
318 |
319 | _this.object.position.addVectors( _this.target, _eye );
320 |
321 | _this.checkDistances();
322 |
323 | _this.object.lookAt( _this.target );
324 |
325 | if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) {
326 |
327 | _this.dispatchEvent( changeEvent );
328 |
329 | lastPosition.copy( _this.object.position );
330 |
331 | }
332 |
333 | };
334 |
335 | this.reset = function () {
336 |
337 | _state = STATE.NONE;
338 | _prevState = STATE.NONE;
339 |
340 | _this.target.copy( _this.target0 );
341 | _this.object.position.copy( _this.position0 );
342 | _this.object.up.copy( _this.up0 );
343 |
344 | _eye.subVectors( _this.object.position, _this.target );
345 |
346 | _this.object.lookAt( _this.target );
347 |
348 | _this.dispatchEvent( changeEvent );
349 |
350 | lastPosition.copy( _this.object.position );
351 |
352 | };
353 |
354 | // listeners
355 |
356 | function keydown( event ) {
357 |
358 | if ( _this.enabled === false ) return;
359 |
360 | window.removeEventListener( 'keydown', keydown );
361 |
362 | _prevState = _state;
363 |
364 | if ( _state !== STATE.NONE ) {
365 |
366 | return;
367 |
368 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate ) {
369 |
370 | _state = STATE.ROTATE;
371 |
372 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom ) {
373 |
374 | _state = STATE.ZOOM;
375 |
376 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan ) {
377 |
378 | _state = STATE.PAN;
379 |
380 | }
381 |
382 | }
383 |
384 | function keyup( event ) {
385 |
386 | if ( _this.enabled === false ) return;
387 |
388 | _state = _prevState;
389 |
390 | window.addEventListener( 'keydown', keydown, false );
391 |
392 | }
393 |
394 | function mousedown( event ) {
395 |
396 | if ( _this.enabled === false ) return;
397 |
398 | event.preventDefault();
399 | event.stopPropagation();
400 |
401 | if ( _state === STATE.NONE ) {
402 |
403 | _state = event.button;
404 |
405 | }
406 |
407 | if ( _state === STATE.ROTATE && ! _this.noRotate ) {
408 |
409 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
410 | _movePrev.copy( _moveCurr );
411 |
412 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
413 |
414 | _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
415 | _zoomEnd.copy( _zoomStart );
416 |
417 | } else if ( _state === STATE.PAN && ! _this.noPan ) {
418 |
419 | _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
420 | _panEnd.copy( _panStart );
421 |
422 | }
423 |
424 | document.addEventListener( 'mousemove', mousemove, false );
425 | document.addEventListener( 'mouseup', mouseup, false );
426 |
427 | _this.dispatchEvent( startEvent );
428 |
429 | }
430 |
431 | function mousemove( event ) {
432 |
433 | if ( _this.enabled === false ) return;
434 |
435 | event.preventDefault();
436 | event.stopPropagation();
437 |
438 | if ( _state === STATE.ROTATE && ! _this.noRotate ) {
439 |
440 | _movePrev.copy( _moveCurr );
441 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
442 |
443 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
444 |
445 | _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
446 |
447 | } else if ( _state === STATE.PAN && ! _this.noPan ) {
448 |
449 | _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
450 |
451 | }
452 |
453 | }
454 |
455 | function mouseup( event ) {
456 |
457 | if ( _this.enabled === false ) return;
458 |
459 | event.preventDefault();
460 | event.stopPropagation();
461 |
462 | _state = STATE.NONE;
463 |
464 | document.removeEventListener( 'mousemove', mousemove );
465 | document.removeEventListener( 'mouseup', mouseup );
466 | _this.dispatchEvent( endEvent );
467 |
468 | }
469 |
470 | function mousewheel( event ) {
471 |
472 | if ( _this.enabled === false ) return;
473 |
474 | event.preventDefault();
475 | event.stopPropagation();
476 |
477 | switch ( event.deltaMode ) {
478 |
479 | case 2:
480 | // Zoom in pages
481 | _zoomStart.y -= event.deltaY * 0.025;
482 | break;
483 |
484 | case 1:
485 | // Zoom in lines
486 | _zoomStart.y -= event.deltaY * 0.01;
487 | break;
488 |
489 | default:
490 | // undefined, 0, assume pixels
491 | _zoomStart.y -= event.deltaY * 0.00025;
492 | break;
493 |
494 | }
495 |
496 | _this.dispatchEvent( startEvent );
497 | _this.dispatchEvent( endEvent );
498 |
499 | }
500 |
501 | function touchstart( event ) {
502 |
503 | if ( _this.enabled === false ) return;
504 |
505 | switch ( event.touches.length ) {
506 |
507 | case 1:
508 | _state = STATE.TOUCH_ROTATE;
509 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
510 | _movePrev.copy( _moveCurr );
511 | break;
512 |
513 | default: // 2 or more
514 | _state = STATE.TOUCH_ZOOM_PAN;
515 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
516 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
517 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
518 |
519 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
520 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
521 | _panStart.copy( getMouseOnScreen( x, y ) );
522 | _panEnd.copy( _panStart );
523 | break;
524 |
525 | }
526 |
527 | _this.dispatchEvent( startEvent );
528 |
529 | }
530 |
531 | function touchmove( event ) {
532 |
533 | if ( _this.enabled === false ) return;
534 |
535 | event.preventDefault();
536 | event.stopPropagation();
537 |
538 | switch ( event.touches.length ) {
539 |
540 | case 1:
541 | _movePrev.copy( _moveCurr );
542 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
543 | break;
544 |
545 | default: // 2 or more
546 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
547 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
548 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
549 |
550 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
551 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
552 | _panEnd.copy( getMouseOnScreen( x, y ) );
553 | break;
554 |
555 | }
556 |
557 | }
558 |
559 | function touchend( event ) {
560 |
561 | if ( _this.enabled === false ) return;
562 |
563 | switch ( event.touches.length ) {
564 |
565 | case 0:
566 | _state = STATE.NONE;
567 | break;
568 |
569 | case 1:
570 | _state = STATE.TOUCH_ROTATE;
571 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
572 | _movePrev.copy( _moveCurr );
573 | break;
574 |
575 | }
576 |
577 | _this.dispatchEvent( endEvent );
578 |
579 | }
580 |
581 | function contextmenu( event ) {
582 |
583 | event.preventDefault();
584 |
585 | }
586 |
587 | this.dispose = function() {
588 |
589 | this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
590 | this.domElement.removeEventListener( 'mousedown', mousedown, false );
591 | this.domElement.removeEventListener( 'wheel', mousewheel, false );
592 |
593 | this.domElement.removeEventListener( 'touchstart', touchstart, false );
594 | this.domElement.removeEventListener( 'touchend', touchend, false );
595 | this.domElement.removeEventListener( 'touchmove', touchmove, false );
596 |
597 | document.removeEventListener( 'mousemove', mousemove, false );
598 | document.removeEventListener( 'mouseup', mouseup, false );
599 |
600 | window.removeEventListener( 'keydown', keydown, false );
601 | window.removeEventListener( 'keyup', keyup, false );
602 |
603 | };
604 |
605 | this.domElement.addEventListener( 'contextmenu', contextmenu, false );
606 | this.domElement.addEventListener( 'mousedown', mousedown, false );
607 | this.domElement.addEventListener( 'wheel', mousewheel, false );
608 |
609 | this.domElement.addEventListener( 'touchstart', touchstart, false );
610 | this.domElement.addEventListener( 'touchend', touchend, false );
611 | this.domElement.addEventListener( 'touchmove', touchmove, false );
612 |
613 | window.addEventListener( 'keydown', keydown, false );
614 | window.addEventListener( 'keyup', keyup, false );
615 |
616 | this.handleResize();
617 |
618 | // force an update at start
619 | this.update();
620 |
621 | };
622 |
623 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
624 | THREE.TrackballControls.prototype.constructor = THREE.TrackballControls;
625 |
--------------------------------------------------------------------------------
/glow-shader/glow.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
242 |
243 |
244 |
245 |
--------------------------------------------------------------------------------