swfmill 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/.document +5 -0
  2. data/.gitignore +23 -0
  3. data/.swfmill +240 -0
  4. data/LICENSE +340 -0
  5. data/README.rdoc +37 -0
  6. data/Rakefile +59 -0
  7. data/VERSION +1 -0
  8. data/ext/.gitignore +5 -0
  9. data/ext/extconf.rb +86 -0
  10. data/ext/swfmill/.gitignore +27 -0
  11. data/ext/swfmill/AUTHORS +9 -0
  12. data/ext/swfmill/COPYING +340 -0
  13. data/ext/swfmill/Makefile.am +14 -0
  14. data/ext/swfmill/Makefile.in +635 -0
  15. data/ext/swfmill/NEWS +189 -0
  16. data/ext/swfmill/README +170 -0
  17. data/ext/swfmill/TODO +33 -0
  18. data/ext/swfmill/aclocal.m4 +7712 -0
  19. data/ext/swfmill/autogen.sh +7 -0
  20. data/ext/swfmill/compile +142 -0
  21. data/ext/swfmill/config.guess +1516 -0
  22. data/ext/swfmill/config.sub +1626 -0
  23. data/ext/swfmill/configure +21868 -0
  24. data/ext/swfmill/configure.ac +55 -0
  25. data/ext/swfmill/depcomp +589 -0
  26. data/ext/swfmill/install-sh +519 -0
  27. data/ext/swfmill/ltmain.sh +6964 -0
  28. data/ext/swfmill/missing +367 -0
  29. data/ext/swfmill/src/Geom.cpp +107 -0
  30. data/ext/swfmill/src/Geom.h +100 -0
  31. data/ext/swfmill/src/Makefile.am +86 -0
  32. data/ext/swfmill/src/Makefile.in +1025 -0
  33. data/ext/swfmill/src/SWF.h +11941 -0
  34. data/ext/swfmill/src/SWFAction.cpp +41 -0
  35. data/ext/swfmill/src/SWFAction.h +19 -0
  36. data/ext/swfmill/src/SWFBasic.h +7 -0
  37. data/ext/swfmill/src/SWFFile.cpp +406 -0
  38. data/ext/swfmill/src/SWFFile.h +34 -0
  39. data/ext/swfmill/src/SWFFilter.cpp +25 -0
  40. data/ext/swfmill/src/SWFFilter.h +15 -0
  41. data/ext/swfmill/src/SWFGlyphList.cpp +262 -0
  42. data/ext/swfmill/src/SWFGlyphList.h +34 -0
  43. data/ext/swfmill/src/SWFIdItem.h +85 -0
  44. data/ext/swfmill/src/SWFIdItems.h +16 -0
  45. data/ext/swfmill/src/SWFItem.cpp +235 -0
  46. data/ext/swfmill/src/SWFItem.h +60 -0
  47. data/ext/swfmill/src/SWFList.h +179 -0
  48. data/ext/swfmill/src/SWFReader.cpp +352 -0
  49. data/ext/swfmill/src/SWFReader.h +73 -0
  50. data/ext/swfmill/src/SWFShapeItem.cpp +220 -0
  51. data/ext/swfmill/src/SWFShapeItem.h +45 -0
  52. data/ext/swfmill/src/SWFShapeMaker.cpp +401 -0
  53. data/ext/swfmill/src/SWFShapeMaker.h +128 -0
  54. data/ext/swfmill/src/SWFTag.cpp +49 -0
  55. data/ext/swfmill/src/SWFTag.h +20 -0
  56. data/ext/swfmill/src/SWFTrait.cpp +35 -0
  57. data/ext/swfmill/src/SWFTrait.h +22 -0
  58. data/ext/swfmill/src/SWFWriter.cpp +312 -0
  59. data/ext/swfmill/src/SWFWriter.h +84 -0
  60. data/ext/swfmill/src/base64.c +110 -0
  61. data/ext/swfmill/src/base64.h +15 -0
  62. data/ext/swfmill/src/codegen/Makefile.am +15 -0
  63. data/ext/swfmill/src/codegen/Makefile.in +346 -0
  64. data/ext/swfmill/src/codegen/basic.xsl +45 -0
  65. data/ext/swfmill/src/codegen/basics.xsl +235 -0
  66. data/ext/swfmill/src/codegen/dumper.xsl +109 -0
  67. data/ext/swfmill/src/codegen/header.xsl +131 -0
  68. data/ext/swfmill/src/codegen/mk.xsl +26 -0
  69. data/ext/swfmill/src/codegen/parser.xsl +196 -0
  70. data/ext/swfmill/src/codegen/parsexml.xsl +312 -0
  71. data/ext/swfmill/src/codegen/size.xsl +189 -0
  72. data/ext/swfmill/src/codegen/source.xml +2197 -0
  73. data/ext/swfmill/src/codegen/writer.xsl +190 -0
  74. data/ext/swfmill/src/codegen/writexml.xsl +138 -0
  75. data/ext/swfmill/src/swfmill.cpp +482 -0
  76. data/ext/swfmill/src/swft/Makefile.am +55 -0
  77. data/ext/swfmill/src/swft/Makefile.in +717 -0
  78. data/ext/swfmill/src/swft/Parser.cpp +76 -0
  79. data/ext/swfmill/src/swft/Parser.h +37 -0
  80. data/ext/swfmill/src/swft/SVGAttributeParser.cpp +78 -0
  81. data/ext/swfmill/src/swft/SVGAttributeParser.h +35 -0
  82. data/ext/swfmill/src/swft/SVGColor.cpp +116 -0
  83. data/ext/swfmill/src/swft/SVGColor.h +37 -0
  84. data/ext/swfmill/src/swft/SVGColors.h +167 -0
  85. data/ext/swfmill/src/swft/SVGGradient.cpp +258 -0
  86. data/ext/swfmill/src/swft/SVGGradient.h +81 -0
  87. data/ext/swfmill/src/swft/SVGPathParser.cpp +155 -0
  88. data/ext/swfmill/src/swft/SVGPathParser.h +126 -0
  89. data/ext/swfmill/src/swft/SVGPointsParser.cpp +51 -0
  90. data/ext/swfmill/src/swft/SVGPointsParser.h +25 -0
  91. data/ext/swfmill/src/swft/SVGStyle.cpp +181 -0
  92. data/ext/swfmill/src/swft/SVGStyle.h +80 -0
  93. data/ext/swfmill/src/swft/SVGTransformParser.cpp +72 -0
  94. data/ext/swfmill/src/swft/SVGTransformParser.h +32 -0
  95. data/ext/swfmill/src/swft/readpng.c +305 -0
  96. data/ext/swfmill/src/swft/readpng.h +92 -0
  97. data/ext/swfmill/src/swft/swft.cpp +251 -0
  98. data/ext/swfmill/src/swft/swft.h +64 -0
  99. data/ext/swfmill/src/swft/swft_document.cpp +57 -0
  100. data/ext/swfmill/src/swft/swft_import.cpp +38 -0
  101. data/ext/swfmill/src/swft/swft_import_binary.cpp +82 -0
  102. data/ext/swfmill/src/swft/swft_import_jpeg.cpp +255 -0
  103. data/ext/swfmill/src/swft/swft_import_mp3.cpp +268 -0
  104. data/ext/swfmill/src/swft/swft_import_png.cpp +231 -0
  105. data/ext/swfmill/src/swft/swft_import_ttf.cpp +519 -0
  106. data/ext/swfmill/src/swft/swft_import_wav.cpp +255 -0
  107. data/ext/swfmill/src/swft/swft_path.cpp +178 -0
  108. data/ext/swfmill/src/xslt/Makefile.am +51 -0
  109. data/ext/swfmill/src/xslt/Makefile.in +536 -0
  110. data/ext/swfmill/src/xslt/README +19 -0
  111. data/ext/swfmill/src/xslt/assemble.xsl +38 -0
  112. data/ext/swfmill/src/xslt/simple-deprecated.xslt +62 -0
  113. data/ext/swfmill/src/xslt/simple-elements.xslt +627 -0
  114. data/ext/swfmill/src/xslt/simple-import.xslt +565 -0
  115. data/ext/swfmill/src/xslt/simple-svg.xslt +383 -0
  116. data/ext/swfmill/src/xslt/simple-tools.xslt +255 -0
  117. data/ext/swfmill/src/xslt/simple.cpp +1686 -0
  118. data/ext/swfmill/src/xslt/simple.xml +7 -0
  119. data/ext/swfmill/src/xslt/xslt.h +7 -0
  120. data/ext/swfmill/test/Makefile.am +1 -0
  121. data/ext/swfmill/test/Makefile.in +490 -0
  122. data/ext/swfmill/test/xml/Makefile.am +20 -0
  123. data/ext/swfmill/test/xml/Makefile.in +353 -0
  124. data/ext/swfmill/test/xml/test-xml +21 -0
  125. data/ext/swfmill_ext.cc +375 -0
  126. data/lib/swfmill.rb +30 -0
  127. data/spec/data/swfmill-banner1.swf +0 -0
  128. data/spec/spec.opts +1 -0
  129. data/spec/spec_helper.rb +14 -0
  130. data/spec/swfmill_spec.rb +125 -0
  131. metadata +206 -0
@@ -0,0 +1,16 @@
1
+ #ifndef SWF_IDITEMS_H
2
+ #define SWF_IDITEMS_H
3
+
4
+ #include <SWFIdItem.h>
5
+
6
+ namespace SWF {
7
+
8
+ class StackItem : public IdItem<StackItem> {};
9
+ class Style : public IdItem<Style> {};
10
+ class NamespaceConstant : public IdItem<NamespaceConstant> {};
11
+ class MultinameConstant : public IdItem<MultinameConstant> {};
12
+ class OpCode : public IdItem<OpCode> {};
13
+
14
+ }
15
+ #endif
16
+
@@ -0,0 +1,235 @@
1
+ #include "SWFItem.h"
2
+ #include <cstring>
3
+ #include <cctype>
4
+ #include "base64.h"
5
+ #include <sys/types.h>
6
+
7
+ namespace SWF {
8
+
9
+ // ------------ utility functions
10
+
11
+ int swf_get_bits_needed_for_uint( uint64_t value ) {
12
+ int i=0;
13
+ while( value > 0 ) {
14
+ value >>= 1;
15
+ i++;
16
+ }
17
+ return i;
18
+ }
19
+
20
+ int swf_get_bits_needed_for_int( int64_t value ) {
21
+ if( value < 0 )
22
+ /* XXX one more than necessary if num = -2^n */
23
+ return swf_get_bits_needed_for_uint( -value ) + 1;
24
+ else if ( value > 0 )
25
+ return swf_get_bits_needed_for_uint( value ) + 1;
26
+ else
27
+ return 0;
28
+ }
29
+
30
+ int swf_get_bits_needed_for_fp( double value ) {
31
+ return swf_get_bits_needed_for_int( (int64_t)(value * 65536.0) );
32
+ }
33
+
34
+ int SWFBitsNeeded( int32_t value, bool is_signed ) {
35
+ if( is_signed )
36
+ return swf_get_bits_needed_for_int( value );
37
+ else
38
+ return swf_get_bits_needed_for_uint( value );
39
+ /*
40
+ long cnt;
41
+ if( is_signed ) {
42
+ if(value < 0) {
43
+ // a special case
44
+ if(value == -1) {
45
+ return 1;
46
+ }
47
+ cnt = 33;
48
+ do {
49
+ cnt--;
50
+ value *= 2;
51
+ } while(value < 0);
52
+ if( value == 0 ) return cnt+1;
53
+ }
54
+ else {
55
+ // a special case
56
+ if(value == 0) {
57
+ return 1;
58
+ }
59
+ cnt = 33;
60
+ do {
61
+ cnt--;
62
+ value *= 2;
63
+ } while(value > 0);
64
+ if( value == 0 ) return cnt+1;
65
+ }
66
+ } else {
67
+ if( value < 0 ) {
68
+ printf("ERROR: unsigned, but <0? %s:%i\n", __FILE__, __LINE__);
69
+ abort();
70
+ }
71
+ // a special case
72
+ if(value == 0) {
73
+ return 1;
74
+ }
75
+ cnt = 32;
76
+ while((long) value > 0) {
77
+ cnt--;
78
+ value *= 2;
79
+ }
80
+ if( value == 0 ) return cnt+1;
81
+ }
82
+ return cnt;
83
+ */
84
+ }
85
+
86
+ long SWFMaxBitsNeeded( bool is_signed, int how_many, ... ) {
87
+ long bits = 0;
88
+ va_list ap;
89
+ int n;
90
+ va_start( ap, how_many );
91
+
92
+ for( int i=0; i<how_many; i++ ) {
93
+ int b = SWFBitsNeeded( va_arg( ap, int ), is_signed );
94
+ if( b > bits ) bits = b;
95
+ }
96
+
97
+ va_end( ap );
98
+ return bits;
99
+ }
100
+
101
+ Item::Item() {
102
+ file_offset = -1;
103
+ cached_size = -1;
104
+ }
105
+
106
+ size_t Item::getSize( Context *ctx, int start_at ) {
107
+ if( cached_size == -1 ) {
108
+ cached_size = calcSize( ctx, start_at );
109
+ }
110
+ return cached_size;
111
+ }
112
+
113
+ int Item::getHeaderSize( int size ) {
114
+ return 0;
115
+ }
116
+
117
+ void Item::writeHeader( Writer *w, Context *ctx, size_t len ) {
118
+ }
119
+
120
+
121
+
122
+ Rest::Rest() {
123
+ size = 0;
124
+ data = NULL;
125
+ }
126
+
127
+ Rest::~Rest() {
128
+ delete[] data;
129
+ }
130
+
131
+ bool Rest::parse( Reader *r, int end, Context *ctx ) {
132
+ file_offset = r->getPosition();
133
+
134
+ size = end - r->getPosition();
135
+ if( size > 0 ) {
136
+ data = new unsigned char[size];
137
+ r->getData( data, size );
138
+ }
139
+
140
+ return r->getError() == SWFR_OK;
141
+ }
142
+
143
+ void Rest::dump( int indent, Context *ctx ) {
144
+ for( int i=0; i<indent; i++ ) printf(" ");
145
+ printf("Rest (length %i)\n", size);
146
+ if( size && data != NULL ) {
147
+ int i=0;
148
+ while( i<size ) {
149
+ for( int in=0; in<indent+1; in++ ) printf(" ");
150
+ for( int n=0; n<8 && i<size; n++ ) {
151
+ printf(" %02X", data[i] );
152
+ i++;
153
+ }
154
+ printf("\n");
155
+ }
156
+ }
157
+ }
158
+
159
+ size_t Rest::calcSize( Context *ctx, int start_at ) {
160
+ int r = start_at;
161
+ r += size * 8;
162
+ r += Item::getHeaderSize(r-start_at);
163
+ return r-start_at;
164
+ }
165
+
166
+ void Rest::write( Writer *w, Context *ctx ) {
167
+ Item::writeHeader( w, ctx, 0 );
168
+
169
+ if( size && data ) {
170
+ w->putData( data, size );
171
+ }
172
+ }
173
+
174
+ #define TMP_STRLEN 0xFF
175
+ void Rest::writeXML( xmlNodePtr xml, Context *ctx ) {
176
+ char tmp[TMP_STRLEN];
177
+ xmlNodePtr node = xml;
178
+
179
+ // node = xmlNewChild( node, NULL, (const xmlChar *)"Rest", NULL );
180
+ {
181
+ if( size && data ) {
182
+ char *tmp_data = (char *)data;
183
+ int sz = size;
184
+ char *tmpstr = new char[ (sz * 3) ];
185
+
186
+ int l = base64_encode( tmpstr, tmp_data, sz );
187
+ if( l > 0 ) {
188
+ tmpstr[l] = 0;
189
+ xmlNewTextChild( node, NULL, (const xmlChar *)"data", (const xmlChar *)tmpstr );
190
+ }
191
+ delete[] tmpstr;
192
+ }
193
+ }
194
+ }
195
+
196
+ void Rest::parseXML( xmlNodePtr node, Context *ctx ) {
197
+ data = NULL;
198
+ size = 0;
199
+
200
+ xmlChar *xmld = xmlNodeGetContent( node );
201
+ char *d = (char *)xmld;
202
+ if( d ) {
203
+ // unsure if this is neccessary
204
+ for( int i=strlen(d)-1; i>0 && isspace(d[i]); i-- ) d[i]=0;
205
+ while( isspace(d[0]) ) d++;
206
+ int l = strlen(d);
207
+ char *dst = new char[ l ];
208
+ int lout = base64_decode( dst, (char*)d, l );
209
+ if( lout > 0 ) {
210
+ size = lout;
211
+ data = new unsigned char[ lout ];
212
+ memcpy( data, dst, lout );
213
+ }
214
+ delete[] dst;
215
+ xmlFree( xmld );
216
+ }
217
+ }
218
+
219
+ void Rest::getdata( unsigned char **d, int *s ) {
220
+ *d = data;
221
+ *s = size;
222
+ }
223
+
224
+ void Rest::setdata( unsigned char *d, int s ) {
225
+ delete[] data;
226
+ data = NULL;
227
+ size = s;
228
+
229
+ if( size ) {
230
+ data = new unsigned char[ size ];
231
+ memcpy( data, d, size );
232
+ }
233
+ }
234
+
235
+ }
@@ -0,0 +1,60 @@
1
+ #ifndef SWF_ITEM_H
2
+ #define SWF_ITEM_H
3
+
4
+ #include <SWFReader.h>
5
+ #include <SWFWriter.h>
6
+ #include <libxml/tree.h>
7
+
8
+ namespace SWF {
9
+
10
+ class Context;
11
+
12
+ int SWFBitsNeeded( int32_t value, bool is_signed = false );
13
+ long SWFMaxBitsNeeded( bool is_signed, int how_many, ... );
14
+
15
+ class Item {
16
+ public:
17
+ Item();
18
+ virtual ~Item() {}
19
+
20
+ virtual bool parse( Reader *r, int end, Context *ctx ) = 0;
21
+ virtual void dump( int indent, Context *ctx ) = 0;
22
+ virtual size_t calcSize( Context *ctx, int start_at ) = 0;
23
+ virtual void write( Writer *r, Context *ctx ) = 0;
24
+
25
+ virtual void writeXML( xmlNodePtr xml, Context *ctx ) = 0;
26
+ virtual void parseXML( xmlNodePtr xml, Context *ctx ) = 0;
27
+
28
+ // wont touch the context if size is cached.
29
+ size_t getSize( Context *ctx, int start_at );
30
+
31
+ protected:
32
+ int getHeaderSize( int size );
33
+ void writeHeader( Writer *w, Context *ctx, size_t len );
34
+
35
+ int file_offset; // bytes after header for SWF, line for XML (NYI)
36
+ int cached_size; // cached size
37
+ };
38
+
39
+ // to save the rest of a tag as binary data...
40
+ class Rest : public Item {
41
+ public:
42
+ Rest();
43
+ virtual ~Rest();
44
+ virtual bool parse( Reader *r, int end, Context *ctx );
45
+ virtual void dump( int indent, Context *ctx );
46
+ virtual size_t calcSize( Context *ctx, int start_at );
47
+ virtual void write( Writer *w, Context *ctx );
48
+ virtual void writeXML( xmlNodePtr node, Context *ctx );
49
+ virtual void parseXML( xmlNodePtr node, Context *ctx );
50
+
51
+ void getdata( unsigned char **data, int *size );
52
+ void setdata( unsigned char *data, int size );
53
+
54
+ protected:
55
+ int size;
56
+ unsigned char *data;
57
+ };
58
+
59
+ }
60
+ #endif
@@ -0,0 +1,179 @@
1
+ #ifndef F_List_H
2
+ #define F_List_H
3
+
4
+ #include <cstdio>
5
+ #define WARNING printf
6
+
7
+ namespace SWF {
8
+
9
+ template <class T> class ListItem;
10
+
11
+ /*
12
+ a simple (likely non-threadsafe) LinkedList
13
+ */
14
+
15
+ template <class T>
16
+ class List {
17
+ public:
18
+ List( bool ownership = true )
19
+ : mOwnership( ownership ) {
20
+ mFirst = mLast = NULL;
21
+ }
22
+ ~List() {
23
+ ListItem<T> *item = mFirst, *next;
24
+ if( mOwnership ) {
25
+ while( item ) {
26
+ if( item->data() ) delete item->data();
27
+ next = item->next();
28
+ delete item;
29
+ item = next;
30
+ }
31
+ } else {
32
+ while( item ) {
33
+ next = item->next();
34
+ delete item;
35
+ item = next;
36
+ }
37
+ }
38
+ }
39
+
40
+ ListItem<T> *append( T *data, void *user_data = NULL ) {
41
+ if( !mLast ) {
42
+ if( !mFirst ) {
43
+ return mFirst = mLast = new ListItem<T>( data, NULL, user_data );
44
+ } else {
45
+ WARNING("Linked List has First but no Last item\n");
46
+ return NULL;
47
+ }
48
+ } else {
49
+ return mLast = new ListItem<T>( data, mLast, user_data );
50
+ }
51
+ }
52
+
53
+ ListItem<T> *prepend( T *data, void *user_data = NULL ) {
54
+ if( !mFirst ) {
55
+ return mFirst = mLast = new ListItem<T>( data, NULL, user_data );
56
+ } else {
57
+ ListItem<T> *item = new ListItem<T>( data, NULL, user_data );
58
+ item->mNext = mFirst;
59
+ mFirst->mPrevious = item;
60
+ return mFirst = item;
61
+ }
62
+ }
63
+
64
+ ListItem<T> *prepend2( T *data, void *user_data = NULL ) {
65
+ if( !mFirst ) {
66
+ return mFirst = mLast = new ListItem<T>( data, NULL, user_data );
67
+ } else {
68
+ return new ListItem<T>( data, mFirst, user_data );
69
+ }
70
+ }
71
+
72
+ T* remove( ListItem<T> *item ) {
73
+ item->remove( this );
74
+ T *ret = item->data();
75
+ if( mOwnership && item->data() ) {
76
+ delete item->data();
77
+ ret = NULL;
78
+ }
79
+ delete item;
80
+ return ret;
81
+ }
82
+
83
+ void moveToLast( ListItem<T> *item ) {
84
+ if( item == mLast ) return;
85
+ item->remove( this );
86
+ item->mPrevious = mLast;
87
+ if( mLast ) {
88
+ mLast->mNext = item;
89
+ }
90
+ mLast = item;
91
+ if( !mFirst ) mFirst = item;
92
+ }
93
+
94
+ ListItem<T> *first() { return mFirst; };
95
+ ListItem<T> *last() { return mLast; };
96
+
97
+ friend class ListItem<T>;
98
+
99
+ int size() {
100
+ if (mFirst == NULL) return 0;
101
+ if (mFirst == mLast) return 1;
102
+
103
+ int count = 1;
104
+ ListItem<T> *item = mFirst;
105
+ while(item != mLast) {
106
+ count++;
107
+ item = item->next();
108
+ }
109
+
110
+ return count;
111
+ }
112
+
113
+ protected:
114
+ ListItem<T> *mFirst;
115
+ ListItem<T> *mLast;
116
+ bool mOwnership;
117
+ };
118
+
119
+ template <class T>
120
+ class ListItem {
121
+ public:
122
+ ListItem( T *data, ListItem* insertAfter = NULL, void *user_data = NULL ) {
123
+ mData = data;
124
+ mPrevious = insertAfter;
125
+ mNext = insertAfter ? insertAfter->replaceNext( this ) : NULL;
126
+ if( mNext ) mNext->mPrevious = this;
127
+ mUserData = user_data;
128
+ }
129
+
130
+ ListItem *replaceNext( ListItem *next ) {
131
+ ListItem *ret = mNext;
132
+ mNext = next;
133
+ return ret;
134
+ }
135
+
136
+ void remove( List<T> *list ) {
137
+ if( !mPrevious ) list->mFirst = mNext;
138
+ else mPrevious->mNext = mNext;
139
+ if( !mNext ) list->mLast = mPrevious;
140
+ else mNext->mPrevious = mPrevious;
141
+ mPrevious = mNext = NULL;
142
+ }
143
+
144
+ ListItem *next() {
145
+ return( mNext );
146
+ }
147
+
148
+ ListItem *previous() {
149
+ return( mPrevious );
150
+ }
151
+
152
+ T* data() {
153
+ return( mData );
154
+ }
155
+
156
+ void* UserData() {
157
+ return( mUserData );
158
+ }
159
+
160
+ bool isLast() {
161
+ return( mNext == 0 );
162
+ }
163
+ bool isFirst() {
164
+ return( mPrevious == 0 );
165
+ }
166
+
167
+ friend class List<T>;
168
+
169
+ protected:
170
+ ListItem *mPrevious;
171
+ ListItem *mNext;
172
+ T *mData;
173
+ void *mUserData;
174
+ };
175
+
176
+
177
+ }
178
+
179
+ #endif