├── .gitignore ├── .gitmodules ├── Procfile ├── README.md ├── bootstrap.sh ├── config.clj ├── epl-v10.html ├── prod-run.sh ├── project.clj ├── resources └── public │ ├── css │ ├── chosen-sprite.png │ ├── chosen.css │ ├── cmtn.css │ ├── embed.css │ ├── refheap.css │ ├── tomorrow-night-bright.css │ └── tomorrow-night.css │ ├── img │ ├── browserid.png │ └── favicon.ico │ ├── js │ ├── api.js │ ├── chosen.jquery.min.js │ ├── create.js │ ├── jquery-1.7.1.min.js │ ├── pastes.js │ └── refheap.js │ └── monokai.css ├── src └── refheap │ ├── config.clj │ ├── dates.clj │ ├── highlight.clj │ ├── markdown.clj │ ├── messages.clj │ ├── models │ ├── api.clj │ ├── login.clj │ ├── paste.clj │ └── users.clj │ ├── server.clj │ ├── utilities.clj │ └── views │ ├── about.clj │ ├── api.clj │ ├── common.clj │ ├── home.clj │ ├── legal.clj │ ├── login.clj │ ├── paste.clj │ ├── templates │ ├── about.html │ ├── all.html │ ├── allheader.html │ ├── api.html │ ├── apihead.html │ ├── common.html │ ├── commonbody.html │ ├── createhead.html │ ├── createuser.html │ ├── embed.html │ ├── embedjs.mustache │ ├── fullscreen.html │ ├── head.html │ ├── loggedin.html │ ├── loggedout.html │ ├── pagination.html │ ├── paste.html │ ├── pasted.html │ ├── preview.html │ ├── privacy.html │ ├── showhead.html │ ├── tos.html │ ├── userheader.html │ └── users.html │ └── users.clj └── test └── noir └── test └── core.clj /.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | *jar 3 | /lib/ 4 | /classes/ 5 | .lein-deps-sum 6 | resources/pygments/ 7 | target -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "resources/public/js/codemirror"] 2 | path = resources/public/js/codemirror 3 | url = git://github.com/marijnh/CodeMirror.git 4 | [submodule "resources/public/js/mousetrap"] 5 | path = resources/public/js/mousetrap 6 | url = git://github.com/ccampbell/mousetrap.git 7 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: ./bootstrap.sh && lein ring server-headless 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RefHeap, The Reference Heap! 2 | 3 | This project is a lightweight Clojure pastebin that uses [Pygments](http://pygments.org) for syntax highlighting. 4 | 5 | ## Usage 6 | 7 | Grab general project dependencies with lein, and grab Pygments with the provided bash script. This project also requires [MongoDB](http://www.mongodb.org). 8 | 9 | ```bash 10 | $ lein deps 11 | $ ./bootstrap.sh 12 | ``` 13 | 14 | Start the Mongo daemon, and in a separate terminal start the RefHeap server using lein. The server will host content from [http://localhost:3000](http://localhost:3000). 15 | 16 | ```bash 17 | $ mongod 18 | $ lein ring server 19 | ``` 20 | 21 | ## License 22 | 23 | Distributed under the Eclipse Public License, the same as Clojure; the terms of which can be found in the file epl-v10.html at the root of this disribution or at [http://opensource.org/licenses/eclipse-1.0.php](http://opensource.org/licenses/eclipse-1.0.php). 24 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SHA="2479eb54f22b" 4 | 5 | echo "Fetching Pygments..." 6 | curl https://bitbucket.org/birkenfeld/pygments-main/get/$SHA.tar.gz -o pygments.tar.gz 7 | tar -xvzf pygments.tar.gz 8 | mv birkenfeld-pygments-main-$SHA resources/pygments 9 | rm pygments.tar.gz 10 | -------------------------------------------------------------------------------- /config.clj: -------------------------------------------------------------------------------- 1 | {:db-name "refheap" 2 | :db-port 27017 3 | :db-host "localhost" 4 | :hosts #{"localhost"} 5 | :port 8080} -------------------------------------------------------------------------------- /epl-v10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Eclipse Public License - Version 1.0 8 | 25 | 26 | 27 | 28 | 29 | 30 |

Eclipse Public License - v 1.0

31 | 32 |

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 33 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR 34 | DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS 35 | AGREEMENT.

36 | 37 |

1. DEFINITIONS

38 | 39 |

"Contribution" means:

40 | 41 |

a) in the case of the initial Contributor, the initial 42 | code and documentation distributed under this Agreement, and

43 |

b) in the case of each subsequent Contributor:

44 |

i) changes to the Program, and

45 |

ii) additions to the Program;

46 |

where such changes and/or additions to the Program 47 | originate from and are distributed by that particular Contributor. A 48 | Contribution 'originates' from a Contributor if it was added to the 49 | Program by such Contributor itself or anyone acting on such 50 | Contributor's behalf. Contributions do not include additions to the 51 | Program which: (i) are separate modules of software distributed in 52 | conjunction with the Program under their own license agreement, and (ii) 53 | are not derivative works of the Program.

54 | 55 |

"Contributor" means any person or entity that distributes 56 | the Program.

57 | 58 |

"Licensed Patents" mean patent claims licensable by a 59 | Contributor which are necessarily infringed by the use or sale of its 60 | Contribution alone or when combined with the Program.

61 | 62 |

"Program" means the Contributions distributed in accordance 63 | with this Agreement.

64 | 65 |

"Recipient" means anyone who receives the Program under 66 | this Agreement, including all Contributors.

67 | 68 |

2. GRANT OF RIGHTS

69 | 70 |

a) Subject to the terms of this Agreement, each 71 | Contributor hereby grants Recipient a non-exclusive, worldwide, 72 | royalty-free copyright license to reproduce, prepare derivative works 73 | of, publicly display, publicly perform, distribute and sublicense the 74 | Contribution of such Contributor, if any, and such derivative works, in 75 | source code and object code form.

76 | 77 |

b) Subject to the terms of this Agreement, each 78 | Contributor hereby grants Recipient a non-exclusive, worldwide, 79 | royalty-free patent license under Licensed Patents to make, use, sell, 80 | offer to sell, import and otherwise transfer the Contribution of such 81 | Contributor, if any, in source code and object code form. This patent 82 | license shall apply to the combination of the Contribution and the 83 | Program if, at the time the Contribution is added by the Contributor, 84 | such addition of the Contribution causes such combination to be covered 85 | by the Licensed Patents. The patent license shall not apply to any other 86 | combinations which include the Contribution. No hardware per se is 87 | licensed hereunder.

88 | 89 |

c) Recipient understands that although each Contributor 90 | grants the licenses to its Contributions set forth herein, no assurances 91 | are provided by any Contributor that the Program does not infringe the 92 | patent or other intellectual property rights of any other entity. Each 93 | Contributor disclaims any liability to Recipient for claims brought by 94 | any other entity based on infringement of intellectual property rights 95 | or otherwise. As a condition to exercising the rights and licenses 96 | granted hereunder, each Recipient hereby assumes sole responsibility to 97 | secure any other intellectual property rights needed, if any. For 98 | example, if a third party patent license is required to allow Recipient 99 | to distribute the Program, it is Recipient's responsibility to acquire 100 | that license before distributing the Program.

101 | 102 |

d) Each Contributor represents that to its knowledge it 103 | has sufficient copyright rights in its Contribution, if any, to grant 104 | the copyright license set forth in this Agreement.

105 | 106 |

3. REQUIREMENTS

107 | 108 |

A Contributor may choose to distribute the Program in object code 109 | form under its own license agreement, provided that:

110 | 111 |

a) it complies with the terms and conditions of this 112 | Agreement; and

113 | 114 |

b) its license agreement:

115 | 116 |

i) effectively disclaims on behalf of all Contributors 117 | all warranties and conditions, express and implied, including warranties 118 | or conditions of title and non-infringement, and implied warranties or 119 | conditions of merchantability and fitness for a particular purpose;

120 | 121 |

ii) effectively excludes on behalf of all Contributors 122 | all liability for damages, including direct, indirect, special, 123 | incidental and consequential damages, such as lost profits;

124 | 125 |

iii) states that any provisions which differ from this 126 | Agreement are offered by that Contributor alone and not by any other 127 | party; and

128 | 129 |

iv) states that source code for the Program is available 130 | from such Contributor, and informs licensees how to obtain it in a 131 | reasonable manner on or through a medium customarily used for software 132 | exchange.

133 | 134 |

When the Program is made available in source code form:

135 | 136 |

a) it must be made available under this Agreement; and

137 | 138 |

b) a copy of this Agreement must be included with each 139 | copy of the Program.

140 | 141 |

Contributors may not remove or alter any copyright notices contained 142 | within the Program.

143 | 144 |

Each Contributor must identify itself as the originator of its 145 | Contribution, if any, in a manner that reasonably allows subsequent 146 | Recipients to identify the originator of the Contribution.

147 | 148 |

4. COMMERCIAL DISTRIBUTION

149 | 150 |

Commercial distributors of software may accept certain 151 | responsibilities with respect to end users, business partners and the 152 | like. While this license is intended to facilitate the commercial use of 153 | the Program, the Contributor who includes the Program in a commercial 154 | product offering should do so in a manner which does not create 155 | potential liability for other Contributors. Therefore, if a Contributor 156 | includes the Program in a commercial product offering, such Contributor 157 | ("Commercial Contributor") hereby agrees to defend and 158 | indemnify every other Contributor ("Indemnified Contributor") 159 | against any losses, damages and costs (collectively "Losses") 160 | arising from claims, lawsuits and other legal actions brought by a third 161 | party against the Indemnified Contributor to the extent caused by the 162 | acts or omissions of such Commercial Contributor in connection with its 163 | distribution of the Program in a commercial product offering. The 164 | obligations in this section do not apply to any claims or Losses 165 | relating to any actual or alleged intellectual property infringement. In 166 | order to qualify, an Indemnified Contributor must: a) promptly notify 167 | the Commercial Contributor in writing of such claim, and b) allow the 168 | Commercial Contributor to control, and cooperate with the Commercial 169 | Contributor in, the defense and any related settlement negotiations. The 170 | Indemnified Contributor may participate in any such claim at its own 171 | expense.

172 | 173 |

For example, a Contributor might include the Program in a commercial 174 | product offering, Product X. That Contributor is then a Commercial 175 | Contributor. If that Commercial Contributor then makes performance 176 | claims, or offers warranties related to Product X, those performance 177 | claims and warranties are such Commercial Contributor's responsibility 178 | alone. Under this section, the Commercial Contributor would have to 179 | defend claims against the other Contributors related to those 180 | performance claims and warranties, and if a court requires any other 181 | Contributor to pay any damages as a result, the Commercial Contributor 182 | must pay those damages.

183 | 184 |

5. NO WARRANTY

185 | 186 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS 187 | PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 188 | OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 189 | ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY 190 | OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely 191 | responsible for determining the appropriateness of using and 192 | distributing the Program and assumes all risks associated with its 193 | exercise of rights under this Agreement , including but not limited to 194 | the risks and costs of program errors, compliance with applicable laws, 195 | damage to or loss of data, programs or equipment, and unavailability or 196 | interruption of operations.

197 | 198 |

6. DISCLAIMER OF LIABILITY

199 | 200 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT 201 | NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, 202 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING 203 | WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF 204 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 205 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR 206 | DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 207 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

208 | 209 |

7. GENERAL

210 | 211 |

If any provision of this Agreement is invalid or unenforceable under 212 | applicable law, it shall not affect the validity or enforceability of 213 | the remainder of the terms of this Agreement, and without further action 214 | by the parties hereto, such provision shall be reformed to the minimum 215 | extent necessary to make such provision valid and enforceable.

216 | 217 |

If Recipient institutes patent litigation against any entity 218 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 219 | Program itself (excluding combinations of the Program with other 220 | software or hardware) infringes such Recipient's patent(s), then such 221 | Recipient's rights granted under Section 2(b) shall terminate as of the 222 | date such litigation is filed.

223 | 224 |

All Recipient's rights under this Agreement shall terminate if it 225 | fails to comply with any of the material terms or conditions of this 226 | Agreement and does not cure such failure in a reasonable period of time 227 | after becoming aware of such noncompliance. If all Recipient's rights 228 | under this Agreement terminate, Recipient agrees to cease use and 229 | distribution of the Program as soon as reasonably practicable. However, 230 | Recipient's obligations under this Agreement and any licenses granted by 231 | Recipient relating to the Program shall continue and survive.

232 | 233 |

Everyone is permitted to copy and distribute copies of this 234 | Agreement, but in order to avoid inconsistency the Agreement is 235 | copyrighted and may only be modified in the following manner. The 236 | Agreement Steward reserves the right to publish new versions (including 237 | revisions) of this Agreement from time to time. No one other than the 238 | Agreement Steward has the right to modify this Agreement. The Eclipse 239 | Foundation is the initial Agreement Steward. The Eclipse Foundation may 240 | assign the responsibility to serve as the Agreement Steward to a 241 | suitable separate entity. Each new version of the Agreement will be 242 | given a distinguishing version number. The Program (including 243 | Contributions) may always be distributed subject to the version of the 244 | Agreement under which it was received. In addition, after a new version 245 | of the Agreement is published, Contributor may elect to distribute the 246 | Program (including its Contributions) under the new version. Except as 247 | expressly stated in Sections 2(a) and 2(b) above, Recipient receives no 248 | rights or licenses to the intellectual property of any Contributor under 249 | this Agreement, whether expressly, by implication, estoppel or 250 | otherwise. All rights in the Program not expressly granted under this 251 | Agreement are reserved.

252 | 253 |

This Agreement is governed by the laws of the State of New York and 254 | the intellectual property laws of the United States of America. No party 255 | to this Agreement will bring a legal action under this Agreement more 256 | than one year after the cause of action arose. Each party waives its 257 | rights to a jury trial in any resulting litigation.

258 | 259 | 260 | 261 | 262 | -------------------------------------------------------------------------------- /prod-run.sh: -------------------------------------------------------------------------------- 1 | export CANONICAL_HOST=www.refheap.com 2 | export HOSTS=refheap.com,www.refheap.com 3 | export JVM_OPTS="-Xmx60m" 4 | export MONGOLAB_URI=mongodb://127.0.0.1/refheap 5 | export MONGO_URI=mongodb://127.0.0.1/refheap 6 | export PORT=43535 7 | export LEIN_NO_DEV=t 8 | 9 | lein trampoline ring server-headless 10 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject refheap "1.4.0" 2 | :description "This is like, totally a pastebin, dude." 3 | :url "https://refheap.com" 4 | :dependencies [[org.clojure/clojure "1.5.0-RC16"] 5 | [stencil "0.2.0"] 6 | [compojure "1.1.5"] 7 | [lib-noir "0.5.6"] 8 | [com.novemberain/monger "1.5.0-beta1"] 9 | [clj-config "0.2.0"] 10 | [clj-http "0.6.4" :exclusions [org.jsoup/jsoup]] 11 | [clavatar "0.2.1"] 12 | [clj-time "0.4.4"] 13 | [me.raynes/conch "0.5.1"] 14 | [commons-codec/commons-codec "1.6"] 15 | [me.raynes/cegdown "0.1.0"] 16 | [me.raynes/laser "1.1.1"]] 17 | :plugins [[lein-ring "0.8.2"]] 18 | :ring {:handler refheap.server/handler}) 19 | 20 | -------------------------------------------------------------------------------- /resources/public/css/chosen-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raynes/refheap/ad85097172a6d11dd9edaa97e2f2eb6d3296e94f/resources/public/css/chosen-sprite.png -------------------------------------------------------------------------------- /resources/public/css/chosen.css: -------------------------------------------------------------------------------- 1 | /* @group Base */ 2 | .chzn-container { 3 | font-size: 13px; 4 | position: relative; 5 | display: inline-block; 6 | zoom: 1; 7 | *display: inline; 8 | } 9 | .chzn-container .chzn-drop { 10 | background: #fff; 11 | border: 1px solid #aaa; 12 | border-top: 0; 13 | position: absolute; 14 | top: 29px; 15 | left: 0; 16 | -webkit-box-shadow: 0 4px 5px rgba(0,0,0,.15); 17 | -moz-box-shadow : 0 4px 5px rgba(0,0,0,.15); 18 | -o-box-shadow : 0 4px 5px rgba(0,0,0,.15); 19 | box-shadow : 0 4px 5px rgba(0,0,0,.15); 20 | z-index: 999; 21 | } 22 | /* @end */ 23 | 24 | /* @group Single Chosen */ 25 | .chzn-container-single .chzn-single { 26 | background-color: #ffffff; 27 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #f4f4f4), color-stop(0.48, #eeeeee), color-stop(0.5, #f6f6f6), color-stop(0.8, #ffffff)); 28 | background-image: -webkit-linear-gradient(center bottom, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); 29 | background-image: -moz-linear-gradient(center bottom, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); 30 | background-image: -o-linear-gradient(top, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); 31 | background-image: -ms-linear-gradient(top, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); 32 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); 33 | background-image: linear-gradient(top, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); 34 | -webkit-border-radius: 5px; 35 | -moz-border-radius : 5px; 36 | border-radius : 5px; 37 | -moz-background-clip : padding; 38 | -webkit-background-clip: padding-box; 39 | background-clip : padding-box; 40 | border: 1px solid #aaaaaa; 41 | -webkit-box-shadow: 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); 42 | -moz-box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); 43 | box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); 44 | display: block; 45 | overflow: hidden; 46 | white-space: nowrap; 47 | position: relative; 48 | height: 23px; 49 | line-height: 24px; 50 | padding: 0 0 0 8px; 51 | color: #444444; 52 | text-decoration: none; 53 | } 54 | .chzn-container-single .chzn-single span { 55 | margin-right: 26px; 56 | display: block; 57 | overflow: hidden; 58 | white-space: nowrap; 59 | -o-text-overflow: ellipsis; 60 | -ms-text-overflow: ellipsis; 61 | text-overflow: ellipsis; 62 | } 63 | .chzn-container-single .chzn-single abbr { 64 | display: block; 65 | position: absolute; 66 | right: 26px; 67 | top: 6px; 68 | width: 12px; 69 | height: 13px; 70 | font-size: 1px; 71 | background: url(chosen-sprite.png) right top no-repeat; 72 | } 73 | .chzn-container-single .chzn-single abbr:hover { 74 | background-position: right -11px; 75 | } 76 | .chzn-container-single .chzn-single div { 77 | position: absolute; 78 | right: 0; 79 | top: 0; 80 | display: block; 81 | height: 100%; 82 | width: 18px; 83 | } 84 | .chzn-container-single .chzn-single div b { 85 | background: url('chosen-sprite.png') no-repeat 0 0; 86 | display: block; 87 | width: 100%; 88 | height: 100%; 89 | } 90 | .chzn-container-single .chzn-search { 91 | padding: 3px 4px; 92 | position: relative; 93 | margin: 0; 94 | white-space: nowrap; 95 | z-index: 1010; 96 | } 97 | .chzn-container-single .chzn-search input { 98 | background: #fff url('chosen-sprite.png') no-repeat 100% -22px; 99 | background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); 100 | background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); 101 | background: url('chosen-sprite.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); 102 | background: url('chosen-sprite.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); 103 | background: url('chosen-sprite.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%,#eeeeee 99%); 104 | background: url('chosen-sprite.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%,#eeeeee 99%); 105 | margin: 1px 0; 106 | padding: 4px 20px 4px 5px; 107 | outline: 0; 108 | border: 1px solid #aaa; 109 | font-family: sans-serif; 110 | font-size: 1em; 111 | } 112 | .chzn-container-single .chzn-drop { 113 | -webkit-border-radius: 0 0 4px 4px; 114 | -moz-border-radius : 0 0 4px 4px; 115 | border-radius : 0 0 4px 4px; 116 | -moz-background-clip : padding; 117 | -webkit-background-clip: padding-box; 118 | background-clip : padding-box; 119 | } 120 | /* @end */ 121 | 122 | .chzn-container-single-nosearch .chzn-search input { 123 | position: absolute; 124 | left: -9000px; 125 | } 126 | 127 | /* @group Multi Chosen */ 128 | .chzn-container-multi .chzn-choices { 129 | background-color: #fff; 130 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); 131 | background-image: -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); 132 | background-image: -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); 133 | background-image: -o-linear-gradient(bottom, white 85%, #eeeeee 99%); 134 | background-image: -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); 135 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); 136 | background-image: linear-gradient(top, #ffffff 85%, #eeeeee 99%); 137 | border: 1px solid #aaa; 138 | margin: 0; 139 | padding: 0; 140 | cursor: text; 141 | overflow: hidden; 142 | height: auto !important; 143 | height: 1%; 144 | position: relative; 145 | } 146 | .chzn-container-multi .chzn-choices li { 147 | float: left; 148 | list-style: none; 149 | } 150 | .chzn-container-multi .chzn-choices .search-field { 151 | white-space: nowrap; 152 | margin: 0; 153 | padding: 0; 154 | } 155 | .chzn-container-multi .chzn-choices .search-field input { 156 | color: #666; 157 | background: transparent !important; 158 | border: 0 !important; 159 | font-family: sans-serif; 160 | font-size: 100%; 161 | height: 15px; 162 | padding: 5px; 163 | margin: 1px 0; 164 | outline: 0; 165 | -webkit-box-shadow: none; 166 | -moz-box-shadow : none; 167 | -o-box-shadow : none; 168 | box-shadow : none; 169 | } 170 | .chzn-container-multi .chzn-choices .search-field .default { 171 | color: #999; 172 | } 173 | .chzn-container-multi .chzn-choices .search-choice { 174 | -webkit-border-radius: 3px; 175 | -moz-border-radius : 3px; 176 | border-radius : 3px; 177 | -moz-background-clip : padding; 178 | -webkit-background-clip: padding-box; 179 | background-clip : padding-box; 180 | background-color: #e4e4e4; 181 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.48, #e8e8e8), color-stop(0.5, #f0f0f0), color-stop(0.8, #f4f4f4)); 182 | background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); 183 | background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); 184 | background-image: -o-linear-gradient(top, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); 185 | background-image: -ms-linear-gradient(top, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); 186 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#f4f4f4',GradientType=0 ); 187 | background-image: linear-gradient(top, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); 188 | -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); 189 | -moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); 190 | box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); 191 | color: #333; 192 | border: 1px solid #aaaaaa; 193 | line-height: 13px; 194 | padding: 3px 20px 3px 5px; 195 | margin: 3px 0 3px 5px; 196 | position: relative; 197 | } 198 | .chzn-container-multi .chzn-choices .search-choice span { 199 | cursor: default; 200 | } 201 | .chzn-container-multi .chzn-choices .search-choice-focus { 202 | background: #d4d4d4; 203 | } 204 | .chzn-container-multi .chzn-choices .search-choice .search-choice-close { 205 | display: block; 206 | position: absolute; 207 | right: 3px; 208 | top: 4px; 209 | width: 12px; 210 | height: 13px; 211 | font-size: 1px; 212 | background: url(chosen-sprite.png) right top no-repeat; 213 | } 214 | .chzn-container-multi .chzn-choices .search-choice .search-choice-close:hover { 215 | background-position: right -11px; 216 | } 217 | .chzn-container-multi .chzn-choices .search-choice-focus .search-choice-close { 218 | background-position: right -11px; 219 | } 220 | /* @end */ 221 | 222 | /* @group Results */ 223 | .chzn-container .chzn-results { 224 | margin: 0 4px 4px 0; 225 | max-height: 240px; 226 | padding: 0 0 0 4px; 227 | position: relative; 228 | overflow-x: hidden; 229 | overflow-y: auto; 230 | } 231 | .chzn-container-multi .chzn-results { 232 | margin: -1px 0 0; 233 | padding: 0; 234 | } 235 | .chzn-container .chzn-results li { 236 | display: none; 237 | line-height: 15px; 238 | padding: 5px 6px; 239 | margin: 0; 240 | list-style: none; 241 | } 242 | .chzn-container .chzn-results .active-result { 243 | cursor: pointer; 244 | display: list-item; 245 | } 246 | .chzn-container .chzn-results .highlighted { 247 | background-color: #3875d7; 248 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.1, #2a62bc), color-stop(0.8, #3875d7)); 249 | background-image: -webkit-linear-gradient(center bottom, #2a62bc 10%, #3875d7 80%); 250 | background-image: -moz-linear-gradient(center bottom, #2a62bc 10%, #3875d7 80%); 251 | background-image: -o-linear-gradient(bottom, #2a62bc 10%, #3875d7 80%); 252 | background-image: -ms-linear-gradient(top, #2a62bc 10%, #3875d7 80%); 253 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2a62bc', endColorstr='#3875d7',GradientType=0 ); 254 | background-image: linear-gradient(top, #2a62bc 10%, #3875d7 80%); 255 | color: #fff; 256 | } 257 | .chzn-container .chzn-results li em { 258 | background: #feffde; 259 | font-style: normal; 260 | } 261 | .chzn-container .chzn-results .highlighted em { 262 | background: transparent; 263 | } 264 | .chzn-container .chzn-results .no-results { 265 | background: #f4f4f4; 266 | display: list-item; 267 | } 268 | .chzn-container .chzn-results .group-result { 269 | cursor: default; 270 | color: #999; 271 | font-weight: bold; 272 | } 273 | .chzn-container .chzn-results .group-option { 274 | padding-left: 15px; 275 | } 276 | .chzn-container-multi .chzn-drop .result-selected { 277 | display: none; 278 | } 279 | .chzn-container .chzn-results-scroll { 280 | background: white; 281 | margin: 0px 4px; 282 | position: absolute; 283 | text-align: center; 284 | width: 321px; /* This should by dynamic with js */ 285 | z-index: 1; 286 | } 287 | .chzn-container .chzn-results-scroll span { 288 | display: inline-block; 289 | height: 17px; 290 | text-indent: -5000px; 291 | width: 9px; 292 | } 293 | .chzn-container .chzn-results-scroll-down { 294 | bottom: 0; 295 | } 296 | .chzn-container .chzn-results-scroll-down span { 297 | background: url('chosen-sprite.png') no-repeat -4px -3px; 298 | } 299 | .chzn-container .chzn-results-scroll-up span { 300 | background: url('chosen-sprite.png') no-repeat -22px -3px; 301 | } 302 | /* @end */ 303 | 304 | /* @group Active */ 305 | .chzn-container-active .chzn-single { 306 | -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); 307 | -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); 308 | -o-box-shadow : 0 0 5px rgba(0,0,0,.3); 309 | box-shadow : 0 0 5px rgba(0,0,0,.3); 310 | border: 1px solid #5897fb; 311 | } 312 | .chzn-container-active .chzn-single-with-drop { 313 | border: 1px solid #aaa; 314 | -webkit-box-shadow: 0 1px 0 #fff inset; 315 | -moz-box-shadow : 0 1px 0 #fff inset; 316 | -o-box-shadow : 0 1px 0 #fff inset; 317 | box-shadow : 0 1px 0 #fff inset; 318 | background-color: #eee; 319 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.2, white), color-stop(0.8, #eeeeee)); 320 | background-image: -webkit-linear-gradient(center bottom, white 20%, #eeeeee 80%); 321 | background-image: -moz-linear-gradient(center bottom, white 20%, #eeeeee 80%); 322 | background-image: -o-linear-gradient(bottom, white 20%, #eeeeee 80%); 323 | background-image: -ms-linear-gradient(top, #ffffff 20%,#eeeeee 80%); 324 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); 325 | background-image: linear-gradient(top, #ffffff 20%,#eeeeee 80%); 326 | -webkit-border-bottom-left-radius : 0; 327 | -webkit-border-bottom-right-radius: 0; 328 | -moz-border-radius-bottomleft : 0; 329 | -moz-border-radius-bottomright: 0; 330 | border-bottom-left-radius : 0; 331 | border-bottom-right-radius: 0; 332 | } 333 | .chzn-container-active .chzn-single-with-drop div { 334 | background: transparent; 335 | border-left: none; 336 | } 337 | .chzn-container-active .chzn-single-with-drop div b { 338 | background-position: -18px 1px; 339 | } 340 | .chzn-container-active .chzn-choices { 341 | -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); 342 | -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); 343 | -o-box-shadow : 0 0 5px rgba(0,0,0,.3); 344 | box-shadow : 0 0 5px rgba(0,0,0,.3); 345 | border: 1px solid #5897fb; 346 | } 347 | .chzn-container-active .chzn-choices .search-field input { 348 | color: #111 !important; 349 | } 350 | /* @end */ 351 | 352 | /* @group Disabled Support */ 353 | .chzn-disabled { 354 | cursor: default; 355 | opacity:0.5 !important; 356 | } 357 | .chzn-disabled .chzn-single { 358 | cursor: default; 359 | } 360 | .chzn-disabled .chzn-choices .search-choice .search-choice-close { 361 | cursor: default; 362 | } 363 | 364 | /* @group Right to Left */ 365 | .chzn-rtl { direction:rtl;text-align: right; } 366 | .chzn-rtl .chzn-single { padding-left: 0; padding-right: 8px; } 367 | .chzn-rtl .chzn-single span { margin-left: 26px; margin-right: 0; } 368 | 369 | .chzn-rtl .chzn-single div { left: 3px; right: auto; } 370 | .chzn-rtl .chzn-single abbr { 371 | left: 26px; 372 | right: auto; 373 | } 374 | .chzn-rtl .chzn-choices li { float: right; } 375 | .chzn-rtl .chzn-choices .search-choice { padding: 3px 5px 3px 19px; margin: 3px 5px 3px 0; } 376 | .chzn-rtl .chzn-choices .search-choice .search-choice-close { left: 4px; right: auto; background-position: right top;} 377 | .chzn-rtl.chzn-container-single .chzn-results { margin-left: 4px; margin-right: 0; padding-left: 0; padding-right: 4px; } 378 | .chzn-rtl .chzn-results .group-option { padding-left: 0; padding-right: 20px; } 379 | .chzn-rtl.chzn-container-active .chzn-single-with-drop div { border-right: none; } 380 | .chzn-rtl .chzn-search input { 381 | background: url('chosen-sprite.png') no-repeat -38px -22px, #ffffff; 382 | background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); 383 | background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); 384 | background: url('chosen-sprite.png') no-repeat -38px -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); 385 | background: url('chosen-sprite.png') no-repeat -38px -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); 386 | background: url('chosen-sprite.png') no-repeat -38px -22px, -ms-linear-gradient(top, #ffffff 85%,#eeeeee 99%); 387 | background: url('chosen-sprite.png') no-repeat -38px -22px, linear-gradient(top, #ffffff 85%,#eeeeee 99%); 388 | padding: 4px 5px 4px 20px; 389 | } 390 | /* @end */ 391 | -------------------------------------------------------------------------------- /resources/public/css/cmtn.css: -------------------------------------------------------------------------------- 1 | .cm-s-cmtn { background: #1d1f21; color: #c5c8c6} 2 | .cm-s-cmtn div.CodeMirror-selected { background: #373b41 !important; } 3 | .cm-s-cmtn .CodeMirror-gutters { 4 | background: #1d1f21; 5 | border-right: 1px solid #585858; 6 | color: gray; 7 | } 8 | .cm-s-cmtn .CodeMirror-cursor { border-left: 1px solid white !important; } 9 | .cm-s-cmtn span.cm-comment, .cm-s-cmtn span.cm-meta { color: #969896; } 10 | .cm-s-cmtn span.cm-atom, .cm-s-cmtn span.cm-number { color: #c5c8c6; } 11 | .cm-s-cmtn span.cm-property, .cm-s-cmtn span.cm-attribute, .cm-s-cmtn span.cm-preamble { color: #8abeb7 } 12 | .cm-s-cmtn span.cm-string, .cm-s-cmtn span.cm-atom, .cm-s-cmtn span.cm-plus { color: #b5bd68 } 13 | .cm-s-cmtn span.cm-keyword, .cm-s-cmtn span.cm-script { color: #b294bb; } 14 | .cm-s-cmtn span.cm-builtin, .cm-s-cmtn span.cm-minus, .cm-s-cmtn span.cm-section { color: #cc6666 } 15 | .cm-s-cmtn span.cm-variable,.cm-s-cmtn span.cm-variable-2, .cm-s-cmtn span.cm-variable-3, .cm-s-cmtn span.cm-tag, .cm-s-cmtn span.cm-rangeinfo, .cm-s-cmtn span.cm-macro { color: #81a2be } 16 | .cm-s-cmtn span.cm-special { color: #f0c674; } 17 | -------------------------------------------------------------------------------- /resources/public/css/embed.css: -------------------------------------------------------------------------------- 1 | .refheap { 2 | font-family: 'Open Sans', sans-serif; 3 | color: #DDD; 4 | } 5 | 6 | .refheap div.markdown { 7 | padding: 8px; 8 | } 9 | 10 | .refheap a { 11 | color: #A2B943; 12 | text-decoration: none; 13 | } 14 | 15 | .refheap pre.md-code { 16 | width: 700px; 17 | overflow: auto; 18 | border: solid #2E2E2E 3px; 19 | padding: 8px; 20 | } 21 | 22 | .refheap pre,code { 23 | font-family: 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 24 | line-height: 1.4em; 25 | font-size: 12px; 26 | } 27 | 28 | .refheap code { 29 | color: #A786D8; 30 | } 31 | 32 | .linenos div { 33 | color: gray; 34 | margin-right: 10px; 35 | } 36 | .linenos a { 37 | color: gray; 38 | text-decoration: none; 39 | } 40 | .refheap .hll { background-color: #373b41 } 41 | .refheap { background: #1d1f21; color: #c5c8c6 } 42 | .refheap .c { color: #969896 } /* Comment */ 43 | .refheap .k { color: #b294bb } /* Keyword */ 44 | .refheap .cm { color: #969896 } /* Comment.Multiline */ 45 | .refheap .cp { color: #969896 } /* Comment.Preproc */ 46 | .refheap .c1 { color: #969896 } /* Comment.Single */ 47 | .refheap .cs { color: #969896 } /* Comment.Special */ 48 | .refheap .gd { color: #cc6666 } /* Generic.Deleted */ 49 | .refheap .gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */ 50 | .refheap .gi { color: #b5bd68 } /* Generic.Inserted */ 51 | .refheap .gp { color: #969896; font-weight: bold } /* Generic.Prompt */ 52 | .refheap .gu { color: #8abeb7; font-weight: bold } /* Generic.Subheading */ 53 | .refheap .kc { color: #b294bb } /* Keyword.Constant */ 54 | .refheap .kd { color: #b294bb } /* Keyword.Declaration */ 55 | .refheap .kn { color: #b294bb } /* Keyword.Namespace */ 56 | .refheap .kp { color: #b294bb } /* Keyword.Pseudo */ 57 | .refheap .kr { color: #b294bb } /* Keyword.Reserved */ 58 | .refheap .kt { color: #f0c674 } /* Keyword.Type */ 59 | .refheap .s { color: #b5bd68 } /* Literal.String */ 60 | .refheap .nb { color: #cc6666 } /* Name.Builtin */ 61 | .refheap .nc { color: #f0c674 } /* Name.Class */ 62 | .refheap .no { color: #b5bd68 } /* Name.Constant */ 63 | .refheap .nd { color: #8abeb7 } /* Name.Decorator */ 64 | .refheap .ne { color: #cc6666 } /* Name.Exception */ 65 | .refheap .nf { color: #81a2be } /* Name.Function */ 66 | .refheap .nn { color: #f0c674 } /* Name.Namespace */ 67 | .refheap .nt { color: #81a2be } /* Name.Tag */ 68 | .refheap .w { color: #c5c8c6 } /* Text.Whitespace */ 69 | .refheap .sb { color: #b5bd68 } /* Literal.String.Backtick */ 70 | .refheap .sc { color: #c5c8c6 } /* Literal.String.Char */ 71 | .refheap .sd { color: #b5bd68 } /* Literal.String.Doc */ 72 | .refheap .s2 { color: #b5bd68 } /* Literal.String.Double */ 73 | .refheap .se { color: #b5bd68 } /* Literal.String.Escape */ 74 | .refheap .sh { color: #b5bd68 } /* Literal.String.Heredoc */ 75 | .refheap .si { color: #b5bd68 } /* Literal.String.Interpol */ 76 | .refheap .sx { color: #b5bd68 } /* Literal.String.Other */ 77 | .refheap .sr { color: #b5bd68 } /* Literal.String.Regex */ 78 | .refheap .s1 { color: #b5bd68 } /* Literal.String.Single */ 79 | .refheap .ss { color: #b5bd68 } /* Literal.String.Symbol */ 80 | .refheap .bp { color: #cc6666 } /* Name.Builtin.Pseudo */ 81 | .refheap .vi { color: #cc6666 } /* Name.Variable.Instance */ 82 | 83 | div.refheap { 84 | overflow: auto; 85 | } 86 | 87 | div#refh-12 { 88 | width: 30%; 89 | height: 40%; 90 | } 91 | 92 | .hide-lines td.linenos { 93 | display: none 94 | } 95 | 96 | .hide-lines div.highlight { 97 | margin: 8px 0 8px 8px; 98 | } -------------------------------------------------------------------------------- /resources/public/css/refheap.css: -------------------------------------------------------------------------------- 1 | .spacedlist ul { 2 | list-style-type: none; 3 | } 4 | 5 | div#site-container { 6 | margin: 0 auto; 7 | max-width: 1280px; 8 | min-width: 775px; 9 | width: 100%; 10 | overflow: auto; 11 | background-color: #2E2E2E; 12 | } 13 | 14 | body { 15 | background-color: #2E2E2E; 16 | margin: 0; 17 | font-family: 'Open Sans', sans-serif; 18 | color: #DDD; 19 | padding: 20px 50px 0; 20 | } 21 | 22 | body#fullscreen { 23 | background-color: #202020; 24 | padding: 0; 25 | } 26 | 27 | #fullscreen div { 28 | border: 0; 29 | overflow-x: visible; 30 | } 31 | 32 | a { 33 | color: #A2B943; 34 | text-decoration: none; 35 | } 36 | 37 | div#header { 38 | padding: 10px 0px 10px 15px; 39 | overflow: hidden; 40 | min-width: 700px; 41 | } 42 | 43 | a#site { 44 | color: #FFE93B; 45 | font-size: 33px; 46 | float: left; 47 | margin-right: 40px; 48 | text-decoration: none; 49 | } 50 | 51 | a#site:active { text-decoration: none; } 52 | 53 | div.headerlinks { 54 | margin-top: 10px; 55 | padding-right: 20px; 56 | float: right; 57 | } 58 | 59 | .headerlinks #signin { 60 | margin-top: 3px; 61 | } 62 | 63 | .headerlinks a { 64 | font-size: 20px; 65 | text-decoration: none; 66 | } 67 | 68 | div#useri { 69 | float: right; 70 | } 71 | 72 | a#userbutton { 73 | font-weight: bold; 74 | margin-right: 7px; 75 | } 76 | 77 | div#user { 78 | padding-top: 15px; 79 | } 80 | 81 | #user div { 82 | font-size: 13px; 83 | } 84 | 85 | a#logout { 86 | margin-left: 7px; 87 | } 88 | 89 | .imgbutton { 90 | cursor: pointer; 91 | } 92 | 93 | div#content { 94 | width: 100%; 95 | } 96 | 97 | div#container { 98 | padding: 6px 12px 12px 12px; 99 | background-color: #434E48; 100 | width: initial; 101 | border-radius: 5px; 102 | } 103 | 104 | div#main-container { 105 | clear: both; 106 | float: left; 107 | width: 100%; 108 | } 109 | 110 | div#paste-container { 111 | background: transparent; 112 | overflow: hidden; 113 | border: none; 114 | } 115 | 116 | .CodeMirror { 117 | width: 100%; 118 | clear: both; 119 | height: 510px; 120 | border: 2px solid #2e2e2e; 121 | border-radius: 3px; 122 | line-height: 1.1em; 123 | } 124 | 125 | div#paste-header { 126 | margin-left: 100%; 127 | float: right; 128 | overflow: visible; 129 | width: 400px; 130 | padding-bottom: 3px; 131 | } 132 | 133 | div#paste-container textarea { 134 | float: left; 135 | clear: left; 136 | width: 100%; 137 | margin: 0px; 138 | background-color: #DDD; 139 | height: 510px; 140 | /* Dear world: stop using fucking prefixes. */ 141 | -moz-box-sizing: border-box; /* Render properly on Firefox */ 142 | -ms-box-sizing: border-box; /* Look at me, all tryin' to support IE8 and such. */ 143 | -webkit-box-sizing: border-box; /* Render properly on popular Android browsers. */ 144 | border: border-box; 145 | font-family: Menlo, Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 146 | } 147 | 148 | div#paste-header input[type="submit"] { 149 | -webkit-appearance: default-button; 150 | cursor: pointer; 151 | font-size: 15px; 152 | padding: 3px 10px; 153 | margin: 0 !important; 154 | border: 1.5px solid #2E2E2E; 155 | background-color: #cfcfcf; 156 | color: #2E2E2E; 157 | border-radius: 5px; 158 | float: right; 159 | } 160 | 161 | div#paste-header input[type="checkbox"]{ 162 | margin-left: 15px; 163 | } 164 | 165 | div#paste-header label { 166 | padding-top: 1px; 167 | margin-left: 5px; 168 | font-size: 15px; 169 | } 170 | 171 | div#paste-header select { 172 | float: left; 173 | font-size: 14px; 174 | background: #CCC; 175 | margin-top: 2px; 176 | width: 150px; 177 | border: 2px solid #2E2E2E; 178 | border-image: initial; 179 | height: 32px; 180 | padding: 4px; 181 | color: #2E2E2E; 182 | } 183 | 184 | div#language_chzn { 185 | color: #2E2E2E; 186 | font-size: 14px; 187 | background: #CCC; 188 | margin: 0px 2px; 189 | border-radius: 5px; 190 | } 191 | 192 | div#footer { 193 | width: initial; 194 | color: #A2B943; 195 | font-size: 13px; 196 | } 197 | 198 | .centered { 199 | width: 100%; 200 | text-align: center; 201 | font-size: 10px; 202 | } 203 | 204 | .header { 205 | text-align: center; 206 | font-weight: bold; 207 | font-size: 20px; 208 | } 209 | 210 | #footer a { 211 | text-decoration: underline; 212 | } 213 | 214 | div.written { 215 | padding: 20px 150px; 216 | } 217 | 218 | .written a { 219 | font-weight: bold; 220 | } 221 | 222 | div.syntax { 223 | border: 2px solid #2e2e2e; 224 | overflow-x: auto; 225 | border-radius: 4px; 226 | } 227 | 228 | div.markdown { 229 | padding: 0 12px 0 12px; 230 | } 231 | 232 | .markdown li { 233 | margin: 5px 0 5px 0; 234 | } 235 | 236 | div.syntax div.more { 237 | position: relative; 238 | top: -10px; 239 | padding-left: 3px; 240 | font-size: 12px; 241 | } 242 | 243 | div.more a { 244 | font-weight: bold; 245 | } 246 | 247 | div#pasteinfo { 248 | margin-bottom: 4px; 249 | font-size: 11px; 250 | } 251 | 252 | .spacedlist { 253 | padding: 0; 254 | margin: 0; 255 | } 256 | 257 | .spacedlist li { 258 | float: left; 259 | display: inline; 260 | } 261 | 262 | #infolist li { 263 | padding: 0 10px 0 10px; 264 | border-right: solid 1px black; 265 | } 266 | 267 | #infolist { 268 | float: left; 269 | } 270 | 271 | .private { 272 | color: #22aa22; 273 | margin-right: 5px; 274 | } 275 | 276 | li#last { 277 | border-right: none; 278 | } 279 | 280 | div.floater { 281 | float: left; 282 | width: 100%; 283 | overflow: hidden; 284 | } 285 | 286 | .linenos div { 287 | color: gray; 288 | margin-right: 10px; 289 | } 290 | 291 | .linenodiv { 292 | padding-left: 3px; 293 | } 294 | 295 | .more { 296 | padding-left: 3px; 297 | } 298 | 299 | .linenodiv a { 300 | text-decoration: none; 301 | color: gray; 302 | } 303 | 304 | div#login { 305 | margin: auto; 306 | width: 525px; 307 | text-align: center; 308 | } 309 | 310 | #starting { 311 | float: left; 312 | border-right: 2px solid #585858; 313 | margin-right: 10px; 314 | } 315 | 316 | .error { 317 | color: #F70000; 318 | font-weight: bold; 319 | text-align: center; 320 | } 321 | 322 | a#newer { 323 | margin-right: 10px; 324 | } 325 | 326 | #starting li { 327 | margin-right: 10px; 328 | padding-right: 10px; 329 | } 330 | 331 | li#last { 332 | margin-right: 10px; 333 | padding-right: 0; 334 | } 335 | 336 | .pagebutton { 337 | font-size: 15px; 338 | padding: 5px 10px; 339 | border: 2px solid #2E2E2E; 340 | background-color: #CFCFCF; 341 | color: #2E2E2E; 342 | border-radius: 5px; 343 | } 344 | 345 | div#edit { 346 | float: right; 347 | padding: 348 | } 349 | 350 | #edit a { 351 | padding-right: 7px; 352 | } 353 | 354 | #edit input[type="submit"] { 355 | background: none; 356 | border: none; 357 | color: #A2B943; 358 | margin: 0; 359 | padding: 0; 360 | cursor: pointer; 361 | } 362 | 363 | #edit form { 364 | display: inline; 365 | } 366 | 367 | .evil { 368 | color: #CF0000; 369 | } 370 | 371 | div#preview-container { 372 | padding-top: 15px; 373 | } 374 | 375 | div.preview-header { 376 | font-size: 12px; 377 | margin: 0 1px; 378 | } 379 | 380 | div.preview-header div.right { 381 | float: right; 382 | } 383 | 384 | div#token { 385 | text-align: center; 386 | } 387 | 388 | code#tokentext { 389 | margin-right: 10px; 390 | background-color: #DDD; 391 | color: black; 392 | padding: 4px; 393 | border-radius: 5px; 394 | } 395 | 396 | button#gentoken { 397 | height: 24px; 398 | border-radius: 5px; 399 | } 400 | 401 | .clearfix:after { 402 | visibility: hidden; 403 | display: block; 404 | font-size: 0; 405 | content: " "; 406 | clear: both; 407 | height: 0; 408 | } 409 | 410 | * html .clearfix { zoom: 1; } /* IE6 */ 411 | *:first-child+html .clearfix { zoom: 1; } /* IE7 */ 412 | 413 | pre#rawDisplay { 414 | background-color: #DDD; 415 | border: double 4px black; 416 | color: black; 417 | } 418 | 419 | span#copyTextPrompt { 420 | position: absolute; 421 | right: 0px; 422 | top: 0px; 423 | font-size: large; 424 | font-weight: bold; 425 | color: lightgray; 426 | } 427 | 428 | input#private { 429 | display: none; 430 | } 431 | 432 | input#private + label { 433 | cursor: pointer; 434 | line-height: 1.5em; 435 | display: inline-block; 436 | vertical-align: top; 437 | } 438 | 439 | div#private-toggle { 440 | background-color: #333; 441 | border-radius: 8px; 442 | width: 100px; 443 | } 444 | 445 | #private-toggle, 446 | #private-toggle div, 447 | #private-toggle span { 448 | display: inline-block; 449 | vertical-align: top; 450 | text-align: center; 451 | } 452 | 453 | #private-toggle span { 454 | width: 40px; 455 | background-color: transparent; 456 | position: relative; 457 | z-index: 2; 458 | } 459 | 460 | #private-toggle span:first { 461 | border-right: 1px solid #888; 462 | } 463 | 464 | #private-toggle div { 465 | -moz-transition: all 250ms; 466 | -ms-transition: all 250ms; 467 | -o-transition: all 250ms; 468 | -webkit-transition: all 250ms; 469 | background-color: darkred; 470 | border-radius: 8px 0px 0px 8px; 471 | box-shadow: 0px 0px 4px red; 472 | height: 1.5em; 473 | position: absolute; 474 | transition: all 250ms; 475 | width: 45px; 476 | z-index: 1; 477 | margin-left: -6px; 478 | } 479 | 480 | input#private:checked + label > div > div { 481 | background-color: darkgreen; 482 | border-radius: 0px 8px 8px 0px; 483 | box-shadow: 0px 0px 4px lightgreen; 484 | margin-left: 45px; 485 | } 486 | 487 | div#help-dialog { 488 | display: none; 489 | background-color: #1D1F21; 490 | border-radius: 5px; 491 | border: solid 2px #2E2E2E; 492 | box-shadow: 10px 10px 10px black; 493 | height: 320px; 494 | margin-top: -320px; 495 | width: 350px; 496 | margin-left: -350px; 497 | font-size: 16px; 498 | position: absolute; 499 | z-index: 5; 500 | } 501 | 502 | div#help-dialog > div { 503 | padding-left: 20px; 504 | } 505 | 506 | div#help-dialog > div > ul { 507 | margin: 0px; 508 | padding: 0px; 509 | } 510 | 511 | div#help-dialog > h3 { 512 | background-color: #434E48; 513 | border-radius: 5px; 514 | color: #A2B943; 515 | margin-top: 2px; 516 | margin-bottom: 0px; 517 | margin-left: 2px; 518 | margin-right: 2px; 519 | padding: 0px; 520 | text-align: center; 521 | font-size: 16px; 522 | height: 28px; 523 | line-height: 28px; 524 | } 525 | 526 | div#help-dialog > h3 > span { 527 | background-color: #1D1F21; 528 | border-radius: 8px; 529 | border: solid 1px #2E2E2E; 530 | cursor: pointer; 531 | display: inline-block; 532 | float: right; 533 | font-size: 14px; 534 | line-height: 20px; 535 | font-variant: small-caps; 536 | margin: 4px; 537 | padding-left: 2px; 538 | padding-right: 2px; 539 | text-align: center; 540 | } 541 | 542 | div#help-dialog > h3 > span:hover { 543 | background-color: #2E2E2E; 544 | text-shadow: 0px 0px 4px lightgreen; 545 | } 546 | 547 | span#help-bubble:active { 548 | box-shadow: -1px -1px 3px black; 549 | border-color: #767676; 550 | } 551 | 552 | div#help-bubble-tray { 553 | background-color: #434E48; 554 | border-top-left-radius: 15px; 555 | border: solid 1px #2E2E2E; 556 | bottom: 0px; 557 | box-shadow: -1px -1px 5px #1D1D1D; 558 | position: fixed; 559 | height: 30px; 560 | right: 0px; 561 | } 562 | 563 | span#help-bubble:hover { 564 | border-color: #DDD; 565 | box-shadow: 1px 1px 3px black; 566 | } 567 | 568 | span#help-bubble { 569 | margin-bottom: 4px; 570 | margin-right: 4px; 571 | margin-top: 2px; 572 | margin-left: 2px; 573 | cursor: pointer; 574 | border: solid 2px #767676; 575 | display: block; 576 | border-radius: 15px; 577 | width: 23px; 578 | text-shadow: 0px 0px 2px black; 579 | text-align: center; 580 | font-size: 16px; 581 | font-weight: 900; 582 | background-color: #1AB8FF; 583 | background-image: linear-gradient(bottom, rgb(0,150,220) 15%, rgb(45,199,255) 81%); 584 | background-image: -o-linear-gradient(bottom, rgb(0,150,220) 15%, rgb(45,199,255) 81%); 585 | background-image: -moz-linear-gradient(bottom, rgb(0,150,220) 15%, rgb(45,199,255) 81%); 586 | background-image: -webkit-linear-gradient(bottom, rgb(0,150,220) 15%, rgb(45,199,255) 81%); 587 | background-image: -ms-linear-gradient(bottom, rgb(0,150,220) 15%, rgb(45,199,255) 81%); 588 | background-image: -webkit-gradient( 589 | linear, 590 | left bottom, 591 | left top, 592 | color-stop(0.15, rgb(0,150,220)), 593 | color-stop(0.81, rgb(45,199,255)) 594 | ); 595 | } 596 | 597 | li.help-subject { 598 | font-size: 16px; 599 | color: #DDD; 600 | padding-bottom: 16px; 601 | } 602 | 603 | li.help-title { 604 | color: #FFE93B; 605 | font-size: 14px; 606 | } 607 | 608 | li.help-line { 609 | font-size: 12px; 610 | } 611 | 612 | span.hotkey { 613 | font-size: 12px; 614 | color: #A2B943; 615 | display: inline-block; 616 | vertical-align: middle; 617 | width: 80px; 618 | } 619 | 620 | pre.md-code { 621 | width: 700px; 622 | overflow: auto; 623 | border: solid #2E2E2E 3px; 624 | padding: 8px; 625 | } 626 | 627 | pre,code { 628 | font-family: Menlo, Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 629 | line-height: 1.4em; 630 | font-size: 10pt; 631 | } 632 | 633 | code { 634 | color: #A786D8; 635 | } -------------------------------------------------------------------------------- /resources/public/css/tomorrow-night-bright.css: -------------------------------------------------------------------------------- 1 | pre { 2 | font-family: 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 3 | line-height: 1.4em; 4 | font-size: 12px; 5 | } 6 | .syntax .hll { background-color: #424242 } 7 | .syntax { background: #000000; color: #eaeaea } 8 | .syntax .c { color: #969896 } /* Comment */ 9 | .syntax .k { color: #c397d8 } /* Keyword */ 10 | .syntax .cm { color: #969896 } /* Comment.Multiline */ 11 | .syntax .cp { color: #969896 } /* Comment.Preproc */ 12 | .syntax .c1 { color: #969896 } /* Comment.Single */ 13 | .syntax .cs { color: #969896 } /* Comment.Special */ 14 | .syntax .gd { color: #d54e53 } /* Generic.Deleted */ 15 | .syntax .gh { color: #eaeaea; font-weight: bold } /* Generic.Heading */ 16 | .syntax .gi { color: #b9ca4a } /* Generic.Inserted */ 17 | .syntax .gp { color: #969896; font-weight: bold } /* Generic.Prompt */ 18 | .syntax .gu { color: #70c0b1; font-weight: bold } /* Generic.Subheading */ 19 | .syntax .kc { color: #c397d8 } /* Keyword.Constant */ 20 | .syntax .kd { color: #c397d8 } /* Keyword.Declaration */ 21 | .syntax .kn { color: #c397d8 } /* Keyword.Namespace */ 22 | .syntax .kp { color: #c397d8 } /* Keyword.Pseudo */ 23 | .syntax .kr { color: #c397d8 } /* Keyword.Reserved */ 24 | .syntax .kt { color: #e7c547 } /* Keyword.Type */ 25 | .syntax .s { color: #b9ca4a } /* Literal.String */ 26 | .syntax .nb { color: #d54e53 } /* Name.Builtin */ 27 | .syntax .nc { color: #e7c547 } /* Name.Class */ 28 | .syntax .no { color: #b9ca4a } /* Name.Constant */ 29 | .syntax .nd { color: #70c0b1 } /* Name.Decorator */ 30 | .syntax .ne { color: #d54e53 } /* Name.Exception */ 31 | .syntax .nf { color: #7aa6da } /* Name.Function */ 32 | .syntax .nn { color: #e7c547 } /* Name.Namespace */ 33 | .syntax .nt { color: #7aa6da } /* Name.Tag */ 34 | .syntax .w { color: #eaeaea } /* Text.Whitespace */ 35 | .syntax .sb { color: #b9ca4a } /* Literal.String.Backtick */ 36 | .syntax .sc { color: #eaeaea } /* Literal.String.Char */ 37 | .syntax .sd { color: #b9ca4a } /* Literal.String.Doc */ 38 | .syntax .s2 { color: #b9ca4a } /* Literal.String.Double */ 39 | .syntax .se { color: #b9ca4a } /* Literal.String.Escape */ 40 | .syntax .sh { color: #b9ca4a } /* Literal.String.Heredoc */ 41 | .syntax .si { color: #b9ca4a } /* Literal.String.Interpol */ 42 | .syntax .sx { color: #b9ca4a } /* Literal.String.Other */ 43 | .syntax .sr { color: #b9ca4a } /* Literal.String.Regex */ 44 | .syntax .s1 { color: #b9ca4a } /* Literal.String.Single */ 45 | .syntax .ss { color: #b9ca4a } /* Literal.String.Symbol */ 46 | .syntax .bp { color: #d54e53 } /* Name.Builtin.Pseudo */ 47 | .syntax .vi { color: #d54e53 } /* Name.Variable.Instance */ 48 | -------------------------------------------------------------------------------- /resources/public/css/tomorrow-night.css: -------------------------------------------------------------------------------- 1 | .syntax .hll { background-color: #373b41 } 2 | .syntax { background: #1d1f21; color: #c5c8c6 } 3 | .syntax .c { color: #969896 } /* Comment */ 4 | .syntax .k { color: #b294bb } /* Keyword */ 5 | .syntax .cm { color: #969896 } /* Comment.Multiline */ 6 | .syntax .cp { color: #b294bb } /* Comment.Preproc */ 7 | .syntax .c1 { color: #969896 } /* Comment.Single */ 8 | .syntax .cs { color: #969896 } /* Comment.Special */ 9 | .syntax .gd { color: #cc6666 } /* Generic.Deleted */ 10 | .syntax .gh { color: #f0c674; font-weight: bold } /* Generic.Heading */ 11 | .syntax .gi { color: #b5bd68 } /* Generic.Inserted */ 12 | .syntax .gp { color: #969896; font-weight: bold } /* Generic.Prompt */ 13 | .syntax .gu { color: #8abeb7; font-weight: bold } /* Generic.Subheading */ 14 | .syntax .kc { color: #b294bb } /* Keyword.Constant */ 15 | .syntax .kd { color: #b294bb } /* Keyword.Declaration */ 16 | .syntax .kn { color: #b294bb } /* Keyword.Namespace */ 17 | .syntax .kp { color: #b294bb } /* Keyword.Pseudo */ 18 | .syntax .kr { color: #b294bb } /* Keyword.Reserved */ 19 | .syntax .kt { color: #f0c674 } /* Keyword.Type */ 20 | .syntax .s { color: #b5bd68 } /* Literal.String */ 21 | .syntax .nb { color: #cc6666 } /* Name.Builtin */ 22 | .syntax .nc { color: #f0c674 } /* Name.Class */ 23 | .syntax .no { color: #b5bd68 } /* Name.Constant */ 24 | .syntax .nd { color: #81a2be } /* Name.Decorator */ 25 | .syntax .ne { color: #cc6666 } /* Name.Exception */ 26 | .syntax .nf { color: #81a2be } /* Name.Function */ 27 | .syntax .nn { color: #f0c674 } /* Name.Namespace */ 28 | .syntax .nt { color: #81a2be } /* Name.Tag */ 29 | .syntax .w { color: #c5c8c6 } /* Text.Whitespace */ 30 | .syntax .sb { color: #b5bd68 } /* Literal.String.Backt2ick */ 31 | .syntax .sc { color: #c5c8c6 } /* Literal.String.Char */ 32 | .syntax .sd { color: #b5bd68 } /* Literal.String.Doc */ 33 | .syntax .s2 { color: #b5bd68 } /* Literal.String.Double */ 34 | .syntax .se { color: #b5bd68 } /* Literal.String.Escape */ 35 | .syntax .sh { color: #b5bd68 } /* Literal.String.Heredoc */ 36 | .syntax .si { color: #b5bd68 } /* Literal.String.Interpol */ 37 | .syntax .sx { color: #b5bd68 } /* Literal.String.Other */ 38 | .syntax .sr { color: #b5bd68 } /* Literal.String.Regex */ 39 | .syntax .s1 { color: #b5bd68 } /* Literal.String.Single */ 40 | .syntax .ss { color: #b5bd68 } /* Literal.String.Symbol */ 41 | .syntax .bp { color: #cc6666 } /* Name.Builtin.Pseudo */ 42 | .syntax .vi { color: #cc6666 } /* Name.Variable.Instance */ 43 | -------------------------------------------------------------------------------- /resources/public/img/browserid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raynes/refheap/ad85097172a6d11dd9edaa97e2f2eb6d3296e94f/resources/public/img/browserid.png -------------------------------------------------------------------------------- /resources/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raynes/refheap/ad85097172a6d11dd9edaa97e2f2eb6d3296e94f/resources/public/img/favicon.ico -------------------------------------------------------------------------------- /resources/public/js/api.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $("#gentoken").click(function(event) { 3 | $.get('/token/generate', 4 | function(data) { $("#tokentext").html(data); }); 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /resources/public/js/chosen.jquery.min.js: -------------------------------------------------------------------------------- 1 | // Chosen, a Select Box Enhancer for jQuery and Protoype 2 | // by Patrick Filler for Harvest, http://getharvest.com 3 | // 4 | // Version 0.9.7 5 | // Full source at https://github.com/harvesthq/chosen 6 | // Copyright (c) 2011 Harvest http://getharvest.com 7 | 8 | // MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md 9 | // This file is generated by `cake build`, do not edit it by hand. 10 | ((function(){var a;a=function(){function a(){this.options_index=0,this.parsed=[]}return a.prototype.add_node=function(a){return a.nodeName==="OPTGROUP"?this.add_group(a):this.add_option(a)},a.prototype.add_group=function(a){var b,c,d,e,f,g;b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:a.label,children:0,disabled:a.disabled}),f=a.childNodes,g=[];for(d=0,e=f.length;d"+a.html+"")},a.prototype.results_update_field=function(){return this.result_clear_highlight(),this.result_single_selected=null,this.results_build()},a.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},a.prototype.results_search=function(a){return this.results_showing?this.winnow_results():this.results_show()},a.prototype.keyup_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale();switch(b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:a.preventDefault();if(this.results_showing)return this.result_select(a);break;case 27:return this.results_showing&&this.results_hide(),!0;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},a.prototype.generate_field_id=function(){var a;return a=this.generate_random_id(),this.form_field.id=a,a},a.prototype.generate_random_char=function(){var a,b,c;return a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ",c=Math.floor(Math.random()*a.length),b=a.substring(c,c+1)},a}(),b.AbstractChosen=a}.call(this),function(){var a,b,c,d,e=Object.prototype.hasOwnProperty,f=function(a,b){function d(){this.constructor=a}for(var c in b)e.call(b,c)&&(a[c]=b[c]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a};d=this,a=jQuery,a.fn.extend({chosen:function(c){return!a.browser.msie||a.browser.version!=="6.0"&&a.browser.version!=="7.0"?a(this).each(function(d){if(!a(this).hasClass("chzn-done"))return new b(this,c)}):this}}),b=function(b){function e(){e.__super__.constructor.apply(this,arguments)}return f(e,b),e.prototype.setup=function(){return this.form_field_jq=a(this.form_field),this.is_rtl=this.form_field_jq.hasClass("chzn-rtl")},e.prototype.finish_setup=function(){return this.form_field_jq.addClass("chzn-done")},e.prototype.set_up_html=function(){var b,d,e,f;return this.container_id=this.form_field.id.length?this.form_field.id.replace(/(:|\.)/g,"_"):this.generate_field_id(),this.container_id+="_chzn",this.f_width=this.form_field_jq.outerWidth(),this.default_text=this.form_field_jq.data("placeholder")?this.form_field_jq.data("placeholder"):this.default_text_default,b=a("
",{id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px;"}),this.is_multiple?b.html('
    '):b.html(''+this.default_text+'
      '),this.form_field_jq.hide().after(b),this.container=a("#"+this.container_id),this.container.addClass("chzn-container-"+(this.is_multiple?"multi":"single")),this.dropdown=this.container.find("div.chzn-drop").first(),d=this.container.height(),e=this.f_width-c(this.dropdown),this.dropdown.css({width:e+"px",top:d+"px"}),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chzn-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chzn-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chzn-search").first(),this.selected_item=this.container.find(".chzn-single").first(),f=e-c(this.search_container)-c(this.search_field),this.search_field.css({width:f+"px"})),this.results_build(),this.set_tab_index(),this.form_field_jq.trigger("liszt:ready",{chosen:this})},e.prototype.register_observers=function(){var a=this;return this.container.mousedown(function(b){return a.container_mousedown(b)}),this.container.mouseup(function(b){return a.container_mouseup(b)}),this.container.mouseenter(function(b){return a.mouse_enter(b)}),this.container.mouseleave(function(b){return a.mouse_leave(b)}),this.search_results.mouseup(function(b){return a.search_results_mouseup(b)}),this.search_results.mouseover(function(b){return a.search_results_mouseover(b)}),this.search_results.mouseout(function(b){return a.search_results_mouseout(b)}),this.form_field_jq.bind("liszt:updated",function(b){return a.results_update_field(b)}),this.search_field.blur(function(b){return a.input_blur(b)}),this.search_field.keyup(function(b){return a.keyup_checker(b)}),this.search_field.keydown(function(b){return a.keydown_checker(b)}),this.is_multiple?(this.search_choices.click(function(b){return a.choices_click(b)}),this.search_field.focus(function(b){return a.input_focus(b)})):this.container.click(function(a){return a.preventDefault()})},e.prototype.search_field_disabled=function(){this.is_disabled=this.form_field_jq[0].disabled;if(this.is_disabled)return this.container.addClass("chzn-disabled"),this.search_field[0].disabled=!0,this.is_multiple||this.selected_item.unbind("focus",this.activate_action),this.close_field();this.container.removeClass("chzn-disabled"),this.search_field[0].disabled=!1;if(!this.is_multiple)return this.selected_item.bind("focus",this.activate_action)},e.prototype.container_mousedown=function(b){var c;if(!this.is_disabled)return c=b!=null?a(b.target).hasClass("search-choice-close"):!1,b&&b.type==="mousedown"&&b.stopPropagation(),!this.pending_destroy_click&&!c?(this.active_field?!this.is_multiple&&b&&(a(b.target)[0]===this.selected_item[0]||a(b.target).parents("a.chzn-single").length)&&(b.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),a(document).click(this.click_test_action),this.results_show()),this.activate_field()):this.pending_destroy_click=!1},e.prototype.container_mouseup=function(a){if(a.target.nodeName==="ABBR")return this.results_reset(a)},e.prototype.blur_test=function(a){if(!this.active_field&&this.container.hasClass("chzn-container-active"))return this.close_field()},e.prototype.close_field=function(){return a(document).unbind("click",this.click_test_action),this.is_multiple||(this.selected_item.attr("tabindex",this.search_field.attr("tabindex")),this.search_field.attr("tabindex",-1)),this.active_field=!1,this.results_hide(),this.container.removeClass("chzn-container-active"),this.winnow_results_clear(),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},e.prototype.activate_field=function(){return!this.is_multiple&&!this.active_field&&(this.search_field.attr("tabindex",this.selected_item.attr("tabindex")),this.selected_item.attr("tabindex",-1)),this.container.addClass("chzn-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},e.prototype.test_active_click=function(b){return a(b.target).parents("#"+this.container_id).length?this.active_field=!0:this.close_field()},e.prototype.results_build=function(){var a,b,c,e,f;this.parsing=!0,this.results_data=d.SelectParser.select_to_array(this.form_field),this.is_multiple&&this.choices>0?(this.search_choices.find("li.search-choice").remove(),this.choices=0):this.is_multiple||(this.selected_item.find("span").text(this.default_text),this.form_field.options.length<=this.disable_search_threshold?this.container.addClass("chzn-container-single-nosearch"):this.container.removeClass("chzn-container-single-nosearch")),a="",f=this.results_data;for(c=0,e=f.length;c'+a("
      ").text(b.label).html()+"")},e.prototype.result_do_highlight=function(a){var b,c,d,e,f;if(a.length){this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClass("highlighted"),d=parseInt(this.search_results.css("maxHeight"),10),f=this.search_results.scrollTop(),e=d+f,c=this.result_highlight.position().top+this.search_results.scrollTop(),b=c+this.result_highlight.outerHeight();if(b>=e)return this.search_results.scrollTop(b-d>0?b-d:0);if(c'+b.html+''),d=a("#"+c).find("a").first(),d.click(function(a){return e.choice_destroy_link_click(a)})},e.prototype.choice_destroy_link_click=function(b){return b.preventDefault(),this.is_disabled?b.stopPropagation:(this.pending_destroy_click=!0,this.choice_destroy(a(b.target)))},e.prototype.choice_destroy=function(a){return this.choices-=1,this.show_search_field_default(),this.is_multiple&&this.choices>0&&this.search_field.val().length<1&&this.results_hide(),this.result_deselect(a.attr("rel")),a.parents("li").first().remove()},e.prototype.results_reset=function(b){this.form_field.options[0].selected=!0,this.selected_item.find("span").text(this.default_text),this.show_search_field_default(),a(b.target).remove(),this.form_field_jq.trigger("change");if(this.active_field)return this.results_hide()},e.prototype.result_select=function(a){var b,c,d,e;if(this.result_highlight)return b=this.result_highlight,c=b.attr("id"),this.result_clear_highlight(),this.is_multiple?this.result_deactivate(b):(this.search_results.find(".result-selected").removeClass("result-selected"),this.result_single_selected=b),b.addClass("result-selected"),e=c.substr(c.lastIndexOf("_")+1),d=this.results_data[e],d.selected=!0,this.form_field.options[d.options_index].selected=!0,this.is_multiple?this.choice_build(d):(this.selected_item.find("span").first().text(d.text),this.allow_single_deselect&&this.single_deselect_control_build()),(!a.metaKey||!this.is_multiple)&&this.results_hide(),this.search_field.val(""),this.form_field_jq.trigger("change"),this.search_field_scale()},e.prototype.result_activate=function(a){return a.addClass("active-result")},e.prototype.result_deactivate=function(a){return a.removeClass("active-result")},e.prototype.result_deselect=function(b){var c,d;return d=this.results_data[b],d.selected=!1,this.form_field.options[d.options_index].selected=!1,c=a("#"+this.container_id+"_o_"+b),c.removeClass("result-selected").addClass("active-result").show(),this.result_clear_highlight(),this.winnow_results(),this.form_field_jq.trigger("change"),this.search_field_scale()},e.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect&&this.selected_item.find("abbr").length<1)return this.selected_item.find("span").first().after('')},e.prototype.winnow_results=function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r;this.no_results_clear(),i=0,j=this.search_field.val()===this.default_text?"":a("
      ").text(a.trim(this.search_field.val())).html(),f=new RegExp("^"+j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),m=new RegExp(j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),r=this.results_data;for(n=0,p=r.length;n=0||c.html.indexOf("[")===0){e=c.html.replace(/\[|\]/g,"").split(" ");if(e.length)for(o=0,q=e.length;o"+c.html.substr(k+j.length),l=l.substr(0,k)+""+l.substr(k)):l=c.html,g.html(l),this.result_activate(g),c.group_array_index!=null&&a("#"+this.results_data[c.group_array_index].dom_id).css("display","list-item")):(this.result_highlight&&h===this.result_highlight.attr("id")&&this.result_clear_highlight(),this.result_deactivate(g))}}return i<1&&j.length?this.no_results(j):this.winnow_results_set_highlight()},e.prototype.winnow_results_clear=function(){var b,c,d,e,f;this.search_field.val(""),c=this.search_results.find("li"),f=[];for(d=0,e=c.length;d'+this.results_none_found+' ""'),c.find("span").first().html(b),this.search_results.append(c)},e.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},e.prototype.keydown_arrow=function(){var b,c;this.result_highlight?this.results_showing&&(c=this.result_highlight.nextAll("li.active-result").first(),c&&this.result_do_highlight(c)):(b=this.search_results.find("li.active-result").first(),b&&this.result_do_highlight(a(b)));if(!this.results_showing)return this.results_show()},e.prototype.keyup_arrow=function(){var a;if(!this.results_showing&&!this.is_multiple)return this.results_show();if(this.result_highlight)return a=this.result_highlight.prevAll("li.active-result"),a.length?this.result_do_highlight(a.first()):(this.choices>0&&this.results_hide(),this.result_clear_highlight())},e.prototype.keydown_backstroke=function(){return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(this.pending_backstroke=this.search_container.siblings("li.search-choice").last(),this.pending_backstroke.addClass("search-choice-focus"))},e.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},e.prototype.keydown_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale(),b!==8&&this.pending_backstroke&&this.clear_backstroke();switch(b){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:this.keydown_arrow()}},e.prototype.search_field_scale=function(){var b,c,d,e,f,g,h,i,j;if(this.is_multiple){d=0,h=0,f="position:absolute; left: -1000px; top: -1000px; display:none;",g=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(i=0,j=g.length;i",{style:f}),c.text(this.search_field.val()),a("body").append(c),h=c.width()+25,c.remove(),h>this.f_width-10&&(h=this.f_width-10),this.search_field.css({width:h+"px"}),b=this.container.height(),this.dropdown.css({top:b+"px"})}},e.prototype.generate_random_id=function(){var b;b="sel"+this.generate_random_char()+this.generate_random_char()+this.generate_random_char();while(a("#"+b).length>0)b+=this.generate_random_char();return b},e}(AbstractChosen),c=function(a){var b;return b=a.outerWidth()-a.width()},d.get_side_border_padding=c}.call(this) -------------------------------------------------------------------------------- /resources/public/js/create.js: -------------------------------------------------------------------------------- 1 | (function ( $, window ) { 2 | 3 | var refheap = refheap || {}; 4 | 5 | /** 6 | * Used to keep track of which modes have been loaded. 7 | */ 8 | refheap.loaded = {}; 9 | 10 | /** 11 | * List of available language modes. Some languages have other mode 12 | * dependencies, in this case the dependencies should be listed first 13 | * with the final mode being the mode that will be set on the editor. 14 | */ 15 | refheap.langs = 16 | { "C++" : ["clike"], 17 | "C" : ["clike"], 18 | "Java" : ["clike"], 19 | "Objective-C" : ["clike"], 20 | "Clojure" : ["clojure"], 21 | "Apricot" : ["clojure"], 22 | "CoffeeScript" : ["coffeescript"], 23 | "CSS" : ["css"], 24 | "Diff" : ["diff"], 25 | "Go" : ["go"], 26 | "Groovy" : ["groovy"], 27 | "Haskell" : ["haskell"], 28 | "Javascript" : ["javascript"], 29 | "Lua" : ["lua"], 30 | "Delphi" : ["pascal"], 31 | "Perl" : ["perl"], 32 | "PHP" : ["css", "javascript", "xml", "clike", "php"], 33 | "Java Properties" : ["properties"], 34 | "Python" : ["python"], 35 | "R" : ["r"], 36 | "Ruby" : ["ruby"], 37 | "Rust" : ["rust"], 38 | "Scheme" : ["scheme"], 39 | "Emacs Lisp" : ["scheme"], 40 | "Smalltalk" : ["smalltalk"], 41 | "Verilog" : ["verilog"], 42 | "XML" : ["xml"], 43 | "YAML" : ["yaml"], 44 | "HTML" : ["css", "xml", "javascript", "htmlmixed"], 45 | "MySQL" : ["mysql"], 46 | "OCaml" : ["ocaml"], 47 | "RPM Spec" : [{mode: "spec", path: "rpm/spec/spec"}]}; 48 | 49 | refheap.isString = function(obj) { 50 | return toString.call(obj) == '[object String]'; 51 | }; 52 | 53 | refheap.normalizeMode = function(mode) { 54 | if (refheap.isString(mode)) return {mode: mode, path: mode + '/' + mode}; 55 | else return mode; 56 | }; 57 | 58 | refheap.notLoaded = function(mode) { 59 | return !(mode in refheap.loaded); 60 | }; 61 | 62 | refheap.setMode = function(modes, editor) { 63 | var modes = $.map(modes, function(mode, index) { return refheap.normalizeMode(mode) }), 64 | notLoaded = $.grep(modes, refheap.notLoaded), 65 | promises = $.map(notLoaded, function(mode, index) { 66 | return $.getScript("/js/codemirror/mode/" + mode.path + ".js"); 67 | }); 68 | return $.when.apply($, promises).done(function() { 69 | $.each(notLoaded, function(mode, i) { 70 | refheap.loaded[mode] = true; 71 | }); 72 | editor.setOption("mode", modes[modes.length - 1].mode); 73 | }); 74 | }; 75 | 76 | /** 77 | * Setup the editor for the specified language. 78 | */ 79 | refheap.setupLang = function ( lang, editor ) { 80 | var modes = refheap.langs[lang]; 81 | if ( modes ) { 82 | refheap.setMode(modes, editor); 83 | } else { 84 | editor.setOption( "mode", null ); 85 | } 86 | }; 87 | 88 | /** 89 | * Set height of the code editor dynamically. 90 | */ 91 | refheap.setCodeHeight = function (editor) { 92 | var currentHeight = $( window ).height(); 93 | if ( currentHeight > 600 ) { 94 | $( ".CodeMirror" ).height( currentHeight - 200 ); 95 | editor.refresh(); 96 | } 97 | }; 98 | 99 | /** 100 | * Toggles the private checkbox. 101 | */ 102 | refheap.togglePrivate = function () { 103 | $( "#private" ).attr( "checked", !$(" #private" ).attr( "checked" ) ); 104 | }; 105 | 106 | /** 107 | * Submits the form. 108 | */ 109 | refheap.paste = function () { 110 | $( "form[name=paste]" ).submit(); 111 | }; 112 | 113 | 114 | $( function () { 115 | $( "select#language" ).chosen(); 116 | 117 | // Setup hotkeys 118 | 119 | var editor = CodeMirror.fromTextArea( $('#paste')[0], { lineNumbers: true, 120 | theme: 'cmtn'} ), 121 | setLang = function () { 122 | refheap.setupLang( $("#language option:selected").text(), editor ); 123 | }; 124 | toggleWrapping = function () { 125 | editor.setOption("lineWrapping", !editor.getOption("lineWrapping")); 126 | }; 127 | 128 | $("#language").on( "change", setLang ); 129 | 130 | setLang(); 131 | editor.focus(); 132 | $(window).on( "resize", function () { 133 | refheap.setCodeHeight(editor); 134 | }); 135 | 136 | editor.setOption( "extraKeys", { 137 | "Alt-P": refheap.togglePrivate, 138 | "Ctrl-Enter": refheap.paste, 139 | "Alt-W": toggleWrapping 140 | 141 | }); 142 | refheap.setCodeHeight(editor); 143 | }); 144 | 145 | }( jQuery, window )); 146 | -------------------------------------------------------------------------------- /resources/public/js/pastes.js: -------------------------------------------------------------------------------- 1 | (function ( $, window ) { 2 | var refheap = refheap || {}; 3 | 4 | /** 5 | * Select all of the text in the selected elements. 6 | */ 7 | $.fn.selectText = function(){ 8 | var doc = document, element = this[0], range, selection; 9 | if (doc.body.createTextRange) { 10 | range = document.body.createTextRange(); 11 | range.moveToElementText(element); 12 | range.select(); 13 | } else if (window.getSelection) { 14 | selection = window.getSelection(); 15 | range = document.createRange(); 16 | range.selectNodeContents(element); 17 | selection.removeAllRanges(); 18 | selection.addRange(range); 19 | } 20 | }; 21 | 22 | /** 23 | * Hilight the line of code indicated by the current hash. 24 | */ 25 | refheap.hlLine = function () { 26 | $('a[style]').removeAttr("style"); 27 | $('a[href|="' + window.location.hash + '"]').attr("style", "color: #FFE93B;"); 28 | }; 29 | 30 | /** 31 | * Given a number, n, return that number unless it is less than min 32 | * or greater than max in which case either max or min will be 33 | * returned respectively. 34 | */ 35 | refheap.limit = function ( n, min, max ) { 36 | if ( n < min ) { 37 | return min; 38 | } else if ( n > max ) { 39 | return max; 40 | } else { 41 | return n; 42 | } 43 | }; 44 | 45 | /** 46 | * Display the raw content of the paste in a pop-under entirely 47 | * selected for easy copying. 48 | */ 49 | refheap.showRaw = function () { 50 | refheap.getRaw().done( function ( text ) { 51 | var $cont = $( "#container" ), 52 | pos = $cont.position(), pre, 53 | sizeDisplay = function () { 54 | pre.css({ 55 | position: "absolute", 56 | top: pos.top, 57 | left: pos.left, 58 | height: $cont.outerHeight(), 59 | width: $cont.outerWidth(), 60 | zIndex: 1000, 61 | overflow: "scroll" 62 | }); 63 | }, 64 | ctrlCHandler = function ( e ) { 65 | $( pre ).fadeOut( "fast", function () { 66 | $( document ).unbind( "keydown", ctrlCHandler ); 67 | $( window ).off( "resize", sizeDisplay ); 68 | }); 69 | }; 70 | pre = $( "
      " )
       71 | 	.text( text )
       72 |         .css("display", "none");
       73 | 
       74 |       sizeDisplay();
       75 | 
       76 |       pre.appendTo( "body" )
       77 | 	.fadeIn( "fast", function () {
       78 | 	  $( pre ).selectText();
       79 |       	  $("copy the text, press ESC to close")
       80 | 	    .appendTo( pre );
       81 | 	  $( document ).bind( "keydown", "esc", ctrlCHandler );
       82 |           $( window ).on( "resize", sizeDisplay );
       83 | 	});
       84 |     });
       85 |   };
       86 | 
       87 |   /**
       88 |    * Retrieve the raw text for the paste. Returns a promise.
       89 |    */
       90 |   refheap.getRaw = function () {
       91 |     return $.get( window.location.pathname + "/raw" );
       92 |   };
       93 | 
       94 |   /**
       95 |    * Prompt the user for a line number then navigate the browser to
       96 |    * the correct hash for that line.
       97 |    */
       98 |   refheap.gotoLine = function () {
       99 |     var promptLine = parseInt( prompt( "Go to line...", "1" ), 10 ),
      100 | 	lineCount = $( "a[href^=#L-]" ).length,
      101 | 	line = refheap.limit( promptLine, 1, lineCount );
      102 |     window.location.hash = "#L-" + line;
      103 |   };
      104 | 
      105 |   /**
      106 |    * Navigate the browser to the edit page for the past if the user is logged in.
      107 |    */
      108 |   refheap.gotoEdit = function () {
      109 |     // This is probably not the best way to test if the user has logged in.
      110 |     if ( $( "#userbutton" ).length > 0 ) {
      111 |       window.location.href = window.location.pathname + "/edit";
      112 |     }
      113 |   };
      114 | 
      115 |   $(function () {
      116 |     $(window).on( "hashchange", refheap.hlLine);
      117 |     if ( window.location.hash ) {
      118 |       refheap.hlLine();
      119 |     }
      120 | 
      121 |     $("#delete").click(function(event) {
      122 |       var r = confirm("Are you sure you want to delete this paste? There is no getting it back.");
      123 |       if (r == false) {
      124 | 	event.preventDefault();
      125 |       }
      126 |     });
      127 | 
      128 |     // Setup hotkeys
      129 |     Mousetrap.bind( "alt+g", refheap.gotoLine );
      130 |     Mousetrap.bind( "alt+ctrl+e", refheap.gotoEdit );
      131 |     Mousetrap.bind( "alt+r", refheap.showRaw );
      132 |   });
      133 | 
      134 | }( jQuery, window ));
      135 | 
      136 | 
      
      
      --------------------------------------------------------------------------------
      /resources/public/js/refheap.js:
      --------------------------------------------------------------------------------
       1 | /*
       2 |  * Refheap UI Enhancements
       3 |  */
       4 | 
       5 | $( function ( $, window ) {
       6 | 
       7 |   var refheap = refheap || {};
       8 | 
       9 |   /**
      10 |    * Prompt the user for their BrowserID and verify via XHR POST.
      11 |    */
      12 |   refheap.signIn = function () {
      13 |     navigator.id.get( function ( assertion ) {
      14 |       $.post( "/user/verify", { assertion: assertion }, function ( data ) {
      15 |         if ( data ) {
      16 |           $( "#useri" ).html( data["login-html"] );
      17 |           $( "body" ).html( data["chooselogin-html"] );
      18 |         }
      19 |       });
      20 |     });
      21 |   };
      22 | 
      23 |   $( function () {
      24 |     $( "#signin" ).click( refheap.signIn );
      25 | 
      26 |     // help popunder
      27 |     $( "#help-bubble" ).click( function () {
      28 |       $( "#help-dialog" ).slideToggle( "fast" )
      29 |         .find( "h3 > span" ).on( "click", function () {
      30 |           $( "#help-dialog" ).fadeOut( "fast" );
      31 |         });
      32 |     });
      33 | 
      34 |   });
      35 | 
      36 | }( jQuery, window ));
      37 | 
      38 | 
      
      
      --------------------------------------------------------------------------------
      /resources/public/monokai.css:
      --------------------------------------------------------------------------------
       1 | .syntax .hll { background-color: #49483e }
       2 | .syntax  { background: #272822; color: #f8f8f2 }
       3 | .syntax .c { color: #75715e } /* Comment */
       4 | .syntax .err { color: #960050; background-color: #1e0010 } /* Error */
       5 | .syntax .k { color: #66d9ef } /* Keyword */
       6 | .syntax .l { color: #ae81ff } /* Literal */
       7 | .syntax .n { color: #f8f8f2 } /* Name */
       8 | .syntax .o { color: #f92672 } /* Operator */
       9 | .syntax .p { color: #f8f8f2 } /* Punctuation */
      10 | .syntax .cm { color: #75715e } /* Comment.Multiline */
      11 | .syntax .cp { color: #75715e } /* Comment.Preproc */
      12 | .syntax .c1 { color: #75715e } /* Comment.Single */
      13 | .syntax .cs { color: #75715e } /* Comment.Special */
      14 | .syntax .ge { font-style: italic } /* Generic.Emph */
      15 | .syntax .gs { font-weight: bold } /* Generic.Strong */
      16 | .syntax .kc { color: #66d9ef } /* Keyword.Constant */
      17 | .syntax .kd { color: #66d9ef } /* Keyword.Declaration */
      18 | .syntax .kn { color: #f92672 } /* Keyword.Namespace */
      19 | .syntax .kp { color: #66d9ef } /* Keyword.Pseudo */
      20 | .syntax .kr { color: #66d9ef } /* Keyword.Reserved */
      21 | .syntax .kt { color: #66d9ef } /* Keyword.Type */
      22 | .syntax .ld { color: #e6db74 } /* Literal.Date */
      23 | .syntax .m { color: #ae81ff } /* Literal.Number */
      24 | .syntax .s { color: #e6db74 } /* Literal.String */
      25 | .syntax .na { color: #a6e22e } /* Name.Attribute */
      26 | .syntax .nb { color: #f8f8f2 } /* Name.Builtin */
      27 | .syntax .nc { color: #a6e22e } /* Name.Class */
      28 | .syntax .no { color: #66d9ef } /* Name.Constant */
      29 | .syntax .nd { color: #a6e22e } /* Name.Decorator */
      30 | .syntax .ni { color: #f8f8f2 } /* Name.Entity */
      31 | .syntax .ne { color: #a6e22e } /* Name.Exception */
      32 | .syntax .nf { color: #a6e22e } /* Name.Function */
      33 | .syntax .nl { color: #f8f8f2 } /* Name.Label */
      34 | .syntax .nn { color: #f8f8f2 } /* Name.Namespace */
      35 | .syntax .nx { color: #a6e22e } /* Name.Other */
      36 | .syntax .py { color: #f8f8f2 } /* Name.Property */
      37 | .syntax .nt { color: #f92672 } /* Name.Tag */
      38 | .syntax .nv { color: #f8f8f2 } /* Name.Variable */
      39 | .syntax .ow { color: #f92672 } /* Operator.Word */
      40 | .syntax .w { color: #f8f8f2 } /* Text.Whitespace */
      41 | .syntax .mf { color: #ae81ff } /* Literal.Number.Float */
      42 | .syntax .mh { color: #ae81ff } /* Literal.Number.Hex */
      43 | .syntax .mi { color: #ae81ff } /* Literal.Number.Integer */
      44 | .syntax .mo { color: #ae81ff } /* Literal.Number.Oct */
      45 | .syntax .sb { color: #e6db74 } /* Literal.String.Backtick */
      46 | .syntax .sc { color: #e6db74 } /* Literal.String.Char */
      47 | .syntax .sd { color: #e6db74 } /* Literal.String.Doc */
      48 | .syntax .s2 { color: #e6db74 } /* Literal.String.Double */
      49 | .syntax .se { color: #ae81ff } /* Literal.String.Escape */
      50 | .syntax .sh { color: #e6db74 } /* Literal.String.Heredoc */
      51 | .syntax .si { color: #e6db74 } /* Literal.String.Interpol */
      52 | .syntax .sx { color: #e6db74 } /* Literal.String.Other */
      53 | .syntax .sr { color: #e6db74 } /* Literal.String.Regex */
      54 | .syntax .s1 { color: #e6db74 } /* Literal.String.Single */
      55 | .syntax .ss { color: #e6db74 } /* Literal.String.Symbol */
      56 | .syntax .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
      57 | .syntax .vc { color: #f8f8f2 } /* Name.Variable.Class */
      58 | .syntax .vg { color: #f8f8f2 } /* Name.Variable.Global */
      59 | .syntax .vi { color: #f8f8f2 } /* Name.Variable.Instance */
      60 | .syntax .il { color: #ae81ff } /* Literal.Number.Integer.Long */
      61 | 
      
      
      --------------------------------------------------------------------------------
      /src/refheap/config.clj:
      --------------------------------------------------------------------------------
      1 | (ns refheap.config
      2 |   (:require [clj-config.core :as cfg]))
      3 | 
      4 | (def config
      5 |   "Some external configuration."
      6 |   (cfg/safely cfg/read-config "config.clj"))
      
      
      --------------------------------------------------------------------------------
      /src/refheap/dates.clj:
      --------------------------------------------------------------------------------
       1 | (ns refheap.dates
       2 |   (:require [clj-time.core :as time]
       3 |             [clj-time.format :as format]))
       4 | 
       5 | (def months
       6 |   {1 "January"
       7 |    2 "February"
       8 |    3 "March"
       9 |    4 "April"
      10 |    5 "May"
      11 |    6 "June"
      12 |    7 "July"
      13 |    8 "August"
      14 |    9 "September"
      15 |    10 "October"
      16 |    11 "November"
      17 |    12 "December"})
      18 | 
      19 | (defn parse-string [date]
      20 |   (format/parse (format/formatters :date-time) date))
      21 | 
      22 | (defn date-string [date]
      23 |   (let [parsed (parse-string date)]
      24 |     (str (months (time/month parsed)) " "
      25 |          (time/day parsed) ", "
      26 |          (time/year parsed))))
      27 | 
      28 | (defn datetime-string [date]
      29 |   (let [date-string (date-string  date)
      30 |         parsed      (parse-string date)]
      31 |     (str date-string " at "
      32 |          (time/hour parsed) ":" (time/minute parsed))))
      
      
      --------------------------------------------------------------------------------
      /src/refheap/highlight.clj:
      --------------------------------------------------------------------------------
        1 | (ns refheap.highlight
        2 |   (:require [me.raynes.conch :refer [let-programs]]
        3 |             [clojure.string :as string]
        4 |             [refheap.markdown :refer [to-html]]))
        5 | 
        6 | (def lexers
        7 |   "A map of language names to pygments lexer names."
        8 |   {"Clojure" {:short "clojure"
        9 |               :exts #{"clj" "cljs"}}
       10 |    "Apricot" {:short "clojure"
       11 |               :exts #{"apr"}}
       12 |    "Factor" {:short "factor"
       13 |              :exts #{"factor"}}
       14 |    "Fancy" {:short "fancy"
       15 |             :exts #{"fy"}}
       16 |    "Groovy" {:short "groovy"
       17 |              :exts #{"groovy"}}
       18 |    "Io" {:short "io"
       19 |          :exts #{"io"}}
       20 |    "Ioke" {:short "ioke"
       21 |            :exts #{"ioke"}}
       22 |    "Lua" {:short "lua"
       23 |           :exts #{"lua"}}
       24 |    "Perl" {:short "perl"
       25 |            :exts #{"pl"}}
       26 |    "Python Console" {:short "pycon"}
       27 |    "Python" {:short "python"
       28 |              :exts #{"py"}}
       29 |    "Python Traceback" {:short "pytb"}
       30 |    "Ruby Console" {:short "irb"}
       31 |    "Ruby" {:short "ruby"
       32 |            :exts #{"rb"}}
       33 |    "Mirah" {:short "ruby"
       34 |             :exts #{"mirah"}}
       35 |    "Tcl" {:short "tcl"
       36 |           :exts #{"mirah"}}
       37 |    "C Object Dump" {:short "c-objdump"}
       38 |    "C++ Object Dump" {:short "cpp-objdump"}
       39 |    "D Object Dump" {:short "d-objdump"}
       40 |    "Gas" {:short "gas"}
       41 |    "LLVM" {:short "llvm"}
       42 |    "NASM" {:short "nasm"}
       43 |    "Object Dump" {:short "objdump"}
       44 |    "Ada" {:short "ada"
       45 |           :exts #{"ada"}}
       46 |    "BlitzMax" {:short "bmax"}
       47 |    "C" {:short "c"
       48 |         :exts #{"c" "h"}}
       49 |    "C++" {:short "cpp"
       50 |           :exts #{"cpp"}}
       51 |    "Cython" {:short "pyx"
       52 |              :exts #{"pyx"}}
       53 |    "D" {:short "d"
       54 |         :exts #{"d"}}
       55 |    "Delphi" {:short "delphi"} ;; What the fuck *is* the right extension for this?
       56 |    "Dylan" {:short "dylan"
       57 |             :exts #{"dylan"}}
       58 |    "Felix" {:short "flx"
       59 |             :exts #{"flx"}}
       60 |    "Fortran" {:short "fortran"
       61 |               :exts #{"fortran"}}
       62 |    "GLSL" {:short "glsl"}
       63 |    "Go" {:short "go"
       64 |          :exts #{"go"}}
       65 |    "Java" {:short "java"
       66 |            :exts #{"java"}}
       67 |    "Modula-2" {:short "m2"
       68 |                :exts #{"def" "mod"}}
       69 |    "Nimrod" {:short "nim"
       70 |              :exts #{"nim" "nimrod"}}
       71 |    "Objective-C" {:short "objective-c"
       72 |                   :exts #{"m"}}
       73 |    "ooc" {:short "ooc"
       74 |           :exts #{"ooc"}}
       75 |    "Prolog" {:short "prolog"
       76 |              :exts #{"pro"}}
       77 |    "Scala" {:short "scala"
       78 |             :exts #{"scala"}}
       79 |    "Vala" {:short "vala"
       80 |            :exts #{"vala"}}
       81 |    "Boo" {:short "boo"
       82 |           :exts #{"boo"}}
       83 |    "C#" {:short "csharp"
       84 |          :exts #{"cs"}}
       85 |    "F#" {:short "fsharp"
       86 |          :exts #{"fs"}}
       87 |    "Nemerle" {:short "nemerle"
       88 |               :exts #{"n"}}
       89 |    "VB.NET" {:short "vbnet"
       90 |              :exts #{"vb"}}
       91 |    "Common Lisp" {:short "cl"
       92 |                   :exts #{"lisp"}}
       93 |    "Erlang" {:short "erlang"
       94 |              :exts #{"erl"}}
       95 |    "Erlang Shell" {:short "erl"}
       96 |    "Haskell" {:short "hs"
       97 |               :exts #{"hs"}}
       98 |    "Literate Haskell" {:short "lhs"
       99 |                        :exts #{"lhs"}}
      100 |    "OCaml" {:short "ocaml"
      101 |             :exts #{"ml"}}
      102 |    "Racket" {:short "racket"
      103 |              :exts #{"rkt" "rktl"}}
      104 |    "Scheme" {:short "scm"
      105 |              :exts #{"scm" "ss"}}
      106 |    "Emacs Lisp" {:short "scm"
      107 |                  :exts #{"el"}}
      108 |    "Coq" {:short "coq"
      109 |           :exts #{"v"}}
      110 |    "Verilog" {:short "v"}
      111 |    "Matlab" {:short "matlab"}
      112 |    "MuPAD" {:short "mupad"}
      113 |    "NumPy" {:short "numpy"}
      114 |    "R Console" {:short "rout"}
      115 |    "R" {:short "r"
      116 |         :exts #{"r"}}
      117 |    "AppleScript" {:short "applescript"
      118 |                   :exts #{"applescript"}}
      119 |    "Autohotkey" {:short "ahk"
      120 |                  :exts #{"ahk"}}
      121 |    "Awk" {:short "awk"
      122 |           :exts #{"awk"}}
      123 |    "Bash" {:short "sh"
      124 |            :exts #{"sh"}}
      125 |    "Bash Session" {:short "console"}
      126 |    "Shell Session" {:short "shell-session"
      127 |                     :exts #{"shell-session"}}
      128 |    "Batch" {:short "bat"
      129 |             :exts #{"bat"}}
      130 |    "Befunge" {:short "befunge"
      131 |               :exts #{"befunge"}}
      132 |    "Brainfuck" {:short "bf"
      133 |                 :exts #{"bf"}}
      134 |    "Cucumber" {:short "cucumber"}
      135 |    "MOOCode" {:short "moocode"}
      136 |    "MySQL" {:short "mysql"}
      137 |    "NewSpeak" {:short "newspeak"}
      138 |    "NewLisp" {:short "newlisp"
      139 |               :exts #{"lsp" "nl"}}
      140 |    "PostScript" {:short "postscript"
      141 |                  :exts #{"ps"}}
      142 |    "Protobuf" {:short "protobuf"
      143 |                :exts #{"proto"}}
      144 |    "REBOL" {:short "rebol"
      145 |             :exts #{"rebol"}}
      146 |    "COBOL" {:short "cobol"
      147 |             :exts #{"cob" "COB" "cpy" "CPY"}}
      148 |    "Rust" {:short "rust"
      149 |            :exts #{"rs" "rc"}}
      150 |    "Smali" {:short "smali"
      151 |             :exts #{"smali"}}
      152 |    "Ceylon" {:short "ceylon"
      153 |              :exts #{"ceylon"}}
      154 |    "Julia" {:short "julia"
      155 |              :exts #{"jl"}}
      156 |    "Julia Console" {:short "jlcon"}
      157 |    "AutoIt" {:short "autoit"
      158 |              :exts #{"au3"}}
      159 |    "Puppet" {:short "puppet"
      160 |              :exts #{"pp"}}
      161 |    "HXML" {:short "hxml"
      162 |            :exts #{"hxml"}}
      163 |    "TypeScript" {:short "ts"
      164 |                  :exts #{"ts"}}
      165 |    "Redcode" {:short "redcode"}
      166 |    "Smalltalk" {:short "squeak"
      167 |                 :exts #{"st"}}
      168 |    "SQL" {:short "sql"
      169 |           :exts #{"sql"}}
      170 |    "TCSH" {:short "csh"}
      171 |    "Apache Configuration" {:short "apacheconf"}
      172 |    "BBCode" {:short "bbcode"}
      173 |    "CMake" {:short "cmake"}
      174 |    "Darcs Patch" {:short "dpatch"}
      175 |    "Diff" {:short "diff"
      176 |            :exts #{"diff"}}
      177 |    "INI" {:short "ini"
      178 |           :exts #{"ini"}}
      179 |    "IRC Logs" {:short "irc"}
      180 |    "Lighttpd" {:short "lighty"}
      181 |    "Makefile" {:short "make"}
      182 |    "Nginx Configuration" {:short "nginx"}
      183 |    "Java Properties" {:short "properties"
      184 |                       :exts #{"properties"}}
      185 |    "rST" {:short "rst"
      186 |           :exts #{"rst"}}
      187 |    "LaTeX" {:short "tex"
      188 |             :exts #{"tex"}}
      189 |    "VimL" {:short "vim"
      190 |            :exts #{"vim"}}
      191 |    "YAML" {:short "yaml"
      192 |            :exts #{"yaml" "yml"}}
      193 |    "ActionScript" {:short "as"
      194 |                    :exts #{"as"}}
      195 |    "CoffeeScript" {:short "coffeescript"
      196 |                    :exts #{"coffeescript" "coffee"}}
      197 |    "CSS" {:short "css"
      198 |           :exts #{"css"}}
      199 |    "DTD" {:short "dtd"}
      200 |    "HAML" {:short "haml"
      201 |            :exts #{"haml"}}
      202 |    "haXe" {:short "hx"
      203 |            :exts #{"hx"}}
      204 |    "HTML" {:short "html"
      205 |            :exts #{"html"}}
      206 |    "Javascript" {:short "js"
      207 |                  :exts #{"js"}}
      208 |    "PHP" {:short "php"
      209 |           :exts #{"php"}}
      210 |    "Plain Text" {:short "text"
      211 |                  :ext #{"txt"}}
      212 |    "SASS" {:short "sass"
      213 |            :exts #{"scss" "sass"}}
      214 |    "Scaml" {:short "scaml"
      215 |             :exts #{"scaml"}}
      216 |    "XML" {:short "xml"
      217 |           :exts #{"xml"}}
      218 |    "Kotlin" {:short "kotlin"
      219 |              :exts #{"kt"}}
      220 |    "Elixir" {:short "ex"
      221 |              :exts #{"ex" "exs"}}
      222 |    "Elixir Console" {:short "iex"}
      223 |    "Markdown" {:short "Markdown"
      224 |                :exts #{"md" "markdown"}}
      225 |    "RPM Spec" {:short "spec"
      226 |                :exts #{"spec"}}})
      227 | 
      228 | (defn lookup-lexer
      229 |   "Selects a language."
      230 |   [lang]
      231 |   (or
      232 |    (if (and lang (.startsWith lang "."))
      233 |      (first
      234 |       (filter (fn [[_ v]]
      235 |                 (when-let [exts (:exts v)]
      236 |                   (exts (string/join (rest lang)))))
      237 |               lexers))
      238 |      (when-let [lang-map (lexers lang)]
      239 |        [lang lang-map]))
      240 |    ["Plain Text" {:short "text"}]))
      241 | 
      242 | (defn highlight
      243 |   "Syntax highlight some code. If anything other than markdown, highlight
      244 |    with pygments. If markdown, render with pegdown."
      245 |   [language text & [anchor?]]
      246 |   (if (= language "Markdown")
      247 |     (try
      248 |       {:success (to-html text)}
      249 |       (catch Exception _
      250 |         {:error "There was an error pasting."}))
      251 |     (let-programs [pygmentize "./pygmentize"]
      252 |       (let [output (pygmentize "-fhtml" (str "-l" language)
      253 |                                (str "-Olinenos=table,stripnl=False,encoding=utf-8"
      254 |                                     (when anchor? ",anchorlinenos=true,lineanchors=L"))
      255 |                                {:dir "resources/pygments"
      256 |                                 :in text})]
      257 |         (if (seq output)
      258 |           {:success output}
      259 |           {:error "There was an error pasting."})))))
      260 | 
      
      
      --------------------------------------------------------------------------------
      /src/refheap/markdown.clj:
      --------------------------------------------------------------------------------
       1 | (ns refheap.markdown
       2 |   (:require [me.raynes.laser :as laser]
       3 |             [me.raynes.cegdown :as md]))
       4 | 
       5 | (defn wrap-code [html]
       6 |   (str "
      \n" 7 | (laser/fragment-to-html 8 | (laser/fragment 9 | (laser/parse-fragment html) 10 | (laser/element= :pre) (laser/add-class "md-code"))) 11 | "
      ")) 12 | 13 | (defn to-html 14 | "Convert markdown to html." 15 | [s] 16 | (wrap-code (md/to-html s [:fenced-code-blocks :tables]))) 17 | -------------------------------------------------------------------------------- /src/refheap/messages.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.messages 2 | (:require [noir.session :as session])) 3 | 4 | (defn error [msg] 5 | (session/flash-put! :error msg) 6 | nil) -------------------------------------------------------------------------------- /src/refheap/models/api.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.models.api 2 | (:require [refheap.models.users :as users] 3 | [refheap.models.paste :as pastes] 4 | [noir.response :as response] 5 | [clojure.string :as string] 6 | [monger.collection :as mc]) 7 | (:import java.util.UUID)) 8 | 9 | (defn gen-token 10 | "Create a new API token. This just generates a UUID." 11 | [] 12 | (str (UUID/randomUUID))) 13 | 14 | (defn new-token 15 | "Gives a user a new API token and disables the old one (by removing it)." 16 | [userid] 17 | (let [old (users/get-user-by-id userid) 18 | new (gen-token)] 19 | (mc/update "users" old (assoc old :token new)) 20 | new)) 21 | 22 | (defn get-token 23 | "Get a user's API token. Generate one if it doesn't exist." 24 | [userid] 25 | (or (:token (users/get-user-by-id userid)) 26 | (new-token userid))) 27 | 28 | (defn validate-user 29 | "Validate that a token exists and that the user has that token." 30 | [username token] 31 | (when (and username token) 32 | (if-let [user (mc/find-one-as-map "users" {:token token, :username (.toLowerCase username)})] 33 | (-> user 34 | (assoc :id (str (:_id user))) 35 | (dissoc :_id)) 36 | "User or token not valid."))) 37 | 38 | (defn id->paste-id [paste] 39 | (if-let [fork (:fork paste)] 40 | (assoc paste :fork (or (:paste-id (pastes/get-paste-by-id fork)) "deleted")) 41 | paste)) 42 | 43 | (defn process-paste 44 | "Select and rename keys to make pastes suitable for api consumption." 45 | [paste] 46 | (-> paste 47 | (assoc :contents (:raw-contents paste)) 48 | (assoc :user (when-let [user (:user paste)] 49 | (:username (users/get-user-by-id user)))) 50 | (assoc :url (str "https://www.refheap.com/" (:paste-id paste))) 51 | (dissoc :id :_id :raw-contents :summary :history) 52 | id->paste-id)) 53 | 54 | (defn string->bool [s] (Boolean/parseBoolean s)) 55 | 56 | (defn add-status [status resp] 57 | (assoc resp :status status)) 58 | 59 | (defn error [msg] {:error msg}) 60 | 61 | (defn response [type & [data kind]] 62 | (let [respond (if (= kind "edn") 63 | response/edn 64 | response/json)] 65 | (case type 66 | :bad (add-status 400 (respond (error data))) 67 | :unprocessable (add-status 422 (respond (error data))) 68 | :created (add-status 201 (respond data)) 69 | :no-content {:status 204} 70 | :not-found (add-status 404 (respond (error data))) 71 | :ok (respond data)))) 72 | -------------------------------------------------------------------------------- /src/refheap/models/login.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.models.login 2 | (:require [refheap.config :refer [config]] 3 | [clj-http.client :as http] 4 | [noir.session :as session] 5 | [cheshire.core :as json] 6 | [refheap.messages :refer [error]] 7 | [monger.collection :as mc] 8 | [monger.operators :refer [$set]]) 9 | (:import org.bson.types.ObjectId)) 10 | 11 | (defn transfer-anon-pastes [user] 12 | (doseq [id (session/get! :anon-pastes)] 13 | (mc/update "pastes" {:paste-id id} {$set {:user user}} 14 | :upsert false :multi false))) 15 | 16 | (defn create-user [email name] 17 | (let [name (.toLowerCase name) 18 | qmap {:email email 19 | :username name} 20 | name-count (count name)] 21 | ;; this stuff would be much cleaner with Validateur. MK. 22 | (cond 23 | (or (> 3 name-count) (< 15 name-count)) 24 | (error "Username must be between 3 and 15 characters.") 25 | (not= name (first (re-seq #"\w+" name))) 26 | (error "Username cannot contain non-alphanumeric characters.") 27 | (mc/find-one-as-map "users" {:username name}) 28 | (error "Username already exists.") 29 | :else (let [user (mc/insert-and-return "users" qmap) 30 | id (str (:_id user))] 31 | (transfer-anon-pastes id) 32 | (session/put! :user (assoc qmap :id id)))))) 33 | 34 | (defn user-exists [email] 35 | (when-let [{:keys [username _id]} (mc/find-one-as-map "users" {:email email})] 36 | (transfer-anon-pastes (str _id)) 37 | (session/put! :user {:email email 38 | :username username 39 | :id (str _id)}) 40 | username)) 41 | 42 | (defn verify-host [host hosts] 43 | (-> (.split host ":") 44 | (first) 45 | (hosts))) 46 | 47 | (defn get-hosts [] 48 | (if-let [hosts (System/getenv "HOSTS")] 49 | (set (.split hosts ",")) 50 | (or (:hosts config) #{"localhost"}))) 51 | 52 | (defn verify-assertion [host assertion] 53 | (let [verified (json/parse-string 54 | (:body 55 | (http/post "https://browserid.org/verify" 56 | {:form-params 57 | {:assertion assertion 58 | :audience (verify-host host (get-hosts))}})) 59 | true)] 60 | (when (= "okay" (:status verified)) 61 | verified))) 62 | -------------------------------------------------------------------------------- /src/refheap/models/paste.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.models.paste 2 | (:refer-clojure :exclude [sort find]) 3 | (:require [noir.session :as session] 4 | [clojure.java.io :as io] 5 | [clojure.string :as string] 6 | [clj-time.core :as time] 7 | [clj-time.format :as format] 8 | [refheap.dates :refer [parse-string]] 9 | [refheap.messages :refer [error]] 10 | [monger.collection :as mc] 11 | [monger.query :refer [with-collection find sort limit paginate]] 12 | [monger.operators :refer [$inc $set $push]] 13 | [refheap.highlight :refer [lookup-lexer highlight]]) 14 | (:import java.io.StringReader 15 | org.apache.commons.codec.digest.DigestUtils)) 16 | 17 | (def paste-id 18 | "The current highest paste-id." 19 | (atom 20 | (-> (with-collection "pastes" 21 | (find {}) 22 | (sort {:id -1}) 23 | (limit 1)) 24 | first 25 | :id 26 | (or 0)))) 27 | 28 | (defn preview 29 | "Get the first 5 lines of a string." 30 | [s] 31 | (->> s StringReader. io/reader line-seq (take 5) (string/join "\n"))) 32 | 33 | (defn generate-id 34 | "Generate a hex string of a SHA1 hack of a random UUID. 35 | Return the first 25 characters." 36 | [] 37 | (-> (java.util.UUID/randomUUID) 38 | str 39 | DigestUtils/shaHex 40 | (.substring 0 25))) 41 | 42 | ;; The reason there are three ids are because they all serve a different purpose. 43 | ;; paste-id is the id that is public-facing. If a paste is private, it is the same 44 | ;; as :random-id. If the paste is not private, it is the same as :id. :id is just 45 | ;; the number of the paste in the database. random-id is an id generated with 46 | ;; generate-id. 47 | (defn paste-map [id random-id user language contents date private fork views] 48 | (let [[name {:keys [short]}] (lookup-lexer language) 49 | private (boolean private) 50 | random-id (or random-id (generate-id)) 51 | pygmentized (highlight short contents true)] 52 | (if-let [highlighted (:success pygmentized)] 53 | {:paste-id (if private random-id (str id)) 54 | :id id 55 | :random-id random-id 56 | :user (:id user) 57 | :remote-addr (:remote-addr user) 58 | :language name 59 | :raw-contents contents 60 | :summary (:success (highlight short (preview contents))) 61 | :private (boolean private) 62 | :date date 63 | :lines (let [lines (count (filter #{\newline} contents))] 64 | (if (= \newline (last contents)) 65 | lines 66 | (inc lines))) 67 | :contents highlighted 68 | :fork fork 69 | :views views} 70 | {:error (:error pygmentized)}))) 71 | 72 | (defn validate [contents] 73 | (cond 74 | (>= (count contents) 614400) {:error "That paste was too big. Has to be less than 600KB"} 75 | (not (re-seq #"\S" (str contents))) {:error "Your paste cannot be empty."} 76 | :else {:contents contents})) 77 | 78 | (defn same-user? [user paste] 79 | (or (and user (= (:id user) (:user paste))) 80 | (some #{(:paste-id paste)} (session/get :anon-pastes)))) 81 | 82 | (defn parse-date [date] 83 | (format/parse)) 84 | 85 | (defn paste 86 | "Create a new paste." 87 | [language contents private user & [fork]] 88 | (when-not fork 89 | (session/put! :last-lang language)) 90 | (let [validated (validate contents)] 91 | (if-let [error (:error validated)] 92 | error 93 | (let [id (swap! paste-id inc) 94 | random-id (generate-id) 95 | paste (paste-map id 96 | random-id 97 | user 98 | language 99 | (:contents validated) 100 | (format/unparse (format/formatters :date-time) (time/now)) 101 | private 102 | fork 103 | 0)] 104 | (if-let [error (:error paste)] 105 | error 106 | (do 107 | (when-not user 108 | (session/update-in! [:anon-pastes] conj (:paste-id paste))) 109 | (mc/insert-and-return "pastes" paste))))))) 110 | 111 | (defn get-paste 112 | "Get a paste." 113 | [id] 114 | (mc/find-one-as-map "pastes" {:paste-id id})) 115 | 116 | (defn view-paste 117 | "Get a paste and increment its view count." 118 | [id] 119 | (let [views (session/get :views)] 120 | (when (>= (count views) 5000) 121 | (session/remove! :views)) 122 | (if (some #{id} views) 123 | (get-paste id) 124 | (when-let [paste (mc/find-and-modify "pastes" {:paste-id id} 125 | {$inc {:views 1}} 126 | :return-new true)] 127 | (session/update-in! [:views] conj id) 128 | paste)))) 129 | 130 | (defn get-paste-by-id 131 | "Get a paste by its :id key (which is the same regardless of being public or private." 132 | [id] 133 | (mc/find-one-as-map "pastes" {:id id})) 134 | 135 | (defn update-paste 136 | "Update an existing paste." 137 | [old language contents private user] 138 | (let [validated (validate contents) 139 | error (:error validated)] 140 | (cond 141 | error error 142 | (not (same-user? user old)) "You can only edit your own pastes!" 143 | :else (let [{old-id :id random-id :random-id} old 144 | paste (paste-map 145 | old-id 146 | random-id 147 | user 148 | language 149 | (:contents validated) 150 | (:date old) 151 | private 152 | (:fork old) 153 | (:views old)) 154 | old-version (-> old 155 | (dissoc :history) 156 | (assoc :version (-> old :history count inc)))] 157 | (if-let [error (:error paste)] 158 | error 159 | (mc/update "pastes" {:id old-id} {$set paste, $push {:history old-version}} 160 | :upsert false :multi false)) 161 | paste)))) 162 | 163 | (defn delete-paste 164 | "Delete an existing paste." 165 | [id] 166 | (mc/remove "pastes" {:paste-id id})) 167 | 168 | (defn get-pastes 169 | "Get public pastes." 170 | [page] 171 | (with-collection "pastes" 172 | (find {:private false}) 173 | (sort {:date -1}) 174 | (paginate :page page :per-page 20))) 175 | 176 | (defn count-pastes 177 | "Count pastes." 178 | [& [private?]] 179 | (mc/count "pastes" (if-not (nil? private?) 180 | {:private private?} 181 | {}))) 182 | 183 | (defn get-forks [paste page] 184 | "Get forks of a paste." 185 | (with-collection "pastes" 186 | (find {:fork (:id paste) 187 | :private false}) 188 | (sort {:date -1}) 189 | (paginate :page page :per-page 20))) 190 | 191 | (defn count-forks [paste] 192 | "Count forks of a paste." 193 | (mc/count "pastes" {:fork (:id paste) 194 | :private false})) 195 | 196 | (defn get-history [paste page] 197 | "Get history of a paste." 198 | (->> (:history paste) 199 | reverse 200 | (cons paste) 201 | (drop (* (dec page) 20)) 202 | (take 20))) 203 | 204 | (defn count-history [paste] 205 | "Count versions of a paste." 206 | (count (:history paste))) 207 | 208 | (defn get-version [paste version] 209 | "Get a version of a paste." 210 | (->> paste :history (filter (comp #{version} :version)) first)) 211 | 212 | (defn count-pages [n per] 213 | (long (Math/ceil (/ n per)))) 214 | 215 | (defn proper-page [n] 216 | (if (<= n 0) 1 n)) 217 | -------------------------------------------------------------------------------- /src/refheap/models/users.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.models.users 2 | (:refer-clojure :exclude [sort find]) 3 | (:require [monger.collection :as mc] 4 | [monger.query :refer [with-collection find sort paginate]]) 5 | (:import org.bson.types.ObjectId)) 6 | 7 | (defn get-user [user] 8 | (mc/find-one-as-map "users" {:username user})) 9 | 10 | (defn get-user-by-id [id] 11 | (mc/find-map-by-id "users" (ObjectId. id))) 12 | 13 | (defn user-pastes [user page & [others]] 14 | (with-collection "pastes" 15 | (find (merge {:user (str (:_id (get-user user)))} others)) 16 | (sort {:date -1}) 17 | (paginate :page page :per-page 10))) 18 | 19 | (defn count-user-pastes [user & [others]] 20 | (mc/count "pastes" (merge {:user (str (:_id (get-user user)))} others))) 21 | -------------------------------------------------------------------------------- /src/refheap/server.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.server 2 | (:require [refheap.config :refer [config]] 3 | [noir.util.middleware :refer [wrap-strip-trailing-slash wrap-canonical-host wrap-force-ssl]] 4 | [noir.session :refer [wrap-noir-session wrap-noir-flash]] 5 | [monger.core :as mg] 6 | [monger.collection :as mc] 7 | [monger.ring.session-store :refer [monger-store]] 8 | [compojure.core :refer [defroutes routes ANY]] 9 | [compojure.handler :refer [api]] 10 | [compojure.route :refer [not-found resources]] 11 | [me.raynes.laser :as l])) 12 | 13 | (let [uri (get (System/getenv) "MONGOLAB_URI" "mongodb://127.0.0.1/refheap_development")] 14 | (mg/connect-via-uri! uri)) 15 | 16 | (mc/ensure-index "pastes" {:user 1 :date 1}) 17 | (mc/ensure-index "pastes" {:private 1}) 18 | (mc/ensure-index "pastes" {:id 1}) 19 | (mc/ensure-index "pastes" {:paste-id 1}) 20 | (mc/ensure-index "pastes" {:fork 1}) 21 | 22 | ;; View loading has to be done after mongo is available. 23 | (require '[refheap.views.common :refer [layout]] 24 | '[refheap.views.about :refer [about-routes]] 25 | '[refheap.views.legal :refer [legal-routes]] 26 | '[refheap.views.paste :refer [paste-routes]] 27 | '[refheap.views.users :refer [user-routes]] 28 | '[refheap.views.api :refer [api-routes]] 29 | '[refheap.views.home :refer [home-routes]] 30 | '[refheap.views.login :refer [login-routes]]) 31 | 32 | (defn four-zero-four [] 33 | (layout (l/unescaped "

      Insert fancy 404 image here.

      "))) 34 | 35 | (defn wrap-prod-middleware [routes] 36 | (if (System/getenv "LEIN_NO_DEV") 37 | (-> routes 38 | (wrap-canonical-host (System/getenv "CANONICAL_HOST")) 39 | (wrap-force-ssl)) 40 | routes)) 41 | 42 | (def handler 43 | (-> (routes about-routes 44 | legal-routes 45 | paste-routes 46 | user-routes 47 | home-routes 48 | login-routes 49 | api-routes 50 | (resources "/") 51 | (not-found (four-zero-four))) 52 | (api) 53 | (wrap-noir-flash) 54 | (wrap-noir-session {:store (monger-store "sessions")}) 55 | (wrap-strip-trailing-slash) 56 | (wrap-prod-middleware))) 57 | -------------------------------------------------------------------------------- /src/refheap/utilities.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.utilities 2 | (:require [refheap.models.paste :as paste] 3 | [clojure.string :refer [lower-case join]])) 4 | 5 | (defn safe-parse-long 6 | "Same as Long/parseLong, but catches exceptions for malformed input and 7 | either returns nil if you passed one argument, or its second argument 8 | if you gave it one." 9 | ([n] (safe-parse-long n nil)) 10 | ([n default] 11 | (try 12 | (if n 13 | (Long/parseLong n) 14 | default) 15 | (catch NumberFormatException _ 16 | default)))) 17 | 18 | (defn to-booleany 19 | "Convert numbers and various representations of 'true' and 'false' 20 | to their actual true or false counterparts." 21 | [s] 22 | (when s 23 | (let [s (lower-case s)] 24 | (case s 25 | "0" false 26 | "1" true 27 | "true" true 28 | "false" false 29 | false)))) 30 | 31 | (def js-char-replacements 32 | (merge char-escape-string 33 | {\' "\\'"})) 34 | 35 | (defn escape-string 36 | "Escapes all escape sequences in a string to make it suitable 37 | for passing to another programming language. Kind of like what 38 | pr-str does for strings but without the wrapper quotes." 39 | [s] 40 | (join (map #(js-char-replacements % %) s))) 41 | 42 | (defn nil-comp 43 | "Composes functions together just like `comp`, but stops and returns nil 44 | if any of the functions in the composition return nil." 45 | [& fns] 46 | (let [fns (reverse fns)] 47 | (fn [& args] 48 | (let [[start & tail] fns] 49 | (reduce 50 | (fn [acc f] 51 | (if (nil? acc) 52 | (reduced nil) 53 | (f acc))) 54 | (apply start args) 55 | tail))))) 56 | 57 | (defn pluralize [n s] 58 | (str n " " s (when-not (= n 1) "s"))) 59 | -------------------------------------------------------------------------------- /src/refheap/views/about.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.about 2 | (:require [refheap.views.common :refer [layout static]] 3 | [compojure.core :refer [defroutes GET]])) 4 | 5 | (defroutes about-routes 6 | (GET "/about" [] (layout (static "refheap/views/templates/about.html")))) -------------------------------------------------------------------------------- /src/refheap/views/api.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.api 2 | (:require [noir.session :as session] 3 | [me.raynes.laser :as laser] 4 | [clojure.java.io :refer [resource]] 5 | [refheap.models.api :as api] 6 | [refheap.models.paste :as paste] 7 | [refheap.models.users :as users] 8 | [compojure.core :refer [defroutes GET POST DELETE]] 9 | [refheap.views.common :refer [layout static]])) 10 | 11 | (let [nodes (laser/parse-fragment (resource "refheap/views/templates/api.html")) 12 | api-head (static "refheap/views/templates/apihead.html")] 13 | (defn api-page [] 14 | (layout 15 | (if-let [id (:id (session/get :user))] 16 | (laser/fragment nodes 17 | (laser/id= "tokentext") (laser/content (api/get-token id)) 18 | (laser/id= "please-login") (laser/remove)) 19 | (laser/fragment nodes (laser/id= "token") (laser/remove))) 20 | nil 21 | api-head))) 22 | 23 | (defn generate-token [] 24 | (when-let [id (:id (session/get :user))] 25 | (api/new-token id))) 26 | 27 | (defn paste [{:keys [private contents language username token return] 28 | :or {private "false"}} 29 | remote-addr] 30 | (let [user (api/validate-user username token)] 31 | (if (string? user) 32 | (api/response :unprocessable user return) 33 | (let [paste (paste/paste 34 | language 35 | contents 36 | (api/string->bool private) 37 | (assoc user :remote-addr remote-addr))] 38 | (if (string? paste) 39 | (api/response :bad paste return) 40 | (api/response :created (api/process-paste paste) return)))))) 41 | 42 | (defn edit-paste [{:keys [id private contents language username token return]}] 43 | (if-let [paste (paste/get-paste id)] 44 | (let [user (api/validate-user username token)] 45 | (cond 46 | (string? user) 47 | (api/response :unprocessable user return) 48 | (nil? (:user paste)) 49 | (api/response :unprocessable "You can't edit anonymous pastes." return) 50 | (nil? user) 51 | (api/response :unprocessable "You must be authenticated to edit pastes." return) 52 | (not= (:id user) (:user paste)) 53 | (api/response :unprocessable "You can only edit pastes that you own." return) 54 | :else (let [paste (paste/update-paste paste 55 | (or language (:language paste)) 56 | (or contents (:raw-contents paste)) 57 | (if (nil? private) 58 | (:private paste) 59 | (api/string->bool private)) 60 | user)] 61 | (if (string? paste) 62 | (api/response :bad paste return) 63 | (api/response :ok (api/process-paste paste) return))))) 64 | (api/response :not-found "Paste does not exist." return))) 65 | 66 | (defn delete-paste [{:keys [id username token return]}] 67 | (if-let [paste (paste/get-paste id)] 68 | (let [user (api/validate-user username token)] 69 | (cond 70 | (string? user) 71 | (api/response :unprocessable user return) 72 | (nil? (:user paste)) 73 | (api/response :unprocessable "You can't delete anonymous pastes." return) 74 | (nil? user) 75 | (api/response :unprocessable "You must be authenticated to delete pastes." return) 76 | (not= (:id user) (:user paste)) 77 | (api/response :unprocessable "You can only delete pastes that you own." return) 78 | :else (api/response :no-content (paste/delete-paste id) return))) 79 | (api/response :not-found "Paste doesn't exist." return))) 80 | 81 | (defn fork-paste [{:keys [id username token return]}] 82 | (if-let [paste (paste/get-paste id)] 83 | (let [user (api/validate-user username token)] 84 | (cond 85 | (string? user) 86 | (api/response :unprocessable user return) 87 | (= (:id user) 88 | (:user paste)) (api/response :unprocessable "You can't fork your own pastes." return) 89 | :else (api/response :created 90 | (api/process-paste 91 | (paste/paste (:language paste) 92 | (:raw-contents paste) 93 | (:private paste) 94 | user 95 | (:id paste))) 96 | return))) 97 | (api/response :not-found "Paste doesn't exist." return))) 98 | 99 | (defroutes api-routes 100 | (GET "/api" [] (api-page)) 101 | (GET "/token/generate" [] (generate-token)) 102 | (POST "/api/paste" {:keys [params remote-addr headers]} 103 | (paste params (or (get headers "x-forwarded-for") remote-addr))) 104 | (POST "/api/paste/:id" {:keys [params]} 105 | (edit-paste params)) 106 | (DELETE "/api/paste/:id" {:keys [params]} 107 | (delete-paste params)) 108 | (POST "/api/paste/:id/fork" {:keys [params]} 109 | (fork-paste params)) 110 | (GET "/api/paste/:id" {{:keys [id return]} :params} 111 | (if-let [paste (paste/get-paste id)] 112 | (api/response :ok (api/process-paste paste) return) 113 | (api/response :not-found "Paste does not exist." return))) 114 | (GET "/api/paste/:id/highlight" {{:keys [id return]} :params} 115 | (if-let [paste (paste/get-paste id)] 116 | (api/response :ok {:content (:contents paste)} return) 117 | (api/response :not-found "Paste does not exist." return)))) 118 | -------------------------------------------------------------------------------- /src/refheap/views/common.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.common 2 | (:require [noir.session :as session] 3 | [refheap.models.paste :as paste] 4 | [clavatar.core :refer [gravatar]] 5 | [me.raynes.laser :refer [defdocument defragment] :as l] 6 | [clojure.java.io :refer [resource]])) 7 | 8 | (defn avatar [email size] 9 | (gravatar email :size size)) 10 | 11 | (defn static [file] 12 | (-> file resource slurp l/unescaped)) 13 | 14 | (let [html (l/parse-fragment (resource "refheap/views/templates/loggedin.html")) 15 | logged-out (static "refheap/views/templates/loggedout.html")] 16 | (defn logged-in [username] 17 | (let [user (or username 18 | (and (bound? #'session/*noir-session*) 19 | (:username (session/get :user))))] 20 | (if user 21 | (l/fragment html 22 | (l/id= "userbutton") (comp (l/attr :href (str "/users/" user)) 23 | (l/content user))) 24 | logged-out)))) 25 | 26 | (defragment head (resource "refheap/views/templates/head.html") 27 | [title heads] 28 | (when heads 29 | [(l/id= :last-include) (l/insert :right heads)]) 30 | (l/element= :title) (l/content (or title "Refheap - The pastebin for your, you know, pastes"))) 31 | 32 | (defragment body (resource "refheap/views/templates/commonbody.html") 33 | [contents] 34 | (l/id= :useri) (l/content (logged-in nil)) 35 | (l/id= :container) (l/content contents)) 36 | 37 | (let [html (l/parse (resource "refheap/views/templates/common.html"))] 38 | (defn layout 39 | ([content] (layout content nil nil)) 40 | ([content title] (layout content title nil)) 41 | ([content title heads] 42 | (l/document 43 | html 44 | (l/element= :head) (l/content (head title heads)) 45 | (l/element= :body) (l/content (body content)))))) 46 | 47 | (defragment page-buttons (resource "refheap/views/templates/pagination.html") 48 | [base n per page] 49 | (if-not (= 1 page) 50 | [(l/id= :newer) (l/attr :href (str base "?page=" (dec page)))] 51 | [(l/id= :newer) (l/remove)]) 52 | (if-not (or (zero? n) (= page (paste/count-pages n per))) 53 | [(l/id= :older) (l/attr :href (str base "?page=" (inc page)))] 54 | [(l/id= :older) (l/remove)])) -------------------------------------------------------------------------------- /src/refheap/views/home.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.home 2 | (:require [noir.response :refer [redirect]] 3 | [compojure.core :refer [defroutes GET]])) 4 | 5 | (defroutes home-routes 6 | (GET "/gh" [] (redirect "https://github.com/Raynes/refheap")) 7 | (GET "/ghi" [] (redirect "https://github.com/Raynes/refheap/issues")) 8 | (GET "/wiki" [] (redirect "https://github.com/Raynes/refheap/wiki"))) 9 | -------------------------------------------------------------------------------- /src/refheap/views/legal.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.legal 2 | (:require [compojure.core :refer [defroutes GET]] 3 | [refheap.views.common :refer [static layout]])) 4 | 5 | (defroutes legal-routes 6 | (GET "/legal/tos" [] (layout (static "refheap/views/templates/tos.html"))) 7 | (GET "/legal/privacy" [] (layout (static "refheap/views/templates/privacy.html")))) 8 | -------------------------------------------------------------------------------- /src/refheap/views/login.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.login 2 | (:require [refheap.models.login :as login] 3 | [noir.session :as session] 4 | [refheap.views.common :refer [body logged-in]] 5 | [compojure.core :refer [defroutes GET POST]] 6 | [noir.response :refer [redirect json]] 7 | [clojure.java.io :refer [resource]] 8 | [me.raynes.laser :as l])) 9 | 10 | (let [html (-> "refheap/views/templates/createuser.html" resource l/parse-fragment)] 11 | (defn create-user-page [email] 12 | (session/flash-put! :email email) 13 | (l/fragment html 14 | (l/class= "error") #(when-let [error (session/flash-get :error)] 15 | (l/on % (l/content error)))))) 16 | 17 | (defn create-user [{:keys [name]}] 18 | (if-let [email (session/flash-get :email)] 19 | (if (login/create-user email name) 20 | (redirect "/paste") 21 | (create-user-page email)))) 22 | 23 | (defn logout-user [] 24 | (session/remove! :user) 25 | (redirect "/paste")) 26 | 27 | (defn verify-user [host {:keys [assertion]}] 28 | (when-let [{:keys [email]} (login/verify-assertion host assertion)] 29 | (json 30 | (if-let [username (login/user-exists email)] 31 | {:login-html (l/fragment-to-html (logged-in username))} 32 | {:chooselogin-html (-> email create-user-page body l/fragment-to-html)})))) 33 | 34 | (defroutes login-routes 35 | (POST "/user/create" {:keys [params]} 36 | (create-user params)) 37 | (GET "/user/logout" [] 38 | (logout-user)) 39 | (POST "/user/verify" {params :params {host "host"} :headers} 40 | (verify-user host params))) -------------------------------------------------------------------------------- /src/refheap/views/paste.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.paste 2 | (:require [refheap.models.paste :as paste] 3 | [refheap.models.users :as users] 4 | [refheap.highlight :refer [lexers]] 5 | [refheap.utilities :refer [to-booleany escape-string pluralize safe-parse-long]] 6 | [noir.session :as session] 7 | [noir.response :refer [redirect content-type]] 8 | [stencil.core :as stencil] 9 | [me.raynes.laser :refer [defragment] :as l] 10 | [clojure.java.io :refer [resource]] 11 | [compojure.core :refer [defroutes GET POST]] 12 | [refheap.views.common :refer [layout avatar page-buttons static]] 13 | [refheap.dates :refer [date-string]] 14 | [clojure.string :refer [split join]])) 15 | 16 | (defn paste-url [paste & [suffix]] 17 | (if-let [version (:version paste)] 18 | (str "/" (:paste-id paste) "/history/" version suffix) 19 | (str "/" (:paste-id paste) suffix))) 20 | 21 | (defn paste-username [paste] 22 | (if-let [user (:user paste)] 23 | (:username (users/get-user-by-id user)) 24 | "anonymous")) 25 | 26 | (defragment paste-page-fragment (resource "refheap/views/templates/paste.html") 27 | [lang & [old]] 28 | (l/child-of (l/id= "language") 29 | (l/negate (l/attr? :selected))) 30 | (fn [node] 31 | (for [lang (sort #(.compareToIgnoreCase % %2) 32 | (keys (dissoc lexers lang)))] 33 | (l/on node (l/attr :value lang) (l/content lang)))) 34 | (l/attr? :selected) (let [lang (or lang (:language old) (session/get :last-lang) "Clojure")] 35 | (comp (l/attr :value lang) 36 | (l/content lang))) 37 | (l/element= :form) (l/attr :action (if old 38 | (paste-url old "/edit") 39 | "/create")) 40 | (when (:private old) 41 | [(l/attr= :name :private) (l/attr :checked "")]) 42 | (when old 43 | [(l/element= :textarea) (l/content (:raw-contents old))]) 44 | (l/id= :submit-button) (l/attr :value (if old "Save!" "Paste!"))) 45 | 46 | 47 | (let [head (static "refheap/views/templates/createhead.html")] 48 | (defn paste-page [lang & [old]] 49 | (layout 50 | (paste-page-fragment lang old) 51 | (when old 52 | (str "Editing paste " (:paste-id old))) 53 | head))) 54 | 55 | (def show-head (static "refheap/views/templates/showhead.html")) 56 | 57 | (let [head (static "refheap/views/templates/head.html") 58 | html (l/parse (resource "refheap/views/templates/fullscreen.html")) 59 | fullscreen #(l/document html 60 | (l/element= :head) (l/content [head show-head]) 61 | (l/class= :syntax) (l/content (l/unescaped %)))] 62 | (defn fullscreen-paste [id] 63 | (when-let [contents (:contents (paste/view-paste id))] 64 | (fullscreen contents))) 65 | (defn fullscreen-version [id version] 66 | (when-let [contents (:contents (paste/get-version (paste/get-paste id) version))] 67 | (fullscreen contents)))) 68 | 69 | (defragment show-paste-page-fragment (resource "refheap/views/templates/pasted.html") 70 | [{:keys [lines private user contents language date fork views] :as paste} paste-user] 71 | [user-id (:id (session/get :user)) 72 | forks (paste/count-forks paste) 73 | history (paste/count-history paste) 74 | current? (not (:version paste))] 75 | (l/id= :language) (l/content language) 76 | (l/id= :lines) (l/content (pluralize lines "line")) 77 | (l/id= :views) (if current? 78 | (l/content (pluralize views "view")) 79 | (l/remove)) 80 | (l/id= :forks) (if (and current? (pos? forks)) 81 | (l/content (l/node :a :attrs {:href (paste-url paste "/forks")} 82 | :content (pluralize forks "fork"))) 83 | (l/remove)) 84 | (l/id= :edits) (if (pos? history) 85 | (l/content (l/node :a :attrs {:href (paste-url 86 | (if current? 87 | paste 88 | (dissoc paste :version)) 89 | "/history")} 90 | :content (pluralize history "edit"))) 91 | (l/remove)) 92 | (when-not private 93 | [(l/class= :private) (l/remove)]) 94 | (l/id= :last) (l/content [(if fork "Forked by " "Pasted by ") 95 | (if user 96 | (l/node :a :attrs {:href (str "/users/" paste-user)} :content paste-user) 97 | paste-user) 98 | (when fork 99 | (l/unescaped 100 | (str " from " 101 | (if-let [paste (:paste-id (paste/get-paste-by-id fork))] 102 | (str "" paste "") 103 | "[deleted]")))) 104 | " on " 105 | (date-string date)]) 106 | (l/id= :embed) (if current? 107 | (l/attr :href (paste-url paste "/embed")) 108 | (l/remove)) 109 | (l/id= :raw) (l/attr :href (paste-url paste "/raw")) 110 | (l/id= :fullscreen) (l/attr :href (paste-url paste "/fullscreen")) 111 | (if (and current? (paste/same-user? (and user-id {:id user-id}) paste)) 112 | [(l/id= :owner) #(l/fragment (l/zip (:content %)) 113 | (l/id= "editb") (l/attr :href (paste-url paste "/edit")) 114 | (l/id= "delete") (l/attr :href (paste-url paste "/delete")))] 115 | [(l/id= :owner) (l/remove)]) 116 | (if (paste/same-user? (and user-id {:id user-id}) paste) 117 | [(l/attr= :name :forkform) (l/remove)] 118 | [(l/attr= :name :forkform) (l/attr :action (paste-url paste "/fork"))]) 119 | (l/id= :paste) (l/content (l/unescaped contents))) 120 | 121 | (defn show-paste-page [id] 122 | (when-let [paste (paste/view-paste id)] 123 | (let [paste-user (paste-username paste)] 124 | (layout 125 | (show-paste-page-fragment paste paste-user) 126 | (str paste-user "'s paste: " id) 127 | show-head)))) 128 | 129 | (defn show-version-page [id version] 130 | (let [current (paste/get-paste id)] 131 | (when-let [paste (paste/get-version current version)] 132 | (layout 133 | (show-paste-page-fragment 134 | (assoc paste :paste-id (:paste-id current) 135 | :history (:history current)) 136 | (paste-username paste)) 137 | (str "Version " version " of paste: " id) 138 | show-head)))) 139 | 140 | (defn paste-preview [node paste header] 141 | (let [{:keys [lines summary date user private]} paste] 142 | (l/at node 143 | (l/class= :more) (l/insert :left (l/unescaped summary)) 144 | (if (> lines 5) 145 | [(l/class= :more) (l/attr :href (paste-url paste))] 146 | [(l/class= :more) (l/remove)]) 147 | (l/class= :syntax) (l/insert :left header)))) 148 | 149 | (defragment render-paste-previews (resource "refheap/views/templates/preview.html") 150 | [pastes header-fn] 151 | (l/class= :preview-header) #(for [paste pastes] 152 | (paste-preview % paste (header-fn paste)))) 153 | 154 | (defragment embed-page-fragment (resource "refheap/views/templates/embed.html") 155 | [id host scheme] 156 | (l/id= :script) (l/content (str ""))) 157 | 158 | (defn embed-page [paste host scheme] 159 | (let [id (:paste-id paste)] 160 | (layout (embed-page-fragment id host scheme) 161 | (str "Embedding paste " id)))) 162 | 163 | (defn embed-paste [id host scheme lines?] 164 | (when-let [paste (paste/get-paste id)] 165 | (content-type 166 | "text/javascript" 167 | (stencil/render-file 168 | "refheap/views/templates/embedjs" 169 | {:id id 170 | :content (escape-string (:contents paste)) 171 | :url (str (name scheme) "://" host "/css/embed.css") 172 | :nolinenos (and lines? (not (to-booleany lines?)) {})})))) 173 | 174 | (defragment paste-header (resource "refheap/views/templates/allheader.html") 175 | [paste] 176 | [{:keys [paste-id date user]} paste] 177 | (l/id= :id) (comp (l/attr :href (paste-url paste)) 178 | (l/content (str "Paste " paste-id))) 179 | (l/class= :right) (l/content [(if-let [user (and user (:username (users/get-user-by-id user)))] 180 | (l/node :a :attrs {:href (str "/users/" user)} :content user) 181 | "anonymous") 182 | " on " 183 | (date-string date)])) 184 | 185 | (defn list-page [title url redirect-url list-count get-fn header-fn page] 186 | (if (> page (paste/count-pages list-count 20)) 187 | (redirect redirect-url) 188 | (layout 189 | (l/node :div :attrs {:class "clearfix"} 190 | :content (concat (render-paste-previews (get-fn page) header-fn) 191 | (page-buttons url list-count 20 page))) 192 | title 193 | show-head))) 194 | 195 | (defn all-pastes-page [page] 196 | (list-page "All pastes" 197 | "/pastes" 198 | "/paste" 199 | (paste/count-pastes false) 200 | paste/get-pastes 201 | paste-header 202 | page)) 203 | 204 | (defn forks-page [id page] 205 | (when-let [paste (paste/get-paste id)] 206 | (list-page (str "Forks of paste: " id) 207 | (paste-url paste "/forks") 208 | (paste-url paste) 209 | (paste/count-forks paste) 210 | (partial paste/get-forks paste) 211 | paste-header 212 | page))) 213 | 214 | (defragment version-header (resource "refheap/views/templates/allheader.html") 215 | [current paste] 216 | [{:keys [version date]} paste] 217 | (l/id= :id) (comp (l/attr :href 218 | (paste-url (assoc paste :paste-id (:paste-id current)))) 219 | (l/content (if version 220 | (str "Version " version) 221 | "Current"))) 222 | (l/class= :right) (l/content (date-string date))) 223 | 224 | (defn history-page [id page] 225 | (when-let [current (paste/get-paste id)] 226 | (list-page (str "History of paste: " id) 227 | (paste-url current "/history") 228 | (paste-url current) 229 | (paste/count-history current) 230 | (partial paste/get-history current) 231 | (partial version-header current) 232 | page))) 233 | 234 | (defn fail [error] 235 | (layout (l/node :p :attrs {:class "error"} :content error) "You broke it.")) 236 | 237 | (defn edit-paste-page [id] 238 | (let [paste (paste/get-paste id)] 239 | (when (paste/same-user? (session/get :user) paste) 240 | (paste-page nil paste)))) 241 | 242 | (defn fork-paste-page [id & [version]] 243 | (let [user (session/get :user) 244 | paste (if version 245 | (paste/get-version (paste/get-paste id) version) 246 | (paste/get-paste id))] 247 | (when (and paste (not (paste/same-user? user paste))) 248 | (let [forked (paste/paste (:language paste) 249 | (:raw-contents paste) 250 | (:private paste) 251 | user 252 | (:id paste))] 253 | (redirect (paste-url forked)))))) 254 | 255 | (defn delete-paste-page [id] 256 | (if-let [user (:user (paste/get-paste id))] 257 | (when (= user (session/get-in [:user :id])) 258 | (paste/delete-paste id) 259 | (redirect (str "/users/" (:username (session/get :user))))) 260 | (when (some #{id} (session/get :anon-pastes)) 261 | (paste/delete-paste id) 262 | (redirect "/pastes")))) 263 | 264 | (defn edit-paste [{:keys [id paste language private]}] 265 | (let [paste (paste/update-paste 266 | (paste/get-paste id) 267 | language 268 | paste 269 | private 270 | (session/get :user))] 271 | (if (map? paste) 272 | (redirect (paste-url paste)) 273 | (fail paste)))) 274 | 275 | (defn create-paste [{:keys [paste language private]} remote-addr] 276 | (let [user (assoc (session/get :user) :remote-addr remote-addr) 277 | paste (paste/paste language paste private user)] 278 | (if (map? paste) 279 | (redirect (paste-url paste)) 280 | (fail paste)))) 281 | 282 | (defroutes paste-routes 283 | (GET "/" [lang] 284 | (paste-page lang)) 285 | 286 | (GET "/pastes" [page] 287 | (all-pastes-page (paste/proper-page (safe-parse-long page 1)))) 288 | 289 | (GET "/:id/forks" [id page] 290 | (forks-page id (paste/proper-page (safe-parse-long page 1)))) 291 | 292 | (GET "/:id/history" [id page] 293 | (history-page id (paste/proper-page (safe-parse-long page 1)))) 294 | 295 | (GET "/:id/fullscreen" [id] 296 | (fullscreen-paste id)) 297 | 298 | (GET "/:id/edit" [id] 299 | (edit-paste-page id)) 300 | 301 | (POST "/:id/fork" [id] 302 | (fork-paste-page id)) 303 | 304 | (GET "/:id/delete" [id] 305 | (delete-paste-page id)) 306 | 307 | (GET "/:id/raw" [id] 308 | (when-let [content (:raw-contents (paste/get-paste id))] 309 | (content-type "text/plain; charset=utf-8" content))) 310 | 311 | (GET "/:id/embed" {{:keys [id]} :params 312 | {host "host"} :headers 313 | scheme :scheme} 314 | (let [paste (paste/get-paste id)] 315 | (embed-page paste host scheme))) 316 | 317 | (GET "/:id.js" {{:keys [id linenumbers]} :params 318 | {host "host"} :headers 319 | scheme :scheme} 320 | (embed-paste id host scheme linenumbers)) 321 | 322 | (GET "/:id" [id] 323 | (show-paste-page id)) 324 | 325 | (GET "/:id/history/:version" [id version] 326 | (show-version-page id (safe-parse-long version))) 327 | 328 | (GET "/:id/history/:version/fullscreen" [id version] 329 | (fullscreen-version id (safe-parse-long version))) 330 | 331 | (GET "/:id/history/:version/raw" [id version] 332 | (when-let [content (:raw-contents (paste/get-version 333 | (paste/get-paste id) 334 | (safe-parse-long version)))] 335 | (content-type "text/plain; charset=utf-8" content))) 336 | 337 | (GET "/:id/history/:version/fork" [id version] 338 | (fork-paste-page id (safe-parse-long version))) 339 | 340 | (POST "/:id/edit" {:keys [params]} 341 | (edit-paste params)) 342 | 343 | (POST "/create" {:keys [params remote-addr headers]} 344 | (create-paste params (or (get headers "x-forwarded-for") remote-addr))) 345 | 346 | ; Redirect legacy /paste/ prefixed URLs 347 | 348 | (GET ["/paste/:uri", :uri #".*"] {{:keys [uri]} :params 349 | query-string :query-string} 350 | (redirect (apply str "/" uri (when query-string ["?" query-string])))) 351 | 352 | (GET "/paste" {:keys [query-string]} 353 | (redirect (if query-string (str "/?" query-string) "/")))) 354 | -------------------------------------------------------------------------------- /src/refheap/views/templates/about.html: -------------------------------------------------------------------------------- 1 |
      2 |

      3 | RefHeap is a pastebin website that is written and designed by 4 | Anthony Grimes and 5 | Alex McNamara. The project 6 | began in late 2011 and was launched in early 2012. 7 |

      8 |

      9 | RefHeap was created for several reasons: 10 |

        11 |
      • We aren't entirely satisfied with existing pastebins
      • 12 |
      • We want to experiment with cool features that other pastebins may or 13 | may not have.
      • 14 |
      • We want to implement gist-like revision and forking features without using Git 15 | for paste storage.
      • 16 |
      • We wanted to write a pastebin with a focus on Clojure. A pastebin written 17 | in Clojure for Clojure. Using Pygments for syntax highlighting means we can 18 | also support a very large number of languages besides Clojure as well.
      • 19 |
      20 | Another motivation is to gain experience writing a non-trivial website in Clojure. 21 |

      22 |

      23 | RefHeap uses a number of technologies. First and foremost, it uses Pygments for 24 | syntax highlighting. Yes, we could have reinvented the wheel and rolled our own 25 | pygments-like for Clojure, but we would have ended up with an ultimately less stable 26 | tool that we would be forced to maintain and that would have support for a 27 | significantly smaller number of languages for quite a while. Pygments is an excellent 28 | tool and the author has been nothing but open to my contributions to improve its 29 | Clojure support. I think Pygments was a fine choice. 30 |

      31 |

      32 | RefHeap is constantly in development. There are numerous issues on our 33 | issue tracker and 34 | the majority of them are planned features. We are ambitious but we are also 35 | small. We are currently a core team of two with other responsibilities, so any 36 | help is certainly appreciated. One of the greatest things about RefHeap is that 37 | it is open source. If you want something to be added or changed, you've got a solid 38 | shot at making that happen. 39 |

      40 |

      41 | Why should you use RefHeap? It has a nice color scheme (based off of 42 | Tomorrow Night Bright) 43 | that is often tweaked to look prettier, support for a ton of languages, is open 44 | source and very easy to contribute to, has a simple API with libraries in Clojure 45 | and Ruby, editor support for both Vim and Emacs, a Ruby gem for pasting from the 46 | command-line, and an ambitious team with cool plans for its future. 47 |

      48 |
      49 | 50 | -------------------------------------------------------------------------------- /src/refheap/views/templates/all.html: -------------------------------------------------------------------------------- 1 |
      2 | {{{pastes}}} 3 | {{{paste-buttons}}} 4 |
      5 | -------------------------------------------------------------------------------- /src/refheap/views/templates/allheader.html: -------------------------------------------------------------------------------- 1 | 2 |
      3 |
      4 | -------------------------------------------------------------------------------- /src/refheap/views/templates/api.html: -------------------------------------------------------------------------------- 1 |
      2 |

      3 | RefHeap has a simple API for accessing and creating pastes. You can use this API without an 4 | account with RefHeap. However, if you want pastes that you create to be created under your 5 | account, you'll need to supply your username and an API token with the request. 6 | You want to keep this API token a secret. However, if you accidentally push it to Github 7 | or it is otherwise compromised, you can generate a new one at anytime. When you generate a new 8 | token, the old one no longer works. 9 |

      10 |

      11 | Check out the API documentation on Github! 12 |

      13 |
      14 | 15 | 16 |
      17 |

      Login to see your token.

      18 |
      19 | -------------------------------------------------------------------------------- /src/refheap/views/templates/apihead.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/refheap/views/templates/common.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/refheap/views/templates/commonbody.html: -------------------------------------------------------------------------------- 1 | 2 |
      3 | 17 |
      18 |
      19 |
      20 | 28 |
      29 |
      30 |
      31 |
      32 |

      33 | Did you know? 34 | CLOSE 35 |

      36 |
      37 |
        38 |
      • 39 | There are keyboard shortcuts! 40 |
          41 |
        • When Creating A Paste
        • 42 |
        • 43 |
            44 |
          • 45 | ALT+P 46 | Toggle Private 47 |
          • 48 |
          • 49 | CTRL+Enter 50 | Create Paste 51 |
          • 52 |
          • 53 | ALT+W 54 | Toggle word wrap 55 |
          • 56 |
          57 |
        • 58 |
        • When Viewing A Paste
        • 59 |
        • 60 |
            61 |
          • 62 | ALT+G 63 | Go to a line 64 |
          • 65 |
          • 66 | ALT+CTRL+E 67 | Edit the paste 68 |
          • 69 |
          • 70 | ALT+R 71 | Show the raw code 72 |
          • 73 |
          74 |
        • 75 |
        76 |
      • 77 |
      • 78 | There are URL options! 79 |
          80 |
        • 81 | When Creating A Paste 82 |
        • 83 |
        • 84 |
            85 |
          • 86 | ?lang=Javascript to default to javascript 87 |
          • 88 |
          89 |
        • 90 |
        • When Viewing A Paste
        • 91 |
        • 92 |
            93 |
          • #L-N Jump to line number N
          • 94 |
          95 |
        • 96 |
        97 |
      • 98 |
      99 |
      100 |
      101 | ? 102 |
      103 | 115 | 116 | -------------------------------------------------------------------------------- /src/refheap/views/templates/createhead.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/refheap/views/templates/createuser.html: -------------------------------------------------------------------------------- 1 |
      2 |

      3 |
      4 |

      You're almost there! Just enter a username and you'll be on your way.

      5 | 6 | 7 |
      8 |
      9 | -------------------------------------------------------------------------------- /src/refheap/views/templates/embed.html: -------------------------------------------------------------------------------- 1 |
      2 |

      Please copy the following html element onto your webpage, and change the 3 | size and styling as needed. If you pass linenumbers=0, the line numbers will 4 | be hidden.

      5 |

      6 |
      7 | -------------------------------------------------------------------------------- /src/refheap/views/templates/embedjs.mustache: -------------------------------------------------------------------------------- 1 | document.write('') 2 | 3 | document.write('
      {{{content}}}
      ') 4 | 5 | {{#nolinenos}} 6 | var d = document.getElementById("refh-{{id}}") 7 | d.className = d.className + " hide-lines" 8 | {{/nolinenos}} 9 | -------------------------------------------------------------------------------- /src/refheap/views/templates/fullscreen.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
      6 |
      7 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/refheap/views/templates/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/refheap/views/templates/loggedin.html: -------------------------------------------------------------------------------- 1 | {{username}} 2 | logout 3 | -------------------------------------------------------------------------------- /src/refheap/views/templates/loggedout.html: -------------------------------------------------------------------------------- 1 | BrowserID 2 | -------------------------------------------------------------------------------- /src/refheap/views/templates/pagination.html: -------------------------------------------------------------------------------- 1 |
      2 | newer 3 | older 4 |
      5 | -------------------------------------------------------------------------------- /src/refheap/views/templates/paste.html: -------------------------------------------------------------------------------- 1 |
      2 |
      3 |
      4 |
      5 | 9 | 10 | 18 | 19 |
      20 | 21 |
      22 |
      23 |
      24 | -------------------------------------------------------------------------------- /src/refheap/views/templates/pasted.html: -------------------------------------------------------------------------------- 1 |
      2 |
      3 |
        4 |
      • 5 |
      • 6 |
      • 7 |
      • 8 |
      • 9 |
      • Private
      • 10 |
      • 11 |
      • 12 |
      13 |
      14 | embed 15 | raw 16 | maximize 17 | 18 | edit 19 | delete 20 | 21 |
      22 | 23 |
      24 |
      25 |
      26 |
      27 |
      28 |
      29 | -------------------------------------------------------------------------------- /src/refheap/views/templates/preview.html: -------------------------------------------------------------------------------- 1 |
      2 |
      3 |
      4 | more... 5 |
      6 |
      7 |
      8 |
      9 | -------------------------------------------------------------------------------- /src/refheap/views/templates/privacy.html: -------------------------------------------------------------------------------- 1 |
      2 |

      Privacy Policy

      3 |

      4 | Internet use and communication is subject to attack, interception, loss and 5 | alteration. On whichever site you provide personal information, it is possible 6 | for a third party to view or later retrieve and/or modify that information. 7 | You acknowledge and agree that RefHeap, its maintainers, owners, and/or 8 | employees shall not be responsible for any damages you may suffer as a result 9 | of the transmission or storage of confidential or sensitive information 10 | communicated over the Internet or otherwise, and that all such communications 11 | will be at your own risk. Furthermore, RefHeap shall not be liable for 12 | maintaining the confidentiality of any communications between RefHeap’s 13 | representatives, affiliates, partners, users, or customers. 14 |

      15 |
      16 | -------------------------------------------------------------------------------- /src/refheap/views/templates/showhead.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/refheap/views/templates/tos.html: -------------------------------------------------------------------------------- 1 |
      2 |

      Terms of Service

      3 |

      4 | Under no circumstances, including, but not limited to, negligence, shall 5 | RefHeap or its affiliates be liable to you for any damages of any kind 6 | (including, but not limited to, compensatory damages, lost profits, lost 7 | data or any form of special, incidental, indirect, consequential or punitive 8 | damages whether based on breach of contract or warranty, tort, product 9 | liability or otherwise) that result from the use of, or the inability to 10 | use, this site or RefHeap’s products or services. You specifically 11 | acknowledge and agree that RefHeap is not liable for any defamatory, 12 | offensive or illegal conduct of any user, customer, or representative. 13 | If you are dissatisfied with any material or content on RefHeap’s web site, 14 | products, external communications, services, or with any of RefHeap’s terms 15 | and conditions, your sole and exclusive remedy is to discontinue using 16 | RefHeap and its web sites, products, and services. 17 |

      18 |
      19 | -------------------------------------------------------------------------------- /src/refheap/views/templates/userheader.html: -------------------------------------------------------------------------------- 1 | 2 |
      3 | (Private) 4 |
      5 | -------------------------------------------------------------------------------- /src/refheap/views/templates/users.html: -------------------------------------------------------------------------------- 1 |
      2 | gravatar 3 |
      4 | 5 | 6 |
      7 |
      8 |
      9 | -------------------------------------------------------------------------------- /src/refheap/views/users.clj: -------------------------------------------------------------------------------- 1 | (ns refheap.views.users 2 | (:require [refheap.models.users :as users] 3 | [refheap.views.paste :as paste] 4 | [refheap.utilities :refer [safe-parse-long]] 5 | [noir.session :as session] 6 | [compojure.core :refer [defroutes GET]] 7 | [refheap.views.common :refer [layout avatar page-buttons]] 8 | [refheap.dates :refer [date-string]] 9 | [noir.response :refer [redirect]] 10 | [refheap.models.paste :refer [count-pages proper-page get-pastes]] 11 | [me.raynes.laser :refer [defragment] :as l] 12 | [clojure.java.io :refer [resource]])) 13 | 14 | (defragment paste-header (resource "refheap/views/templates/userheader.html") 15 | [paste] 16 | [{:keys [paste-id date private]} paste] 17 | (l/element= :a) (comp (l/attr :href (str "/" paste-id)) 18 | (l/content (str "Paste " paste-id))) 19 | (when-not private 20 | [(l/element= :span) (l/remove)]) 21 | (l/element= :div) #(update-in % [:content] conj (date-string date))) 22 | 23 | (defragment user-page-fragment (resource "refheap/views/templates/users.html") 24 | [user page user-data] 25 | [you? (= user (:username (session/get :user))) 26 | others (when-not you? {:private false}) 27 | total (users/count-user-pastes user others)] 28 | (l/element= :img) (l/attr :src (avatar (:email user-data) 70)) 29 | (l/id= :header-data) (l/content [(if you? 30 | (str "You have ") 31 | (str user " has ")) 32 | (str (users/count-user-pastes user {:private false})) 33 | " public " 34 | (when you? 35 | (str "and " (users/count-user-pastes user {:private true}) " private ")) 36 | "pastes."]) 37 | (l/id= :pastes) (l/content 38 | (concat (paste/render-paste-previews (users/user-pastes user page others) paste-header) 39 | (page-buttons (str "/users/" user) total 10 page)))) 40 | 41 | (defn user-page [user page] 42 | (when-let [user-data (users/get-user user)] 43 | (layout 44 | (user-page-fragment user page user-data) 45 | (str user "'s pastes") 46 | paste/show-head))) 47 | 48 | (defroutes user-routes 49 | (GET "/users/:user" {{:keys [user page]} :params} 50 | (user-page (.toLowerCase user) 51 | (proper-page (safe-parse-long page 1))))) 52 | -------------------------------------------------------------------------------- /test/noir/test/core.clj: -------------------------------------------------------------------------------- 1 | (ns noir.test.core 2 | (:use [noir.core]) 3 | (:use [clojure.test])) 4 | 5 | (deftest replace-me ;; FIXME: write 6 | (is false "No tests have been written.")) 7 | --------------------------------------------------------------------------------