|
| 1 | +<!DOCTYPE html> |
| 2 | +<html > |
| 3 | +<head> |
| 4 | + |
| 5 | + <link rel=stylesheet type="text/css" href="http://synrc.com/synrc.css"> |
| 6 | + <meta name="Author" content="5HT"> |
| 7 | + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
| 8 | + <meta property="og:image" content="images/s_64.png"/> |
| 9 | + <meta http-equiv="X-UA-Compatible" content="IE=IE10,chrome=1" /> |
| 10 | + <title>N2O |
| 11 | +</title> |
| 12 | +</head> |
| 13 | +<body > |
| 14 | +<!--HEVEA command line is: hevea index.tex -o index.htm --> |
| 15 | +<!--CUT STYLE article--><!--HTMLHEAD--> |
| 16 | + |
| 17 | +<div class="nonselectedwrapper white" style="padding: 10px 0px 10px 0px;margin: 0px 0px 10px 0px;"> |
| 18 | + <a href="//synrc.com/"> |
| 19 | + <img style="float:left; margin-left: 55px; margin-top: 5px; margin-bottom:-5px;" src="http://synrc.com/images/synrc.png" border="0"></a> |
| 20 | + |
| 21 | + <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top" style="display:none;margin-top:39px;"> |
| 22 | + <input type="hidden" name="cmd" value="_s-xclick"> |
| 23 | + <input type="hidden" name="hosted_button_id" value="P8WQHAQK5HWWW"> |
| 24 | + <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" border="0" name="submit" style="width:74px;margin-top:0px;"> |
| 25 | + </form> |
| 26 | + |
| 27 | + <div align=right style="float:right;width:700px;height: auto; margin: 20px 50px 0px 0px;"> |
| 28 | + <script type="text/javascript"> |
| 29 | + |
| 30 | + var args = (window.location).toString().split('/'); |
| 31 | + var page_name = args[args.length-1]; |
| 32 | + var menu = {'http://synrc.com/index.htm': 'Home', |
| 33 | + 'http://synrc.com/research.htm': 'Showcase', |
| 34 | + 'http://synrc.com/apps/': 'Apps', |
| 35 | + 'http://synrc.com/feedback.htm': 'Contacts', |
| 36 | + 'http://spawnproc.com': '<b>Spawnproc</b>', }; |
| 37 | + |
| 38 | + Object.keys(menu).forEach(function (key) { |
| 39 | + if (page_name == key) { document.write('<div class="menu" style="font-weight: bold;">'+menu[key]+'</div>'); } |
| 40 | + else { document.write('<a class="menu" href="'+key+'">'+menu[key]+'</a>'); } |
| 41 | + }); |
| 42 | + |
| 43 | + </script> |
| 44 | + </div> |
| 45 | +</div> |
| 46 | + |
| 47 | +<hr size="1"> |
| 48 | + |
| 49 | +<!--ENDHTML--> |
| 50 | +<!--CUT DEF section 1 --><div class="nonselectedwrapper"> |
| 51 | +<div class="article"> |
| 52 | +<div class="toc"> |
| 53 | +<!--TOC section id="sec1" TOC--> |
| 54 | +<h2 id="sec1" class="section">TOC</h2><!--SEC END --> |
| 55 | +<!--TOC paragraph id="sec2" --> |
| 56 | +<!--SEC END --><p> |
| 57 | +<a href="http://synrc.com/apps/n2o/doc/web">1. Framework</a> <br> |
| 58 | + |
| 59 | +<a href="http://synrc.com/apps/n2o/doc/web/setup.htm">2. Setup</a> <br> |
| 60 | + |
| 61 | +<a href="http://synrc.com/apps/n2o/doc/web/processes.htm">3. Processes</a> <br> |
| 62 | + |
| 63 | +<a href="http://synrc.com/apps/n2o/doc/web/endpoints.htm">4. Endpoints</a> <br> |
| 64 | + |
| 65 | +<a href="http://synrc.com/apps/n2o/doc/web/handlers.htm">5. Handlers</a> <br> |
| 66 | + |
| 67 | +<a href="http://synrc.com/apps/n2o/doc/web/protocols.htm">6. Protocols</a> <br> |
| 68 | + |
| 69 | +<a href="http://synrc.com/apps/n2o/doc/web/api.htm">7. API</a> <br> |
| 70 | + |
| 71 | +<a href="http://synrc.com/apps/n2o/doc/web/elements.htm">8. Elements</a> <br> |
| 72 | + |
| 73 | +<a href="http://synrc.com/apps/n2o/doc/web/actions.htm">9. Actions</a> <br> |
| 74 | + |
| 75 | +<a href="http://synrc.com/apps/n2o/doc/web/macros.htm">10. JavaScript</a> <br> |
| 76 | + |
| 77 | +<a href="http://synrc.com/apps/n2o/doc/web/utf8.htm">11. UTF-8</a> <br> |
| 78 | + |
| 79 | +<a href="http://synrc.com/apps/n2o/doc/web/packages.htm">12. Packages</a> <br> |
| 80 | + |
| 81 | +<a href="http://synrc.com/apps/n2o/doc/web/persistence.htm">13. Persistence</a> <br> |
| 82 | + |
| 83 | +<a href="http://synrc.com/apps/n2o/doc/web/last.htm">14. History</a> <br> |
| 84 | + |
| 85 | +<a href="http://synrc.com/apps/n2o/doc/book.pdf">Download PDF</a> <br> |
| 86 | + |
| 87 | +</p></div> |
| 88 | + |
| 89 | +<div class="articlecol"> |
| 90 | + |
| 91 | +<!--TOC section id="sec3" N2O: Application Server--> |
| 92 | +<h2 id="sec3" class="section">N2O: Application Server</h2><!--SEC END --><p>N2O was started as the first Erlang Web Framework |
| 93 | +that uses WebSocket protocol only. We saved great compatibility with Nitrogen |
| 94 | +and added many improvements, such as binary page construction, |
| 95 | +binary data transfer, minimized process spawns, transmission of all events over the WebSocket |
| 96 | +and work within Cowboy processes. N2O renders pages several times faster than Nitrogen.</p> |
| 97 | +<!--TOC subsection id="sec4" Wide Coverage--> |
| 98 | +<h3 id="sec4" class="subsection">Wide Coverage</h3><!--SEC END --><p> |
| 99 | +N2O is unusual in that it solves problems in different web development domains |
| 100 | +and stays small and concise at the same time. Started as a Nitrogen concept |
| 101 | +of server-side framework it can also build offline client-side applications |
| 102 | +using the same source code. This became possible with powerful Erlang JavaScript Parse |
| 103 | +Transform which enables running Erlang on JavaScript platform and brings in Erlang and JavaScript |
| 104 | +interoperability. You can use Elixir, LFE and Joxa languages for backend development as well.</p> |
| 105 | +<!--TOC paragraph id="sec5" --> |
| 106 | +<!--SEC END --><p> |
| 107 | +N2O supports DSL and HTML templates. It lets you build JavaScript |
| 108 | +control elements in Erlang and perform inline rendering with DSL using |
| 109 | +the same code base for both client and server-side. |
| 110 | +How to use N2O is up to you. You can build mobile applications using server-side rendering |
| 111 | +for both HTML and JavaScript thus reducing CPU cycles and saving the battery of a mobile device. |
| 112 | +Or you can create rich offline desktop applications using Erlang JavaScript compiler.</p><!--TOC subsection id="sec6" Why Erlang in Web?--> |
| 113 | +<h3 id="sec6" class="subsection">Why Erlang in Web?</h3><!--SEC END --><p> |
| 114 | +We have benchmarked all the existing modern web frameworks that were built using functional |
| 115 | +languages and Cowboy was still the winner. The chart below shows raw HTTP |
| 116 | +performance of functional and C-based languages with concurrent |
| 117 | +primitives (Go, D and Rust) on a VAIO Z notebook with i7640M processor.</p><p> |
| 118 | + |
| 119 | +<img src="http://synrc.com/apps/n2o/doc/images/n2o_benchmark.png" style="margin-left: -20px;margin-botton: 30px; padding:20 20 20 20px;"><br> |
| 120 | + |
| 121 | +Picture. <span style="font-weight:bold">Web-Servers raw performance grand congregation</span><br> |
| 122 | +<br> |
| 123 | + |
| 124 | + |
| 125 | + |
| 126 | +Erlang was built for low latency streaming of binary data in telecom systems. |
| 127 | +It’s fundamental design goal included high manageability, scalability |
| 128 | +and extreme concurrency. Thinking of WebSocket channels as binary |
| 129 | +telecom streams and web pages as user binary sessions |
| 130 | +helps to get an understanding reasons behind choosing Erlang |
| 131 | +over other alternatives for web development.</p> |
| 132 | +<!--TOC paragraph id="sec7" --> |
| 133 | +<!--SEC END --><p> |
| 134 | +Using Erlang for web allows you to unleash the full power of telecom systems for |
| 135 | +building web-scale, event-driven, message-passing, NoSQL, asynchronous, non-blocking, |
| 136 | +reliable, highly-available, performant, secure, real-time, distributed applications. |
| 137 | +See Erlang: The Movie II.</p> |
| 138 | +<!--TOC paragraph id="sec8" --> |
| 139 | +<!--SEC END --><p> |
| 140 | +N2O outperforms full Nitrogen stack with only 2X raw HTTP Cowboy |
| 141 | +performance downgrade thus upgrading rendering performance several |
| 142 | +times compared to any other functional web framework. And |
| 143 | +sure it’s faster than raw HTTP performance of Node.js.</p> |
| 144 | +<!--TOC subsection id="sec9" Rich and Lightweight Applications--> |
| 145 | +<h3 id="sec9" class="subsection">Rich and Lightweight Applications</h3><!--SEC END --><p> |
| 146 | +There are two approaches for designing client/server communication. |
| 147 | +The first one is called ’data-on-wire’. With this approach only JSON, XML or binary |
| 148 | +data are transferred over RPC and REST channels. All HTML rendering |
| 149 | +is performed on the client-side. This is the most suitable approach for building desktop |
| 150 | +applications. Examples include React, Meteor and ClojureScript. |
| 151 | +This approach can also be used for building mobile clients.</p> |
| 152 | +<!--TOC paragraph id="sec10" --> |
| 153 | +<!--SEC END --><p> |
| 154 | +Another approach is sending pre-rendered parts of pages and JS |
| 155 | +and then replacing HTML and executing JavaScript on the client-side. This approach |
| 156 | +is better suited for mobile web development since the |
| 157 | +client doesn’t have much resources.</p> |
| 158 | +<!--TOC paragraph id="sec11" --> |
| 159 | +<!--SEC END --><p> |
| 160 | +With N2O you can create both types of applications. You can use N2O REST framework |
| 161 | +for desktop applications based on Cowboy REST API along with DTL |
| 162 | +templates for initial HTML rendering for mobile applications. |
| 163 | +You can also use Nitrogen DSL-based approach for modeling parts of pages |
| 164 | +as widgets and control elements, thanks to Nitrogen |
| 165 | +rich collection of elements provided by Nitrogen community.</p> |
| 166 | +<!--TOC paragraph id="sec12" --> |
| 167 | +<!--SEC END --><p> |
| 168 | +In cases when your system is built around Erlang infrastructure, N2O |
| 169 | +is the best choice for fast web prototyping, bringing simplicity |
| 170 | +of use and clean codebase. Despite HTML being transfered over the wire, |
| 171 | +you still have access to all your Erlang services directly.</p> |
| 172 | +<!--TOC paragraph id="sec13" --> |
| 173 | +<!--SEC END --><p> |
| 174 | +You can also create offline applications using Erlang JavaScript compiler |
| 175 | +just the way you would use ClojureScript, Scala.js, Elm, WebSharper |
| 176 | +or any other similar tool. N2O includes: REST micro frameworks, |
| 177 | +server-side and client-side rendering engines, |
| 178 | +WebSocket events streaming, JavaScript generation |
| 179 | +and JavaScript macro system along with <span style="font-weight:bold">AVZ</span> authorization |
| 180 | +library (Facebook, Google, Twitter, Github, Microsoft), key-value storages |
| 181 | +access library <span style="font-weight:bold">KVS</span> and <span style="font-weight:bold">MQS</span> Message Bus client library (gproc, emqttd).</p> |
| 182 | +<!--TOC subsection id="sec14" JSON and BERT--> |
| 183 | +<h3 id="sec14" class="subsection">JSON and BERT</h3><!--SEC END --><p> |
| 184 | +N2O uses JSON and BERT. All messages passed over |
| 185 | +WebSockets are encoded in native Erlang External Term Format. |
| 186 | +It is easy to parse it in JavaScript with <span style="font-weight:bold">dec(msg)</span> |
| 187 | +and it helps to avoid complexity on the server-side. Please refer |
| 188 | +to <a href="http://bert-rpc.org">http://bert-rpc.org</a> for detailed information.</p> |
| 189 | +<!--TOC subsection id="sec15" DSL and Templates--> |
| 190 | +<h3 id="sec15" class="subsection">DSL and Templates</h3><!--SEC END --><p> |
| 191 | +We like Nitrogen for the simple and elegant way it constructs typed |
| 192 | +HTML with internal DSL. This is analogous to Scala Lift, |
| 193 | +OCaml Ocsigen and Haskell Blaze approach. It lets you develop reusable control |
| 194 | +elements and components in the host language.</p> |
| 195 | +<!--TOC paragraph id="sec16" --> |
| 196 | +<!--SEC END --><p> |
| 197 | +Template-based approach (Yesod, ASP, PHP, JSP, Rails, Yaws and ChicagoBoss) |
| 198 | +requires developers to deal with raw HTML. It allows |
| 199 | +defining pages in terms of top-level controls, placeholders |
| 200 | +and panels. N2O also support this approach by proving bindings |
| 201 | +to DTL and ET template engines.</p> |
| 202 | +<!--TOC paragraph id="sec17" --> |
| 203 | +<!--SEC END --><p> |
| 204 | +The main N2O advantage is its suitability for large-scale projects |
| 205 | +without sacrificing simplicity and comfort of prototyping solutions |
| 206 | +in fast and dynamic manner. Below is an example of complete Web Chat |
| 207 | +implementation using WebSockets that shows how Templates, DSL and |
| 208 | +asynchronous inter-process communication work in N2O.</p><div class="center">Listing 1: chat.erl</div><p><br> |
| 209 | +</p><div class="lstlisting"> -module(chat). |
| 210 | + -include_lib("nitro/include/nitro.hrl"). |
| 211 | + -compile(export_all). |
| 212 | + |
| 213 | + main() -> |
| 214 | + #dtl { file = "login", |
| 215 | + app = review, |
| 216 | + bindings = [ { body, body() } ] }. |
| 217 | + |
| 218 | + body() -> |
| 219 | + [ #span { id=title, body="Your nickname: " }, |
| 220 | + #textbox { id=user, body="Anonymous" }, |
| 221 | + #panel { id=history }, |
| 222 | + #textbox { id=message }, |
| 223 | + #button { id=send, source=[user,message], |
| 224 | + body="Send", |
| 225 | + postback=chat } ]. |
| 226 | + |
| 227 | + event(init) -> wf:reg(room), wf:async("looper",fun loop/1); |
| 228 | + event(chat) -> User = wf:q(user), |
| 229 | + Message = wf:q(message), |
| 230 | + n2o_async:send("looper",{chat,User,Message}). |
| 231 | + |
| 232 | + loop({chat,User,Message}) -> |
| 233 | + Terms = #panel { body = [ |
| 234 | + #span { body = User }, ": ", |
| 235 | + #span { body = Message } ]}, |
| 236 | + wf:insert_bottom(history, Terms), |
| 237 | + wf:flush(room).</div><p>Just try to build the similar functionality with your favorite |
| 238 | +language/framework and feel the difference! Here are one message bus, |
| 239 | +one async <span style="font-weight:bold">gen_server</span> worker under supervision, NITRO DSL, DTL template, |
| 240 | +WebSockets, HTML and JavaScript generation in a simple file that you can |
| 241 | +put in your N2O application directory tree without restart and |
| 242 | +manual compilation. Also you can create single-file bundle |
| 243 | +which is able to run in Windows, Linux and Mac. Moreover this |
| 244 | +application is ready to run under multiplatform LING Erlang virtual machine.</p><!--TOC subsection id="sec18" Changes from Nitrogen--> |
| 245 | +<h3 id="sec18" class="subsection">Changes from Nitrogen</h3><!--SEC END --><p> |
| 246 | +We took a liberty to break some compatibility with the original |
| 247 | +Nitrogen framework, mostly because we wanted to have a clean codebase |
| 248 | +and achieve better performance. However, it’s still possible to port |
| 249 | +Nitrogen web sites to N2O quite easily. E.g., N2O returns id and |
| 250 | +class semantics of HTML and not <span style="font-weight:bold">html_id</span>. |
| 251 | +We simplified HTML rendering without using |
| 252 | +<span style="font-weight:bold">html_encode</span> which should be handled by application layer.</p> |
| 253 | +<!--TOC paragraph id="sec19" --> |
| 254 | +<!--SEC END --><p> |
| 255 | +Nitrogen.js, originally created by Rusty Klophaus, was removed |
| 256 | +because of the pure WebSocket nature of N2O which doesn’t |
| 257 | +require jQuery on the client-side anymore. In terms of lines of code |
| 258 | +we have impressive showing. New <span style="font-weight:bold">xhr.js</span> 25 LOC and <span style="font-weight:bold">bullet.js</span> 18 LOC |
| 259 | +was added as the replacement, also <span style="font-weight:bold">nitrogen.js</span> takes only 45 LOC. |
| 260 | +UTF-8 <span style="font-weight:bold">utf8.js</span> 38 LOC could be plugged separately only when you’re |
| 261 | +using <span style="font-weight:bold">bert.js</span> 200 LOC formatter. <span style="font-weight:bold">n2o.js</span> protocol handler is about 20 LOC.</p> |
| 262 | +<!--TOC paragraph id="sec20" --> |
| 263 | +<!--SEC END --><p> |
| 264 | +We also removed <span style="font-weight:bold">simple_bridge</span> and optimized N2O on each level to |
| 265 | +unlock maximum performance and simplicity. We hope you will enjoy |
| 266 | +using N2O. We are fully convinced it is the most efficient way to |
| 267 | +build Web applications in Erlang.</p> |
| 268 | +<!--TOC paragraph id="sec21" --> |
| 269 | +<!--SEC END --><p> |
| 270 | +Original Nitrogen was already tested in production under high load and we |
| 271 | +decided to remove <span style="font-weight:bold">nprocreg</span> process registry along |
| 272 | +with <span style="font-weight:bold">action_comet</span> heavy process creation. N2O creates a single |
| 273 | +process for an async WebSocket handler, all operations |
| 274 | +are handled within Cowboy processes.</p> |
| 275 | +<!--TOC paragraph id="sec22" --> |
| 276 | +<!--SEC END --><p> |
| 277 | +Also, we introduced new levels of abstraction. You can extend |
| 278 | +the set of available protocols (Nitrogen, Heartbeat, Binary), |
| 279 | +change protocol formatters to BERT, JSON or MessagePack, inject |
| 280 | +your code on almost any level. The code structure |
| 281 | +is clean and Nitrogen compatibility layer NITRO is fully detachable |
| 282 | +from N2O and lives in a separate <span style="font-weight:bold">synrc/nitro</span> application. |
| 283 | + |
| 284 | +<br><br> |
| 285 | +<h2><a name="testimonials"><b>N2O in Production</b></a></h2><blockquote>In this framework, most of all I liked the fact that most of the |
| 286 | +tasks solving in one code, in one language. And is not spread to the |
| 287 | +front-end & back-end.<div align=right>Alex Radetsky, |
| 288 | +<a href="http://pearlpbx.com/">PearlPBX</a></div></blockquote> |
| 289 | + |
| 290 | +<blockquote>Writing asynchronous web-applications has never been so easy for me. |
| 291 | +Now I really like to push data to client!<div align=right>Max Treskin, |
| 292 | +<a href="http://metachord.com/">Metachord</a></div></blockquote> |
| 293 | + |
| 294 | +<blockquote>N2O is the easiest way how to write different webapps. It just works. |
| 295 | +<div align=right>Alexander Karpich, |
| 296 | +<a href="http://rontel.ru/">RON-Telecom CJSC</a></div></blockquote> |
| 297 | + |
| 298 | +<blockquote>N2O is nice way to deal with WebSockets. |
| 299 | +<div align=right>Roman Gladkov |
| 300 | +<a href="http://crashkeeper.com/">Crashkeeper, Inc.</a></div></blockquote> |
| 301 | + |
| 302 | +<h2><a name="trendsetters"><b>Erlang Trendsetters on N2O</b></a></h2> |
| 303 | + |
| 304 | +<!--blockquote>This [N2O] makes Websockets so easy. Thanks for this, it's great. |
| 305 | +<div align=right>Joe Armstrong, |
| 306 | +<a href="http://ericsson.com/">Ericsson AG</a></div></blockquote--> |
| 307 | + |
| 308 | +<blockquote>Excited to see these guys pushing boundaries; that's exactly what |
| 309 | +inspired Nitrogen in the first place. My hat is off to the <a href="http://synrc.com">synrc.com</a> |
| 310 | +team for their work on N2O... |
| 311 | +<div align=right style="margin-top: 10px;">Rusty Klophaus, Nitrogen author, |
| 312 | +<a href="http://basho.com/">Basho Technologies, Inc.</a></div></blockquote> |
| 313 | + |
| 314 | +<blockquote>N2O is one of the most interesting Cowboy based frameworks. |
| 315 | +<div align=right style="margin-top: 10px;">Loïc Hoguin, Cowboy, |
| 316 | +<a href="http://ninenines.eu/">Nine Nines</a></div></blockquote> |
| 317 | + |
| 318 | +<br><center> |
| 319 | +<iframe src="http://slid.es/maximsokhatsky/n2o/embed" width="600" height="400" scrolling="no" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> |
| 320 | +</center><br> |
| 321 | + |
| 322 | + |
| 323 | + <!--div id="disqus_thread"></div> |
| 324 | + <script type="text/javascript"> |
| 325 | + var disqus_shortname = 'synrc'; // required: replace example with your forum shortname |
| 326 | + (function() { |
| 327 | + var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; |
| 328 | + dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; |
| 329 | + (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); |
| 330 | + })(); |
| 331 | + </script> |
| 332 | + <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> |
| 333 | + <a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a--> |
| 334 | + |
| 335 | + |
| 336 | +</p></div> |
| 337 | +</div> |
| 338 | +</div><div class="clear"> </div><!--CUT END --> |
| 339 | +<!--HTMLFOOT--> |
| 340 | + |
| 341 | +<div class="nonselectedwrapper"> |
| 342 | +<div class="verywidecol"> |
| 343 | + |
| 344 | + <div style="width:100%;height:300px;float:left;font-size:16pt;" align=center> |
| 345 | + <hr size=1> |
| 346 | + <br><br><br> |
| 347 | + <a href="//synrc.com/news/index.htm">Events</a> | |
| 348 | + <a href="//synrc.com/privacy.htm">Privacy Policy</a> | |
| 349 | + <a href="//synrc.com/feedback.htm">Feedback</a> | |
| 350 | + <a href="//synrc.com/brandbook.htm">Brandbook</a><br> |
| 351 | + Copyright © 2005–2016 <a href="//synrc.com/index.htm"> Synrc Research Center s.r.o.</a> |
| 352 | + </div> |
| 353 | + |
| 354 | +</div> |
| 355 | +</div> |
| 356 | + |
| 357 | + |
| 358 | +<div class="clear"></div> |
| 359 | + |
| 360 | +<script type="text/javascript"> |
| 361 | + |
| 362 | + var _gaq = _gaq || []; |
| 363 | + _gaq.push(['_setAccount', 'UA-29227518-1']); |
| 364 | + _gaq.push(['_trackPageview']); |
| 365 | + |
| 366 | + (function() { |
| 367 | + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| 368 | + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js'; |
| 369 | + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| 370 | + })(); |
| 371 | + |
| 372 | + </script> |
| 373 | + |
| 374 | +<script type="text/javascript" src="http://synrc.com/hi.js"></script> |
| 375 | +<!--ENDHTML--> |
| 376 | +</body> |
| 377 | +</html> |
0 commit comments