├── .gitignore ├── Makefile ├── README.md ├── conf ├── mime.types └── nginx.conf ├── css ├── cn-home.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── home.css ├── main.css └── vendor │ ├── bootstrap.min.css │ └── ie10-viewport-bug-workaround.css ├── html ├── cn-index.html ├── fail.html ├── index.html └── success.html ├── init └── mysql.sql ├── js └── vendor │ ├── bootstrap.min.js │ ├── ie-emulation-modes-warning.js │ ├── ie10-viewport-bug-workaround.js │ ├── jquery.min.js │ └── validator.min.js ├── logs └── README ├── lua └── survey │ └── post.lua └── template ├── cn-index.tt └── index.tt /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | *.swo 4 | *.bak 5 | *.pid 6 | *.log 7 | go 8 | upload 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | html_files := html/index.html html/cn-index.html 2 | 3 | .DELETE_ON_ERRORS: $(html_files) 4 | 5 | all: $(html_files) 6 | 7 | html/%.html: template/%.tt 8 | tpage $< > $@ 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Name 2 | ==== 3 | 4 | openresty-survey - OpenResty Web App for OpenResty User Survey 5 | 6 | Table of Contents 7 | ================= 8 | 9 | * [Name](#name) 10 | * [Initialize the MySQL database](#initialize-the-mysql-database) 11 | * [Run This App with OpenResty](#run-this-app-with-openresty) 12 | * [Author](#author) 13 | * [Copyright and License](#copyright-and-license) 14 | 15 | Description 16 | =========== 17 | 18 | This is the source code for the OpenResty User Survey app built upon OpenResty. 19 | 20 | See the sites alive below: 21 | 22 | * https://openresty.org/survey/ (English version) 23 | * https://openresty.org/survey/cn (Chinese version) 24 | 25 | Initialize the MySQL database 26 | ============================= 27 | 28 | Ensure you have the following lines added under the `[mysqld]` group in your `my.cnf` configuration 29 | file for your MySQL server (usually being `/etc/my.cnf`): 30 | 31 | ``` 32 | character-set-server=utf8 33 | collation-server=utf8_general_ci 34 | ``` 35 | 36 | such that your MySQL server uses the UTF-8 character encoding by default. Remember to restart 37 | your MySQL server after this change. 38 | 39 | Below we create a MySQL database named `ngx_test` as well as a MySQL user account named 40 | `ngx_test` with the password `ngx_test`. 41 | 42 | ```console 43 | $ mysql -u root 44 | mysql> create database ngx_test; 45 | mysql> create user 'ngx_test'@'localhost' identified by 'ngx_test'; 46 | mysql> grant all privileges on ngx_test.* to 'ngx_test'@'localhost' with grant option; 47 | ``` 48 | 49 | ```console 50 | $ cd /path/to/openresty-survey/ 51 | $ mysql -u ngx_test ngx_test -p < init/mysql.sql 52 | (type the password "ngx_test") 53 | ``` 54 | 55 | Run This App with OpenResty 56 | =========================== 57 | 58 | ```bash 59 | cd /path/to/openresty-survey/ 60 | # update conf/nginx.conf as needed 61 | /usr/local/openresty/nginx/sbin/nginx -p $PWD/ -c conf/nginx.conf 62 | ``` 63 | 64 | Here we assume you installed OpenResty with its default prefix, `/usr/local/openresty`. 65 | 66 | Author 67 | ====== 68 | 69 | Yichun Zhang (agentzh) <agentzh@gmail.com> 70 | 71 | [Back to TOC](#table-of-contents) 72 | 73 | Copyright and License 74 | ===================== 75 | 76 | This module is licensed under the BSD license. 77 | 78 | Copyright (C) 2015-2017, by Yichun "agentzh" Zhang (章亦春) <agentzh@gmail.com>, OpenResty Inc. 79 | 80 | All rights reserved. 81 | 82 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 83 | 84 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 85 | 86 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 87 | 88 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 89 | 90 | [Back to TOC](#table-of-contents) 91 | 92 | -------------------------------------------------------------------------------- /conf/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/x-icon ico; 22 | image/x-jng jng; 23 | image/x-ms-bmp bmp; 24 | image/svg+xml svg svgz; 25 | image/webp webp; 26 | 27 | application/font-woff woff; 28 | application/java-archive jar war ear; 29 | application/json json; 30 | application/mac-binhex40 hqx; 31 | application/msword doc; 32 | application/pdf pdf; 33 | application/postscript ps eps ai; 34 | application/rtf rtf; 35 | application/vnd.apple.mpegurl m3u8; 36 | application/vnd.ms-excel xls; 37 | application/vnd.ms-fontobject eot; 38 | application/vnd.ms-powerpoint ppt; 39 | application/vnd.wap.wmlc wmlc; 40 | application/vnd.google-earth.kml+xml kml; 41 | application/vnd.google-earth.kmz kmz; 42 | application/x-7z-compressed 7z; 43 | application/x-cocoa cco; 44 | application/x-java-archive-diff jardiff; 45 | application/x-java-jnlp-file jnlp; 46 | application/x-makeself run; 47 | application/x-perl pl pm; 48 | application/x-pilot prc pdb; 49 | application/x-rar-compressed rar; 50 | application/x-redhat-package-manager rpm; 51 | application/x-sea sea; 52 | application/x-shockwave-flash swf; 53 | application/x-stuffit sit; 54 | application/x-tcl tcl tk; 55 | application/x-x509-ca-cert der pem crt; 56 | application/x-xpinstall xpi; 57 | application/xhtml+xml xhtml; 58 | application/xspf+xml xspf; 59 | application/zip zip; 60 | 61 | application/octet-stream bin exe dll; 62 | application/octet-stream deb; 63 | application/octet-stream dmg; 64 | application/octet-stream iso img; 65 | application/octet-stream msi msp msm; 66 | 67 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; 68 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; 69 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; 70 | 71 | audio/midi mid midi kar; 72 | audio/mpeg mp3; 73 | audio/ogg ogg; 74 | audio/x-m4a m4a; 75 | audio/x-realaudio ra; 76 | 77 | video/3gpp 3gpp 3gp; 78 | video/mp2t ts; 79 | video/mp4 mp4; 80 | video/mpeg mpeg mpg; 81 | video/quicktime mov; 82 | video/webm webm; 83 | video/x-flv flv; 84 | video/x-m4v m4v; 85 | video/x-mng mng; 86 | video/x-ms-asf asx asf; 87 | video/x-ms-wmv wmv; 88 | video/x-msvideo avi; 89 | } 90 | -------------------------------------------------------------------------------- /conf/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon on; 2 | master_process on; 3 | worker_processes 1; 4 | error_log logs/error.log debug; 5 | pid logs/nginx.pid; 6 | #pcre_jit on; 7 | 8 | events { 9 | accept_mutex off; 10 | } 11 | 12 | http { 13 | lua_package_path "$prefix/lua/?.lua;;"; 14 | lua_code_cache on; 15 | 16 | limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; 17 | limit_conn_zone $binary_remote_addr zone=addr:10m; 18 | 19 | server { 20 | listen 8080; 21 | 22 | include mime.types; 23 | 24 | location = /survey/cn { 25 | rewrite ^ /survey/cn-index.html last; 26 | } 27 | 28 | location /survey { 29 | alias html; 30 | index index.html; 31 | } 32 | 33 | location /survey/css { 34 | alias css; 35 | } 36 | 37 | location /survey/js { 38 | alias js; 39 | } 40 | 41 | location = /survey/post { 42 | client_body_buffer_size 20k; 43 | client_body_timeout 20s; 44 | client_max_body_size 20k; 45 | 46 | limit_req zone=one burst=5; 47 | limit_conn addr 1; 48 | 49 | content_by_lua_block { require("survey.post").go() } 50 | 51 | error_page 503 /survey/fail.html; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /css/cn-home.css: -------------------------------------------------------------------------------- 1 | #cnt1 { 2 | /* background-color: rgba(215, 212, 212, 0.88); */ 3 | margin-top: 10px; 4 | margin-bottom: 70px; 5 | } 6 | 7 | #panel1 { 8 | padding:20px; 9 | } 10 | 11 | .panel-body:not(.two-col) { 12 | padding: 0px; 13 | } 14 | 15 | .panel-body .radio, .panel-body .checkbox { 16 | margin-top: 0px; 17 | margin-bottom: 0px; 18 | } 19 | 20 | .panel-body .list-group { 21 | margin-bottom: 0; 22 | } 23 | 24 | .margin-bottom-none { 25 | margin-bottom: 0; 26 | } 27 | 28 | @media screen and (min-width: 480px) { 29 | .text-box-md { 30 | width: 20em; 31 | } 32 | 33 | .text-box-lg { 34 | width: 33em; 35 | } 36 | 37 | .text-label { 38 | display: inline-block; 39 | width: 6em; 40 | } 41 | 42 | .text-label-lg { 43 | display: inline-block; 44 | width: 17em; 45 | } 46 | } 47 | 48 | .success-icon { 49 | color: green; 50 | padding: 10px; 51 | font-size: 110%; 52 | } 53 | 54 | .fail-icon { 55 | color: red; 56 | padding: 10px; 57 | font-size: 110%; 58 | } 59 | 60 | .required-field { 61 | color: red; 62 | } 63 | -------------------------------------------------------------------------------- /css/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openresty/openresty-survey/d4ee1f4bd39b005e84b8c1393a32bb1eb2dedc1c/css/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /css/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openresty/openresty-survey/d4ee1f4bd39b005e84b8c1393a32bb1eb2dedc1c/css/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /css/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openresty/openresty-survey/d4ee1f4bd39b005e84b8c1393a32bb1eb2dedc1c/css/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /css/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openresty/openresty-survey/d4ee1f4bd39b005e84b8c1393a32bb1eb2dedc1c/css/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /css/home.css: -------------------------------------------------------------------------------- 1 | #cnt1 { 2 | /* background-color: rgba(215, 212, 212, 0.88); */ 3 | margin-top: 10px; 4 | margin-bottom: 70px; 5 | } 6 | 7 | #panel1 { 8 | padding:20px; 9 | } 10 | 11 | .panel-body:not(.two-col) { 12 | padding: 0px; 13 | } 14 | 15 | .panel-body .radio, .panel-body .checkbox { 16 | margin-top: 0px; 17 | margin-bottom: 0px; 18 | } 19 | 20 | .panel-body .list-group { 21 | margin-bottom: 0; 22 | } 23 | 24 | .margin-bottom-none { 25 | margin-bottom: 0; 26 | } 27 | 28 | @media screen and (min-width: 480px) { 29 | .text-box-md { 30 | width: 20em; 31 | } 32 | 33 | .text-box-lg { 34 | width: 33em; 35 | } 36 | 37 | .text-label { 38 | display: inline-block; 39 | width: 8em; 40 | } 41 | 42 | .text-label-lg { 43 | display: inline-block; 44 | width: 24em; 45 | } 46 | } 47 | 48 | .success-icon { 49 | color: green; 50 | padding: 10px; 51 | font-size: 110%; 52 | } 53 | 54 | .fail-icon { 55 | color: red; 56 | padding: 10px; 57 | font-size: 110%; 58 | } 59 | 60 | .required-field { 61 | color: red; 62 | } 63 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | } 4 | .starter-template { 5 | padding: 40px 15px; 6 | text-align: center; 7 | } 8 | -------------------------------------------------------------------------------- /css/vendor/ie10-viewport-bug-workaround.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * IE10 viewport hack for Surface/desktop Windows 8 bug 3 | * Copyright 2014-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | /* 8 | * See the Getting Started docs for more information: 9 | * http://getbootstrap.com/getting-started/#support-ie10-width 10 | */ 11 | @-webkit-viewport { width: device-width; } 12 | @-moz-viewport { width: device-width; } 13 | @-ms-viewport { width: device-width; } 14 | @-o-viewport { width: device-width; } 15 | @viewport { width: device-width; } 16 | -------------------------------------------------------------------------------- /html/cn-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | OpenResty User Survey 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 57 | 58 |
59 |
60 |
61 | 62 |
63 |
64 |
65 |

66 | 用户调查

67 |
68 |
69 | 70 |
71 |
72 |

73 | OpenResty 团队会对用户提交的信息严格保密,除非用户明确允许我们公开其中的某些信息。 74 |

75 |

当我们说“OpenResty”的时候,我们既指 OpenResty 软件包,也指 OpenResty 的核心组件,例如 ngx_lua 模块.

76 |

标记有 * 的表单字段为必填项。

77 |
78 |
79 | 80 |
81 | 82 | 83 |
84 | 85 | 86 |
87 |
88 |
89 | 90 | *
95 |
96 |
97 |
98 | 99 |
100 |
101 |
102 | 103 | *
108 |
109 |
110 |
111 |
112 | 113 |
114 | 115 | 116 |
117 |
118 |
119 | 120 | *
125 |
126 |
127 |
128 | 129 |
130 |
131 |
132 | 133 | *
138 |
139 |
140 |
141 |
142 | 143 |
144 | 145 | 146 |
147 |
148 |
149 | 150 | *
155 |
156 |
157 |
158 | 159 |
160 |
161 |
162 | 163 |
168 |
169 |
170 |
171 |
172 | 173 |
174 | 175 | 176 |
177 |
178 |
179 | 180 |
185 |
186 |
187 |
188 | 189 |
190 |
191 |
192 | 193 |
198 |
199 |
200 |
201 |
202 | 203 |
204 | 205 | 206 |
207 |
208 |
209 | 210 |
215 |
216 |
217 |
218 | 219 |
220 |
221 |
222 | 223 |
228 |
229 |
230 |
231 |
232 | 233 |
234 | 235 | 236 |
237 |
238 |
239 | 240 |
245 |
246 |
247 |
248 | 249 |
250 |
251 |
252 | 253 |
258 |
259 |
260 |
261 |
262 | 263 |
264 |
265 |
266 |
267 | 268 | 272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 | 281 | 285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 | 294 | 298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 | 307 | 311 | (每秒)
312 |
313 |
314 |
315 |
316 | 317 |
318 |
319 |
320 | 323 |
324 |
325 |
326 |
327 |
328 |
329 | 332 |
333 |
334 |
335 |
336 |
337 | 338 |
339 |
340 |
341 | 344 |
345 |
346 |
347 |
348 |
349 |
350 | 353 |
354 |
355 |
356 |
357 | 358 |
359 |
360 |
361 |
362 | 366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 | 378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 | 390 |
391 |
392 |
393 |
394 | 395 |
396 | 410 |
411 |
412 |
413 | 414 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | -------------------------------------------------------------------------------- /html/fail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | OpenResty User Survey Failed 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 57 | 58 |
59 | 60 |
61 | 62 |

63 | 64 | Sorry, there is something wrong while submitting your survey.
65 |

66 |

67 | Please contact openresty@gmail.com if the problem persists. 68 |

69 |
70 |

71 | Return to the survey page 72 |

73 |
74 | 75 |
76 | 77 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | OpenResty User Survey 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | 37 | 38 | 58 | 59 |
60 |
61 |
62 | 63 |
64 |
65 |
66 |

67 | User Survey

68 |
69 |
70 | 71 |
72 |
73 |

74 | The OpenResty team will keep the submitted user information strictly confidential unless being 75 | explicitly told otherwise. 76 |

77 |

By "OpenResty" we mean either the OpenResty bundle or just core OpenResty components like the ngx_lua module.

78 |

Fields marked by * are required.

79 |
80 |
81 | 82 |
83 | 84 | 85 |
86 | 87 | 88 |
89 |
90 |
91 | 92 | *
97 |
98 |
99 |
100 | 101 |
102 |
103 |
104 | 105 | *
110 |
111 |
112 |
113 |
114 | 115 |
116 | 117 | 118 |
119 |
120 |
121 | 122 | *
127 |
128 |
129 |
130 | 131 |
132 |
133 |
134 | 135 | *
140 |
141 |
142 |
143 |
144 | 145 |
146 | 147 | 148 |
149 |
150 |
151 | 152 | *
157 |
158 |
159 |
160 | 161 |
162 |
163 |
164 | 165 |
170 |
171 |
172 |
173 |
174 | 175 |
176 | 177 | 178 |
179 |
180 |
181 | 182 |
187 |
188 |
189 |
190 | 191 |
192 |
193 |
194 | 195 |
200 |
201 |
202 |
203 |
204 | 205 |
206 | 207 | 208 |
209 |
210 |
211 | 212 |
217 |
218 |
219 |
220 | 221 |
222 |
223 |
224 | 225 |
230 |
231 |
232 |
233 |
234 | 235 |
236 | 237 | 238 |
239 |
240 |
241 | 242 |
247 |
248 |
249 |
250 | 251 |
252 |
253 |
254 | 255 |
260 |
261 |
262 |
263 |
264 | 265 |
266 |
267 |
268 |
269 | 270 | 274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 | 283 | 287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 | 296 | 300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 | 309 | 313 | (per second)
314 |
315 |
316 |
317 |
318 | 319 |
320 |
321 |
322 | 325 |
326 |
327 |
328 |
329 |
330 |
331 | 334 |
335 |
336 |
337 |
338 |
339 | 340 |
341 |
342 |
343 | 346 |
347 |
348 |
349 |
350 |
351 |
352 | 355 |
356 |
357 |
358 |
359 | 360 |
361 |
362 |
363 |
364 | 368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 | 380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 | 392 |
393 |
394 |
395 |
396 | 397 |
398 | 412 |
413 |
414 |
415 | 416 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | -------------------------------------------------------------------------------- /html/success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | OpenResty User Survey Success 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 57 | 58 |
59 | 60 |
61 | 62 |

63 | 64 | Thank you for submitting the survey results! 65 |

66 |
67 |

68 | Return to the OpenResty home 69 |

70 |
71 | 72 |
73 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /init/mysql.sql: -------------------------------------------------------------------------------- 1 | create table user_survey ( 2 | id serial primary key, 3 | first_name varchar(50) not null, 4 | last_name varchar(50) not null, 5 | country varchar(125) not null, 6 | city varchar(35) not null, 7 | email varchar(255) not null unique, 8 | homepage varchar(2038), 9 | github varchar(40), 10 | twitter varchar(40), 11 | weibo varchar(40), 12 | company varchar(50), 13 | company_url varchar(2038), 14 | job_title varchar(30), 15 | department varchar(30), 16 | logo varchar(2038), 17 | typical_uses varchar(2048), 18 | dev_count integer, 19 | traffic varchar(50), 20 | prod tinyint, 21 | fun tinyint, 22 | extern tinyint, 23 | intern tinyint, 24 | show_logo tinyint, 25 | subscribed tinyint, 26 | will_tell tinyint, 27 | client_addr varchar(45) not null, 28 | inserted datetime not null 29 | ) 30 | engine = InnoDB 31 | default character set = utf8 32 | collate = utf8_bin; 33 | -------------------------------------------------------------------------------- /js/vendor/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); -------------------------------------------------------------------------------- /js/vendor/ie-emulation-modes-warning.js: -------------------------------------------------------------------------------- 1 | // NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT 2 | // IT'S JUST JUNK FOR OUR DOCS! 3 | // ++++++++++++++++++++++++++++++++++++++++++ 4 | /*! 5 | * Copyright 2014-2015 Twitter, Inc. 6 | * 7 | * Licensed under the Creative Commons Attribution 3.0 Unported License. For 8 | * details, see https://creativecommons.org/licenses/by/3.0/. 9 | */ 10 | // Intended to prevent false-positive bug reports about Bootstrap not working properly in old versions of IE due to folks testing using IE's unreliable emulation modes. 11 | (function () { 12 | 'use strict'; 13 | 14 | function emulatedIEMajorVersion() { 15 | var groups = /MSIE ([0-9.]+)/.exec(window.navigator.userAgent) 16 | if (groups === null) { 17 | return null 18 | } 19 | var ieVersionNum = parseInt(groups[1], 10) 20 | var ieMajorVersion = Math.floor(ieVersionNum) 21 | return ieMajorVersion 22 | } 23 | 24 | function actualNonEmulatedIEMajorVersion() { 25 | // Detects the actual version of IE in use, even if it's in an older-IE emulation mode. 26 | // IE JavaScript conditional compilation docs: https://msdn.microsoft.com/library/121hztk3%28v=vs.94%29.aspx 27 | // @cc_on docs: https://msdn.microsoft.com/library/8ka90k2e%28v=vs.94%29.aspx 28 | var jscriptVersion = new Function('/*@cc_on return @_jscript_version; @*/')() // jshint ignore:line 29 | if (jscriptVersion === undefined) { 30 | return 11 // IE11+ not in emulation mode 31 | } 32 | if (jscriptVersion < 9) { 33 | return 8 // IE8 (or lower; haven't tested on IE<8) 34 | } 35 | return jscriptVersion // IE9 or IE10 in any mode, or IE11 in non-IE11 mode 36 | } 37 | 38 | var ua = window.navigator.userAgent 39 | if (ua.indexOf('Opera') > -1 || ua.indexOf('Presto') > -1) { 40 | return // Opera, which might pretend to be IE 41 | } 42 | var emulated = emulatedIEMajorVersion() 43 | if (emulated === null) { 44 | return // Not IE 45 | } 46 | var nonEmulated = actualNonEmulatedIEMajorVersion() 47 | 48 | if (emulated !== nonEmulated) { 49 | window.alert('WARNING: You appear to be using IE' + nonEmulated + ' in IE' + emulated + ' emulation mode.\nIE emulation modes can behave significantly differently from ACTUAL older versions of IE.\nPLEASE DON\'T FILE BOOTSTRAP BUGS based on testing in IE emulation modes!') 50 | } 51 | })(); 52 | -------------------------------------------------------------------------------- /js/vendor/ie10-viewport-bug-workaround.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * IE10 viewport hack for Surface/desktop Windows 8 bug 3 | * Copyright 2014-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | // See the Getting Started docs for more information: 8 | // http://getbootstrap.com/getting-started/#support-ie10-width 9 | 10 | (function () { 11 | 'use strict'; 12 | 13 | if (navigator.userAgent.match(/IEMobile\/10\.0/)) { 14 | var msViewportStyle = document.createElement('style') 15 | msViewportStyle.appendChild( 16 | document.createTextNode( 17 | '@-ms-viewport{width:auto!important}' 18 | ) 19 | ) 20 | document.querySelector('head').appendChild(msViewportStyle) 21 | } 22 | 23 | })(); 24 | -------------------------------------------------------------------------------- /js/vendor/validator.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Validator v0.9.0 for Bootstrap 3, by @1000hz 3 | * Copyright 2015 Cina Saffary 4 | * Licensed under http://opensource.org/licenses/MIT 5 | * 6 | * https://github.com/1000hz/bootstrap-validator 7 | */ 8 | 9 | +function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),f=d.data("bs.validator");(f||"destroy"!=b)&&(f||d.data("bs.validator",f=new c(this,e)),"string"==typeof b&&f[b]())})}var c=function(b,d){this.$element=a(b),this.options=d,d.errors=a.extend({},c.DEFAULTS.errors,d.errors);for(var e in d.custom)if(!d.errors[e])throw new Error("Missing default error message for custom validator: "+e);a.extend(c.VALIDATORS,d.custom),this.$element.attr("novalidate",!0),this.toggleSubmit(),this.$element.on("input.bs.validator change.bs.validator focusout.bs.validator",a.proxy(this.validateInput,this)),this.$element.on("submit.bs.validator",a.proxy(this.onSubmit,this)),this.$element.find("[data-match]").each(function(){var b=a(this),c=b.data("match");a(c).on("input.bs.validator",function(){b.val()&&b.trigger("input.bs.validator")})})};c.INPUT_SELECTOR=':input:not([type="submit"], button):enabled:visible',c.DEFAULTS={delay:500,html:!1,disable:!0,custom:{},errors:{match:"Does not match",minlength:"Not long enough"},feedback:{success:"glyphicon-ok",error:"glyphicon-remove"}},c.VALIDATORS={"native":function(a){var b=a[0];return b.checkValidity?b.checkValidity():!0},match:function(b){var c=b.data("match");return!b.val()||b.val()===a(c).val()},minlength:function(a){var b=a.data("minlength");return!a.val()||a.val().length>=b}},c.prototype.validateInput=function(b){var c=a(b.target),d=c.data("bs.validator.errors");if(c.is('[type="radio"]')&&(c=this.$element.find('input[name="'+c.attr("name")+'"]')),this.$element.trigger(b=a.Event("validate.bs.validator",{relatedTarget:c[0]})),!b.isDefaultPrevented()){var e=this;this.runValidators(c).done(function(f){c.data("bs.validator.errors",f),f.length?e.showErrors(c):e.clearErrors(c),d&&f.toString()===d.toString()||(b=f.length?a.Event("invalid.bs.validator",{relatedTarget:c[0],detail:f}):a.Event("valid.bs.validator",{relatedTarget:c[0],detail:d}),e.$element.trigger(b)),e.toggleSubmit(),e.$element.trigger(a.Event("validated.bs.validator",{relatedTarget:c[0]}))})}},c.prototype.runValidators=function(b){function d(a){return b.data(a+"-error")||b.data("error")||"native"==a&&b[0].validationMessage||g.errors[a]}var e=[],f=a.Deferred(),g=this.options;return b.data("bs.validator.deferred")&&b.data("bs.validator.deferred").reject(),b.data("bs.validator.deferred",f),a.each(c.VALIDATORS,a.proxy(function(a,c){if((b.data(a)||"native"==a)&&!c.call(this,b)){var f=d(a);!~e.indexOf(f)&&e.push(f)}},this)),!e.length&&b.val()&&b.data("remote")?this.defer(b,function(){var c={};c[b.attr("name")]=b.val(),a.get(b.data("remote"),c).fail(function(a,b,c){e.push(d("remote")||c)}).always(function(){f.resolve(e)})}):f.resolve(e),f.promise()},c.prototype.validate=function(){var a=this.options.delay;return this.options.delay=0,this.$element.find(c.INPUT_SELECTOR).trigger("input.bs.validator"),this.options.delay=a,this},c.prototype.showErrors=function(b){var c=this.options.html?"html":"text";this.defer(b,function(){var d=b.closest(".form-group"),e=d.find(".help-block.with-errors"),f=d.find(".form-control-feedback"),g=b.data("bs.validator.errors");g.length&&(g=a("
    ").addClass("list-unstyled").append(a.map(g,function(b){return a("
  • ")[c](b)})),void 0===e.data("bs.validator.originalContent")&&e.data("bs.validator.originalContent",e.html()),e.empty().append(g),d.addClass("has-error"),f.length&&f.removeClass(this.options.feedback.success)&&f.addClass(this.options.feedback.error)&&d.removeClass("has-success"))})},c.prototype.clearErrors=function(a){var b=a.closest(".form-group"),c=b.find(".help-block.with-errors"),d=b.find(".form-control-feedback");c.html(c.data("bs.validator.originalContent")),b.removeClass("has-error"),d.length&&d.removeClass(this.options.feedback.error)&&d.addClass(this.options.feedback.success)&&b.addClass("has-success")},c.prototype.hasErrors=function(){function b(){return!!(a(this).data("bs.validator.errors")||[]).length}return!!this.$element.find(c.INPUT_SELECTOR).filter(b).length},c.prototype.isIncomplete=function(){function b(){return"checkbox"===this.type?!this.checked:"radio"===this.type?!a('[name="'+this.name+'"]:checked').length:""===a.trim(this.value)}return!!this.$element.find(c.INPUT_SELECTOR).filter("[required]").filter(b).length},c.prototype.onSubmit=function(a){this.validate(),(this.isIncomplete()||this.hasErrors())&&a.preventDefault()},c.prototype.toggleSubmit=function(){if(this.options.disable){var b=a('button[type="submit"], input[type="submit"]').filter('[form="'+this.$element.attr("id")+'"]').add(this.$element.find('input[type="submit"], button[type="submit"]'));b.toggleClass("disabled",this.isIncomplete()||this.hasErrors())}},c.prototype.defer=function(b,c){return c=a.proxy(c,this),this.options.delay?(window.clearTimeout(b.data("bs.validator.timeout")),void b.data("bs.validator.timeout",window.setTimeout(c,this.options.delay))):c()},c.prototype.destroy=function(){return this.$element.removeAttr("novalidate").removeData("bs.validator").off(".bs.validator"),this.$element.find(c.INPUT_SELECTOR).off(".bs.validator").removeData(["bs.validator.errors","bs.validator.deferred"]).each(function(){var b=a(this),c=b.data("bs.validator.timeout");window.clearTimeout(c)&&b.removeData("bs.validator.timeout")}),this.$element.find(".help-block.with-errors").each(function(){var b=a(this),c=b.data("bs.validator.originalContent");b.removeData("bs.validator.originalContent").html(c)}),this.$element.find('input[type="submit"], button[type="submit"]').removeClass("disabled"),this.$element.find(".has-error").removeClass("has-error"),this};var d=a.fn.validator;a.fn.validator=b,a.fn.validator.Constructor=c,a.fn.validator.noConflict=function(){return a.fn.validator=d,this},a(window).on("load",function(){a('form[data-toggle="validator"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery); -------------------------------------------------------------------------------- /logs/README: -------------------------------------------------------------------------------- 1 | This directory contains nginx log files like error.log and access.log. 2 | -------------------------------------------------------------------------------- /lua/survey/post.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Yichun Zhang (agentzh) 2 | 3 | local string = require "string" 4 | local cjson = require "cjson" 5 | local table_new = require "table.new" 6 | local table = require "table" 7 | local resty_mysql = require "resty.mysql" 8 | 9 | local table_concat = table.concat 10 | local read_body = ngx.req.read_body 11 | local set_method = ngx.req.set_method 12 | local get_post_args = ngx.req.get_post_args 13 | local quote_sql_str = ngx.quote_sql_str 14 | local str_fmt = string.format 15 | local ipairs = ipairs 16 | local HTTP_GET = ngx.HTTP_GET 17 | local ngx_time = ngx.time 18 | local ngx_exec = ngx.exec 19 | local ngx_var = ngx.var 20 | 21 | local _M = {} 22 | 23 | local fields = { 24 | "first_name", 25 | "last_name", 26 | "country", 27 | "city", 28 | "email", 29 | "homepage", 30 | "github", 31 | "twitter", 32 | "weibo", 33 | "company", 34 | "company_url", 35 | "job_title", 36 | "department", 37 | "logo", 38 | "typical_uses", 39 | "dev_count", 40 | "traffic", 41 | "prod", 42 | "fun", 43 | "extern", 44 | "intern", 45 | "show_logo", 46 | "subscribed", 47 | "will_tell", 48 | "client_addr", 49 | "inserted", 50 | } 51 | 52 | local field_list = table_concat(fields, ", ") 53 | 54 | local values = table_new(#fields, 0) 55 | 56 | local function quote(s) 57 | if not s or s == "" then 58 | return "NULL" 59 | end 60 | return quote_sql_str(s) 61 | end 62 | 63 | local function build_value_list(args) 64 | local ncols = #fields 65 | -- no need to call table.clear() here since we a fixed set 66 | -- of keys 67 | for i, key in ipairs(fields) do 68 | if key == 'inserted' then 69 | values[i] = 'from_unixtime(' .. ngx_time() .. ')' 70 | else 71 | values[i] = quote(args[key]) 72 | end 73 | end 74 | return table_concat(values, ", ") 75 | end 76 | 77 | local function fail(...) 78 | ngx.log(ngx.ERR, ...) 79 | set_method(HTTP_GET) 80 | ngx.status = 500 81 | ngx_exec("/survey/fail.html") 82 | end 83 | 84 | local function warn(...) 85 | ngx.log(ngx.WARN, ...) 86 | end 87 | 88 | function _M.go() 89 | -- warn("header: ", ngx.req.raw_header()) 90 | read_body() 91 | local args = get_post_args(#fields) 92 | 93 | -- warn("body: ", ngx.req.get_body_data()) 94 | -- warn("args: ", cjson.encode(args)) 95 | 96 | local first_name = quote(args.first_name) 97 | local last_name = quote(args.last_name) 98 | 99 | local db, err = resty_mysql:new() 100 | if not db then 101 | return fail("failed to create mysql instance: ", err) 102 | end 103 | 104 | db:set_timeout(1000) -- 1 sec 105 | 106 | local ok, err, errno, sqlstate = db:connect{ 107 | host = "127.0.0.1", 108 | port = 3306, 109 | database = "ngx_test", 110 | user = "ngx_test", 111 | password = "ngx_test", 112 | max_packet_size = 1024 113 | } 114 | 115 | if not ok then 116 | return fail("failed to connect to mysql: ", err, ": ", errno, " ", 117 | sqlstate) 118 | end 119 | 120 | args.client_addr = ngx_var.remote_addr 121 | 122 | local value_list = build_value_list(args) 123 | 124 | local sql = str_fmt("insert into user_survey (%s) values (%s)", 125 | field_list, value_list) 126 | 127 | local res, err, errno, sqlstate = db:query(sql) 128 | if not res then 129 | return fail("failed to insert a record into mysql: ", 130 | err, ": ", errno, ": ", sqlstate, ".") 131 | end 132 | 133 | local ok, err = db:set_keepalive(10000, 10) 134 | if not ok then 135 | return fail("mysql: failed to set keepalive: ", err) 136 | end 137 | 138 | set_method(HTTP_GET) 139 | return ngx_exec("/survey/success.html") 140 | end 141 | 142 | return _M 143 | -------------------------------------------------------------------------------- /template/cn-index.tt: -------------------------------------------------------------------------------- 1 | 2 | [%- DEFAULT 3 | form = [ 4 | { 5 | name = "last_name", 6 | label = "姓", 7 | required = 1, 8 | pattern = "\\S+" 9 | }, 10 | { 11 | name = "first_name", 12 | label = "名", 13 | required = 1, 14 | pattern = "\\S+" 15 | }, 16 | { 17 | name = "country", 18 | label = "国家/地区", 19 | required = 1, 20 | }, 21 | { 22 | name = "city", 23 | label = "城市", 24 | required = 1, 25 | }, 26 | { 27 | name = "email", 28 | label = "电子信箱", 29 | required = 1, 30 | type = "email", 31 | }, 32 | { 33 | name = "homepage", 34 | label = "个人主页", 35 | type = "url", 36 | } 37 | { 38 | name = "github", 39 | label = "GitHub ID", 40 | pattern = "[-\\w]+" 41 | }, 42 | { 43 | name = "weibo", 44 | label = "新浪微博 ID", 45 | pattern = "\\S+" 46 | }, 47 | { 48 | name = "company", 49 | label = "公司名称", 50 | }, 51 | { 52 | name = "company_url", 53 | label = "公司主页", 54 | type = "url", 55 | }, 56 | { 57 | name = "job_title", 58 | label = "工作职位", 59 | }, 60 | { 61 | name = "department", 62 | label = "公司部门", 63 | }, 64 | { 65 | name = "logo", 66 | label = "公司徽标图片的 URL", 67 | single = 1, 68 | type = "url", 69 | class = "text-box-lg", 70 | }, 71 | { 72 | name = "typical_uses", 73 | label = "OpenResty 在公司的典型应用场景", 74 | single = 1, 75 | class = "text-box-lg", 76 | }, 77 | { 78 | name = "dev_count", 79 | label = "公司使用 OpenResty 的开发者人数", 80 | single = 1, 81 | class = "text-box-md", 82 | type = "number", 83 | }, 84 | { 85 | name = "traffic", 86 | label = "公司使用 OpenResty 服务的大致流量", 87 | single = 1, 88 | class = "text-box-md", 89 | suffix = "(每秒)", 90 | }, 91 | { 92 | name = "prod", 93 | label = "正在生产上使用 OpenResty", 94 | checkbox = 1, 95 | }, 96 | { 97 | name = "fun", 98 | label = "为了兴趣使用 OpenResty", 99 | checkbox = 1, 100 | }, 101 | { 102 | name = "extern", 103 | label = "在公司的对外服务中使用 OpenResty", 104 | checkbox = 1, 105 | }, 106 | { 107 | name = "intern", 108 | label = "在公司的内部工具中使用 OpenResty", 109 | checkbox = 1, 110 | }, 111 | { 112 | name = "show_logo", 113 | label = "希望在 OpenResty 官网的“谁在使用 OpenResty”页面上展示公司的徽标", 114 | checkbox = 1, 115 | single = 1, 116 | }, 117 | { 118 | name = "subscribed", 119 | label = '已经订阅了 openresty 邮件列表', 120 | checkbox = 1, 121 | single = 1, 122 | }, 123 | { 124 | name = "will_tell", 125 | label = "乐意把 OpenResty 介绍给其他人", 126 | checkbox = 1, 127 | single = 1, 128 | }, 129 | ] 130 | note = "This file was automatically generated from template/cn-index.tt." 131 | -%] 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | OpenResty User Survey 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 164 | 165 | 166 | 167 | 168 | 188 | 189 |
    190 |
    191 |
    192 | 193 |
    194 |
    195 |
    196 |

    197 | 用户调查

    198 |
    199 |
    200 | 201 |
    202 |
    203 |

    204 | OpenResty 团队会对用户提交的信息严格保密,除非用户明确允许我们公开其中的某些信息。 205 |

    206 |

    当我们说“OpenResty”的时候,我们既指 OpenResty 软件包,也指 OpenResty 的核心组件,例如 ngx_lua 模块.

    207 |

    标记有 * 的表单字段为必填项。

    208 |
    209 |
    210 | 211 |
    212 | 213 | [%- i = 0 %] 214 | [%- WHILE i < form.size %] 215 | [%- field = form.$i -%] 216 | [%- IF field.single; 217 | LAST; 218 | END %] 219 | 220 |
    221 | 222 | [%- j = 0 -%] 223 | [%- WHILE j < 2 -%] 224 | [%- j = j + 1 -%] 225 | 226 | [%- IF i >= form.size; 227 | LAST; 228 | END %] 229 | [%- field = form.$i -%] 230 | [%- i = i + 1 -%] 231 | [%- IF NOT field.name; 232 | LAST; 233 | END %] 234 | 235 |
    236 |
    237 |
    238 | 239 | 246 | [%- IF field.required -%] 247 | * 248 | [%- END -%] 249 |
    250 |
    251 |
    252 |
    253 | [%- END %] 254 |
    255 | [%- END %] 256 | 257 | [%- WHILE i < form.size %] 258 | [%- field = form.$i; 259 | IF field.checkbox; 260 | LAST; 261 | END %] 262 |
    263 |
    264 |
    265 |
    266 | 267 | 271 | [% IF field.suffix %][% field.suffix %][% END -%] 272 |
    273 |
    274 |
    275 |
    276 | [%- i = i + 1 -%] 277 | [%- END -%] 278 | 279 | [%- WHILE i < form.size %] 280 | [%- field = form.$i; 281 | IF field.single; 282 | LAST; 283 | END -%] 284 | 285 |
    286 | 287 | [%- j = 0; 288 | WHILE j < 2; 289 | field = form.$i; 290 | i = i + 1; 291 | IF NOT field; 292 | LAST; 293 | END; 294 | %] 295 |
    296 |
    297 |
    298 | 302 |
    303 |
    304 |
    305 | [%- j = j + 1 %] 306 | [%- END %] 307 |
    308 | [%- END %] 309 | 310 | [%- WHILE i < form.size %] 311 | [%- field = form.$i %] 312 |
    313 |
    314 |
    315 |
    316 | 320 |
    321 |
    322 |
    323 |
    324 | [%- i = i + 1 %] 325 | [%- END %] 326 | 327 |
    328 | 342 |
    343 |
    344 |
    345 | 346 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | -------------------------------------------------------------------------------- /template/index.tt: -------------------------------------------------------------------------------- 1 | [%- DEFAULT 2 | form = [ 3 | { 4 | name = "first_name", 5 | label = "First Name", 6 | required = 1, 7 | pattern = "\\S+" 8 | }, 9 | { 10 | name = "last_name", 11 | label = "Last Name", 12 | required = 1, 13 | pattern = "\\S+" 14 | }, 15 | { 16 | name = "country", 17 | label = "Country/Region", 18 | required = 1, 19 | }, 20 | { 21 | name = "city", 22 | label = "City", 23 | required = 1, 24 | }, 25 | { 26 | name = "email", 27 | label = "Email", 28 | required = 1, 29 | type = "email", 30 | }, 31 | { 32 | name = "homepage", 33 | label = "Home Page", 34 | type = "url", 35 | } 36 | { 37 | name = "github", 38 | label = "GitHub ID", 39 | pattern = "[-\\w]+" 40 | }, 41 | { 42 | name = "twitter", 43 | label = "Twitter ID", 44 | pattern = "[-\\w]+" 45 | }, 46 | { 47 | name = "company", 48 | label = "Company", 49 | }, 50 | { 51 | name = "company_url", 52 | label = "Company URL", 53 | type = "url", 54 | }, 55 | { 56 | name = "job_title", 57 | label = "Job Title", 58 | }, 59 | { 60 | name = "department", 61 | label = "Department", 62 | }, 63 | { 64 | name = "logo", 65 | label = "URL to your company's logo image", 66 | single = 1, 67 | type = "url", 68 | class = "text-box-lg", 69 | }, 70 | { 71 | name = "typical_uses", 72 | label = "Typical use cases of OpenResty in your company", 73 | single = 1, 74 | class = "text-box-lg", 75 | }, 76 | { 77 | name = "dev_count", 78 | label = "Number of developers doing OpenResty", 79 | single = 1, 80 | class = "text-box-md", 81 | type = "number", 82 | }, 83 | { 84 | name = "traffic", 85 | label = "Approximate traffic through OpenResty", 86 | single = 1, 87 | class = "text-box-md", 88 | suffix = "(per second)", 89 | }, 90 | { 91 | name = "prod", 92 | label = "Using OpenResty in production", 93 | checkbox = 1, 94 | }, 95 | { 96 | name = "fun", 97 | label = "Using OpenResty for fun", 98 | checkbox = 1, 99 | }, 100 | { 101 | name = "extern", 102 | label = "Using OpenResty in your company's external services", 103 | checkbox = 1, 104 | }, 105 | { 106 | name = "intern", 107 | label = "Using OpenResty in your company's internal tools", 108 | checkbox = 1, 109 | }, 110 | { 111 | name = "show_logo", 112 | label = "Want to show your company's logo on the \"Who are using OpenResty\" page of the OpenResty official site", 113 | checkbox = 1, 114 | single = 1, 115 | }, 116 | { 117 | name = "subscribed", 118 | label = 'Already subscribed to the openresty-en mailing list', 119 | checkbox = 1, 120 | single = 1, 121 | }, 122 | { 123 | name = "will_tell", 124 | label = "Will tell other people about OpenResty", 125 | checkbox = 1, 126 | single = 1, 127 | }, 128 | ] 129 | note = "This file was automatically generated from template/index.tt." 130 | -%] 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | OpenResty User Survey 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 164 | 165 | 166 | 167 | 168 | 188 | 189 |
    190 |
    191 |
    192 | 193 |
    194 |
    195 |
    196 |

    197 | User Survey

    198 |
    199 |
    200 | 201 |
    202 |
    203 |

    204 | The OpenResty team will keep the submitted user information strictly confidential unless being 205 | explicitly told otherwise. 206 |

    207 |

    By "OpenResty" we mean either the OpenResty bundle or just core OpenResty components like the ngx_lua module.

    208 |

    Fields marked by * are required.

    209 |
    210 |
    211 | 212 |
    213 | 214 | [%- i = 0 %] 215 | [%- WHILE i < form.size %] 216 | [%- field = form.$i -%] 217 | [%- IF field.single; 218 | LAST; 219 | END %] 220 | 221 |
    222 | 223 | [%- j = 0 -%] 224 | [%- WHILE j < 2 -%] 225 | [%- j = j + 1 -%] 226 | 227 | [%- IF i >= form.size; 228 | LAST; 229 | END %] 230 | [%- field = form.$i -%] 231 | [%- i = i + 1 -%] 232 | [%- IF NOT field.name; 233 | LAST; 234 | END %] 235 | 236 |
    237 |
    238 |
    239 | 240 | 247 | [%- IF field.required -%] 248 | * 249 | [%- END -%] 250 |
    251 |
    252 |
    253 |
    254 | [%- END %] 255 |
    256 | [%- END %] 257 | 258 | [%- WHILE i < form.size %] 259 | [%- field = form.$i; 260 | IF field.checkbox; 261 | LAST; 262 | END %] 263 |
    264 |
    265 |
    266 |
    267 | 268 | 272 | [% IF field.suffix %][% field.suffix %][% END -%] 273 |
    274 |
    275 |
    276 |
    277 | [%- i = i + 1 -%] 278 | [%- END -%] 279 | 280 | [%- WHILE i < form.size %] 281 | [%- field = form.$i; 282 | IF field.single; 283 | LAST; 284 | END -%] 285 | 286 |
    287 | 288 | [%- j = 0; 289 | WHILE j < 2; 290 | field = form.$i; 291 | i = i + 1; 292 | IF NOT field; 293 | LAST; 294 | END; 295 | %] 296 |
    297 |
    298 |
    299 | 303 |
    304 |
    305 |
    306 | [%- j = j + 1 %] 307 | [%- END %] 308 |
    309 | [%- END %] 310 | 311 | [%- WHILE i < form.size %] 312 | [%- field = form.$i %] 313 |
    314 |
    315 |
    316 |
    317 | 321 |
    322 |
    323 |
    324 |
    325 | [%- i = i + 1 %] 326 | [%- END %] 327 | 328 |
    329 | 343 |
    344 |
    345 |
    346 | 347 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | --------------------------------------------------------------------------------