SlideShare a Scribd company logo
Mastering Large Scale
JavaScript Applications
Fabian Jakobs
About



•   Senior JavaScript Developer at 1&1

•             core developer since 2006


               @fjakobs
Man With Two Hats
Framework   Application
Large Scale
JavaScript Applications
JavaScript Application
JavaScript Application
JavaScript Application
JavaScript Application
JavaScript Application

•   Single Page Application

•   Client Logic in JavaScript

•   Client-Server
    Communication with
    AJAX calls
Large Scale

• Complexity and Size of JavaScript code
 • ~ 150,000 LOC
 • ~ 1000 Classes
Masterin Large Scale Java Script Applications
• Rich Web Mail Application

• Pure JavaScript Client
• Backend Communication with Ajax calls
• Based on qooxdoo
• Client-side JavaScript Framework
• Cross-browser web applications
• Open Source
JavaScript isn‘t made for this
JavaScript isn‘t made
         for this
• No package mechanism
• By default everything is in the global
  namespace
• Only basic building blocks for OOP
• Tooling still sucks
Everybody puts a layer
       on top
• GWT covers JavaScript with Java
• Cappuchino uses Objective-J
• Adobe invented ActionScript
• Everyone else uses (different) meta object
  systems written in JavaScript
qooxdoo OOP
qx.Class.define("demo.Person",
{
  extend : qx.core.Object,

  construct : function(firstName, lastName)
  {
	     this.base(arguments);	
	
	     this._firstName = firstName;
	     this._lastName = lastName;
  },

  members :
  {
    getFullName : function() {
      return this._firstName + " " + this._lastName;
    }
  }
});
Tooling
Tooling

  API Doc                    Unit Testing
                  Linker
Auto Completion            Code Coverage
                    Lint


         IDE Support
Tooling dilemma
• Different OOP syntax makes generic
  tooling hard
• Tools often depend in certain Framework
  features


• Don‘t just look at the widgets, look at the
  development tools as well
Find the Right Level of
      Abstraction
Desktop Like Web
 Applications Need
Desktop Abstractions

• Widgets               • DOM Nodes
• Layout Manager   vs   • CSS
• Themes                • Browser Bugs
Abstractions
                            Application
  Application Components

      Custom Widgets


       Base Widgets         Framework
         UI Core
     (Rendering Engine)

 BOM (Cross Browser Code)

   Core (JavaScript OOP)
Desktop Style
       Development Model

// Create a button
var button = new qx.ui.form.Button("First Button", "demo/browser.png");

// Add button to container at fixed coordinates
container.add(button, {left: 100, top: 50});

// Add an event listener
button.addListener("execute", function(e) {
  alert("Hello World!");
});
Leaky Abstractions
• Emulated behavior may be slower
 • e.g. Canvas wrapper for IE
• For advanced tasks its essential to know
  the lower layers
  • CSS, HMTL, DOM knowledge is still
    needed
Styling
Styling
No OS clone!   No default theme   Everything Custom!
Masterin Large Scale Java Script Applications
Not Everyone
Speaks German
i18n
i18n
i18n
i18n in qooxdoo
this button = var qx.ui.form.Button(this.tr("Hello World!"));




      • Standards
       • gettext
       • CLDR
      • good external tooling
      • known by professional translators
Performance
Our Bottlenecks

• Startup time
• Widget creation
• Table scroll performance
Startup Time
  The 3Cs + O


  • Combine
  • Compress
  • Cache
  • On demand
Combine

• reduce number of requests
• combine                  JS        JS   PNG     PNG
 • JavaScript files
 • CSS                          JS              PNG
 • Images
Compress

• optipng et el for images
• compress JavaScript
• serve with gzip
Compress JavaScript
Cache

• Serve static files with „cache forever“
 • Increase version number if content
    changes
• Use Image servers
On Demand

• Defer operations
 • Load Code on demand
 • Load Data on demand
 • Render UI on demand
On Demand Code

• The initial view does not need
 • Editor
 • Settings
 • Address book
 • ...
On Demand Code
   • Code
qx.io.PartLoader.require("settings", function()
{
  mailclient.ui.SettingsDialog.getInstance().open();
}, this);



   • Content
...
"packages" : {
  "parts" : {
    "settings": {
      "include" : ["mailclient.ui.SettingsDialog"]
    }
  }
}
...
On Demand Data and UI

• Thousands of mails
  in the inbox
• Only load visible
  data
• Only render visible
  rows of the table
Widget Creation
• DOM operations are expensive
• Creation Widgets is expensive
• Reuse Widgets
 • Share Widgets
 • Pool Widgets
• Increases Complexity!
Reuse Widgets



pool and reuse               share mail preview
  mail folder                   among tabs
Clean Code
Decouple UI
Components
Decouple UI
Components




   Message Bus
Code Should be
Executable in Isolation

• Without rebuilding the application
• Without restarting the application
• Without a server
Unit Tests
Mini Applications
Summary

• Good Abstractions
• Styling
• Internationalization
• Performance
• Clean Code
colorstrip.gifT
THE NEW ERA OF WEB DEVELOPMENT




Thank you.

                                Fabian Jakobs
                                    @fjakobs
                <fabian.jakobs@1und1.de>
                         http://qooxdoo.org
Fotos
•   http://www.flickr.com/photos/martin_uj/2505238011/

•   http://www.flickr.com/photos/born-clothing/3764261653/

•   http://www.flickr.com/photos/countrushmore/540548338/

•   http://www.flickr.com/photos/gordonr/42555739/

•   http://www.flickr.com/photos/evaekeblad/345203452/

•   http://www.flickr.com/photos/oldonliner/1095360979/

•   http://www.flickr.com/photos/imcomkorea/3496427357/

•   http://www.flickr.com/photos/nhr/460382116/

•   http://www.flickr.com/photos/evaekeblad/345203452/
Ad

Recommended

PPTX
Angular.js in XPages
Mark Roden
 
PDF
Why use Go for web development?
Weng Wei
 
PDF
Modern javascript
Kevin Ball
 
PDF
Adobe AEM for Business Heads
Yash Mody
 
PPTX
Iconus 2016
Mark Roden
 
PDF
Server Check.in case study - Drupal and Node.js
Jeff Geerling
 
PDF
Back to the 90s' - Revenge of the static website
Yves Goeleven
 
PDF
React server side rendering performance
Nick Dreckshage
 
PDF
Isomorphic web application
Oliver N
 
PPTX
Untangling - fall2017 - week 8
Derek Jacoby
 
PPTX
Untangling - fall2017 - week 7
Derek Jacoby
 
PPTX
Agile sites @ telmore
Michele Sciabarrà
 
PPTX
Agile sites2
Michele Sciabarrà
 
PPTX
Untangling spring week5
Derek Jacoby
 
PDF
Agile sites311training
Michele Sciabarrà
 
PDF
Web Performance Part 4 "Client-side performance"
Binary Studio
 
PDF
Building Enterprise Grade Front-End Applications with JavaScript Frameworks
FITC
 
PPTX
Untangling spring week4
Derek Jacoby
 
PDF
Client vs Server Templating: Speed up initial load for SPA with Angular as an...
David Amend
 
PPTX
[Srijan Wednesday Webinars] Developing Large Scale Applications in AngularJS
Srijan Technologies
 
PPTX
Ci of js and apex using jasmine, phantom js and drone io df14
Kevin Poorman
 
PPTX
Untangling spring week10
Derek Jacoby
 
PPTX
How NOT to get lost in the current JavaScript landscape
Radosław Scheibinger
 
PPTX
WebGL: Yesterday, Today, Tomorrow
Bogdan Gorpynchuk
 
KEY
Capybara-Webkit
bostonrb
 
KEY
Rapid development with Rails
Yi-Ting Cheng
 
PDF
Back to the future with static site generators
Chris Ward
 
PPTX
Untangling spring week9
Derek Jacoby
 
PPTX
JS Essence
Uladzimir Piatryka
 
PPTX
JavaOne2016 - How to Generate Customized Java 8 Code from Your Database [TUT4...
Speedment, Inc.
 

More Related Content

What's hot (20)

PDF
Isomorphic web application
Oliver N
 
PPTX
Untangling - fall2017 - week 8
Derek Jacoby
 
PPTX
Untangling - fall2017 - week 7
Derek Jacoby
 
PPTX
Agile sites @ telmore
Michele Sciabarrà
 
PPTX
Agile sites2
Michele Sciabarrà
 
PPTX
Untangling spring week5
Derek Jacoby
 
PDF
Agile sites311training
Michele Sciabarrà
 
PDF
Web Performance Part 4 "Client-side performance"
Binary Studio
 
PDF
Building Enterprise Grade Front-End Applications with JavaScript Frameworks
FITC
 
PPTX
Untangling spring week4
Derek Jacoby
 
PDF
Client vs Server Templating: Speed up initial load for SPA with Angular as an...
David Amend
 
PPTX
[Srijan Wednesday Webinars] Developing Large Scale Applications in AngularJS
Srijan Technologies
 
PPTX
Ci of js and apex using jasmine, phantom js and drone io df14
Kevin Poorman
 
PPTX
Untangling spring week10
Derek Jacoby
 
PPTX
How NOT to get lost in the current JavaScript landscape
Radosław Scheibinger
 
PPTX
WebGL: Yesterday, Today, Tomorrow
Bogdan Gorpynchuk
 
KEY
Capybara-Webkit
bostonrb
 
KEY
Rapid development with Rails
Yi-Ting Cheng
 
PDF
Back to the future with static site generators
Chris Ward
 
PPTX
Untangling spring week9
Derek Jacoby
 
Isomorphic web application
Oliver N
 
Untangling - fall2017 - week 8
Derek Jacoby
 
Untangling - fall2017 - week 7
Derek Jacoby
 
Agile sites @ telmore
Michele Sciabarrà
 
Agile sites2
Michele Sciabarrà
 
Untangling spring week5
Derek Jacoby
 
Agile sites311training
Michele Sciabarrà
 
Web Performance Part 4 "Client-side performance"
Binary Studio
 
Building Enterprise Grade Front-End Applications with JavaScript Frameworks
FITC
 
Untangling spring week4
Derek Jacoby
 
Client vs Server Templating: Speed up initial load for SPA with Angular as an...
David Amend
 
[Srijan Wednesday Webinars] Developing Large Scale Applications in AngularJS
Srijan Technologies
 
Ci of js and apex using jasmine, phantom js and drone io df14
Kevin Poorman
 
Untangling spring week10
Derek Jacoby
 
How NOT to get lost in the current JavaScript landscape
Radosław Scheibinger
 
WebGL: Yesterday, Today, Tomorrow
Bogdan Gorpynchuk
 
Capybara-Webkit
bostonrb
 
Rapid development with Rails
Yi-Ting Cheng
 
Back to the future with static site generators
Chris Ward
 
Untangling spring week9
Derek Jacoby
 

Similar to Masterin Large Scale Java Script Applications (20)

PPTX
JS Essence
Uladzimir Piatryka
 
PPTX
JavaOne2016 - How to Generate Customized Java 8 Code from Your Database [TUT4...
Speedment, Inc.
 
PPTX
How to JavaOne 2016 - Generate Customized Java 8 Code from Your Database [TUT...
Malin Weiss
 
PDF
Gwt.Create Keynote San Francisco
Ray Cromwell
 
PDF
Intro JavaScript
koppenolski
 
PDF
Shift Remote: JS - Javascript Build Tools: Past & Beyond - Shedrack Akintayo
Shift Conference
 
PDF
MEAN Stack Warm-up
Troy Miles
 
PPTX
Super tools to boost productivity in React dev env!
Souvik Basu
 
PDF
Developing High Performance Web Apps
Timothy Fisher
 
PDF
Web Development using Ruby on Rails
Avi Kedar
 
PDF
Building Real-World Dojo Web Applications
Andrew Ferrier
 
KEY
20120306 dublin js
Richard Rodger
 
PPTX
Silicon Valley JUG - How to generate customized java 8 code from your database
Speedment, Inc.
 
PPTX
How to generate customized java 8 code from your database
Speedment, Inc.
 
PPTX
Webpack and Web Performance Optimization
Chen-Tien Tsai
 
PDF
TheFutureIsDynamic-BoxLang-CFCamp2024.pdf
Ortus Solutions, Corp
 
PPTX
External JavaScript Widget Development Best Practices (updated) (v.1.1)
Volkan Özçelik
 
PDF
How to start developing apps for Firefox OS
benko
 
PPTX
External JavaScript Widget Development Best Practices
Volkan Özçelik
 
KEY
Developing High Performance Web Apps - CodeMash 2011
Timothy Fisher
 
JS Essence
Uladzimir Piatryka
 
JavaOne2016 - How to Generate Customized Java 8 Code from Your Database [TUT4...
Speedment, Inc.
 
How to JavaOne 2016 - Generate Customized Java 8 Code from Your Database [TUT...
Malin Weiss
 
Gwt.Create Keynote San Francisco
Ray Cromwell
 
Intro JavaScript
koppenolski
 
Shift Remote: JS - Javascript Build Tools: Past & Beyond - Shedrack Akintayo
Shift Conference
 
MEAN Stack Warm-up
Troy Miles
 
Super tools to boost productivity in React dev env!
Souvik Basu
 
Developing High Performance Web Apps
Timothy Fisher
 
Web Development using Ruby on Rails
Avi Kedar
 
Building Real-World Dojo Web Applications
Andrew Ferrier
 
20120306 dublin js
Richard Rodger
 
Silicon Valley JUG - How to generate customized java 8 code from your database
Speedment, Inc.
 
How to generate customized java 8 code from your database
Speedment, Inc.
 
Webpack and Web Performance Optimization
Chen-Tien Tsai
 
TheFutureIsDynamic-BoxLang-CFCamp2024.pdf
Ortus Solutions, Corp
 
External JavaScript Widget Development Best Practices (updated) (v.1.1)
Volkan Özçelik
 
How to start developing apps for Firefox OS
benko
 
External JavaScript Widget Development Best Practices
Volkan Özçelik
 
Developing High Performance Web Apps - CodeMash 2011
Timothy Fisher
 
Ad

More from Fabian Jakobs (12)

PDF
Amsterdam.js talk: node webkit
Fabian Jakobs
 
PDF
Bespin, Skywriter, Ace The Past, Present and Future of online Code Editing
Fabian Jakobs
 
PDF
Kick ass code editing and end to end JavaScript debugging
Fabian Jakobs
 
PDF
Autopsy Of A Widget
Fabian Jakobs
 
PDF
Tdd For GuIs
Fabian Jakobs
 
PDF
Und es geht doch - TDD für GUIs
Fabian Jakobs
 
PDF
Lecture 8 - Qooxdoo - Rap Course At The University Of Szeged
Fabian Jakobs
 
PDF
Going Virtual
Fabian Jakobs
 
ZIP
Going Virtual
Fabian Jakobs
 
PDF
Qooxdoo 0.8 - Das Neue Gui Toolkit
Fabian Jakobs
 
PDF
Ajax In Action 2008 - Gui Development With qooxdoo
Fabian Jakobs
 
PDF
DLW Europe - JavaScript Tooling
Fabian Jakobs
 
Amsterdam.js talk: node webkit
Fabian Jakobs
 
Bespin, Skywriter, Ace The Past, Present and Future of online Code Editing
Fabian Jakobs
 
Kick ass code editing and end to end JavaScript debugging
Fabian Jakobs
 
Autopsy Of A Widget
Fabian Jakobs
 
Tdd For GuIs
Fabian Jakobs
 
Und es geht doch - TDD für GUIs
Fabian Jakobs
 
Lecture 8 - Qooxdoo - Rap Course At The University Of Szeged
Fabian Jakobs
 
Going Virtual
Fabian Jakobs
 
Going Virtual
Fabian Jakobs
 
Qooxdoo 0.8 - Das Neue Gui Toolkit
Fabian Jakobs
 
Ajax In Action 2008 - Gui Development With qooxdoo
Fabian Jakobs
 
DLW Europe - JavaScript Tooling
Fabian Jakobs
 
Ad

Recently uploaded (20)

PPTX
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
PPTX
Securing Account Lifecycles in the Age of Deepfakes.pptx
FIDO Alliance
 
PDF
2025_06_18 - OpenMetadata Community Meeting.pdf
OpenMetadata
 
PDF
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
PPTX
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
PDF
Salesforce Summer '25 Release Frenchgathering.pptx.pdf
yosra Saidani
 
PDF
Oh, the Possibilities - Balancing Innovation and Risk with Generative AI.pdf
Priyanka Aash
 
PDF
Cracking the Code - Unveiling Synergies Between Open Source Security and AI.pdf
Priyanka Aash
 
PDF
"Database isolation: how we deal with hundreds of direct connections to the d...
Fwdays
 
PDF
Quantum AI: Where Impossible Becomes Probable
Saikat Basu
 
PDF
GenAI Opportunities and Challenges - Where 370 Enterprises Are Focusing Now.pdf
Priyanka Aash
 
PPTX
Wenn alles versagt - IBM Tape schützt, was zählt! Und besonders mit dem neust...
Josef Weingand
 
PDF
AI vs Human Writing: Can You Tell the Difference?
Shashi Sathyanarayana, Ph.D
 
PPTX
" How to survive with 1 billion vectors and not sell a kidney: our low-cost c...
Fwdays
 
PDF
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
PDF
Securing AI - There Is No Try, Only Do!.pdf
Priyanka Aash
 
PDF
Connecting Data and Intelligence: The Role of FME in Machine Learning
Safe Software
 
PDF
A Constitutional Quagmire - Ethical Minefields of AI, Cyber, and Privacy.pdf
Priyanka Aash
 
PDF
Database Benchmarking for Performance Masterclass: Session 2 - Data Modeling ...
ScyllaDB
 
PPTX
Curietech AI in action - Accelerate MuleSoft development
shyamraj55
 
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
Securing Account Lifecycles in the Age of Deepfakes.pptx
FIDO Alliance
 
2025_06_18 - OpenMetadata Community Meeting.pdf
OpenMetadata
 
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
Salesforce Summer '25 Release Frenchgathering.pptx.pdf
yosra Saidani
 
Oh, the Possibilities - Balancing Innovation and Risk with Generative AI.pdf
Priyanka Aash
 
Cracking the Code - Unveiling Synergies Between Open Source Security and AI.pdf
Priyanka Aash
 
"Database isolation: how we deal with hundreds of direct connections to the d...
Fwdays
 
Quantum AI: Where Impossible Becomes Probable
Saikat Basu
 
GenAI Opportunities and Challenges - Where 370 Enterprises Are Focusing Now.pdf
Priyanka Aash
 
Wenn alles versagt - IBM Tape schützt, was zählt! Und besonders mit dem neust...
Josef Weingand
 
AI vs Human Writing: Can You Tell the Difference?
Shashi Sathyanarayana, Ph.D
 
" How to survive with 1 billion vectors and not sell a kidney: our low-cost c...
Fwdays
 
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
Securing AI - There Is No Try, Only Do!.pdf
Priyanka Aash
 
Connecting Data and Intelligence: The Role of FME in Machine Learning
Safe Software
 
A Constitutional Quagmire - Ethical Minefields of AI, Cyber, and Privacy.pdf
Priyanka Aash
 
Database Benchmarking for Performance Masterclass: Session 2 - Data Modeling ...
ScyllaDB
 
Curietech AI in action - Accelerate MuleSoft development
shyamraj55
 

Masterin Large Scale Java Script Applications

  • 1. Mastering Large Scale JavaScript Applications Fabian Jakobs
  • 2. About • Senior JavaScript Developer at 1&1 • core developer since 2006 @fjakobs
  • 4. Framework Application
  • 10. JavaScript Application • Single Page Application • Client Logic in JavaScript • Client-Server Communication with AJAX calls
  • 11. Large Scale • Complexity and Size of JavaScript code • ~ 150,000 LOC • ~ 1000 Classes
  • 13. • Rich Web Mail Application • Pure JavaScript Client • Backend Communication with Ajax calls • Based on qooxdoo
  • 14. • Client-side JavaScript Framework • Cross-browser web applications • Open Source
  • 16. JavaScript isn‘t made for this • No package mechanism • By default everything is in the global namespace • Only basic building blocks for OOP • Tooling still sucks
  • 17. Everybody puts a layer on top • GWT covers JavaScript with Java • Cappuchino uses Objective-J • Adobe invented ActionScript • Everyone else uses (different) meta object systems written in JavaScript
  • 18. qooxdoo OOP qx.Class.define("demo.Person", { extend : qx.core.Object, construct : function(firstName, lastName) { this.base(arguments); this._firstName = firstName; this._lastName = lastName; }, members : { getFullName : function() { return this._firstName + " " + this._lastName; } } });
  • 20. Tooling API Doc Unit Testing Linker Auto Completion Code Coverage Lint IDE Support
  • 21. Tooling dilemma • Different OOP syntax makes generic tooling hard • Tools often depend in certain Framework features • Don‘t just look at the widgets, look at the development tools as well
  • 22. Find the Right Level of Abstraction
  • 23. Desktop Like Web Applications Need Desktop Abstractions • Widgets • DOM Nodes • Layout Manager vs • CSS • Themes • Browser Bugs
  • 24. Abstractions Application Application Components Custom Widgets Base Widgets Framework UI Core (Rendering Engine) BOM (Cross Browser Code) Core (JavaScript OOP)
  • 25. Desktop Style Development Model // Create a button var button = new qx.ui.form.Button("First Button", "demo/browser.png"); // Add button to container at fixed coordinates container.add(button, {left: 100, top: 50}); // Add an event listener button.addListener("execute", function(e) { alert("Hello World!"); });
  • 26. Leaky Abstractions • Emulated behavior may be slower • e.g. Canvas wrapper for IE • For advanced tasks its essential to know the lower layers • CSS, HMTL, DOM knowledge is still needed
  • 28. Styling No OS clone! No default theme Everything Custom!
  • 31. i18n
  • 32. i18n
  • 33. i18n
  • 34. i18n in qooxdoo this button = var qx.ui.form.Button(this.tr("Hello World!")); • Standards • gettext • CLDR • good external tooling • known by professional translators
  • 36. Our Bottlenecks • Startup time • Widget creation • Table scroll performance
  • 37. Startup Time The 3Cs + O • Combine • Compress • Cache • On demand
  • 38. Combine • reduce number of requests • combine JS JS PNG PNG • JavaScript files • CSS JS PNG • Images
  • 39. Compress • optipng et el for images • compress JavaScript • serve with gzip
  • 41. Cache • Serve static files with „cache forever“ • Increase version number if content changes • Use Image servers
  • 42. On Demand • Defer operations • Load Code on demand • Load Data on demand • Render UI on demand
  • 43. On Demand Code • The initial view does not need • Editor • Settings • Address book • ...
  • 44. On Demand Code • Code qx.io.PartLoader.require("settings", function() { mailclient.ui.SettingsDialog.getInstance().open(); }, this); • Content ... "packages" : { "parts" : { "settings": { "include" : ["mailclient.ui.SettingsDialog"] } } } ...
  • 45. On Demand Data and UI • Thousands of mails in the inbox • Only load visible data • Only render visible rows of the table
  • 46. Widget Creation • DOM operations are expensive • Creation Widgets is expensive • Reuse Widgets • Share Widgets • Pool Widgets • Increases Complexity!
  • 47. Reuse Widgets pool and reuse share mail preview mail folder among tabs
  • 50. Decouple UI Components Message Bus
  • 51. Code Should be Executable in Isolation • Without rebuilding the application • Without restarting the application • Without a server
  • 54. Summary • Good Abstractions • Styling • Internationalization • Performance • Clean Code
  • 55. colorstrip.gifT THE NEW ERA OF WEB DEVELOPMENT Thank you. Fabian Jakobs @fjakobs <[email protected]> http://qooxdoo.org
  • 56. Fotos • http://www.flickr.com/photos/martin_uj/2505238011/ • http://www.flickr.com/photos/born-clothing/3764261653/ • http://www.flickr.com/photos/countrushmore/540548338/ • http://www.flickr.com/photos/gordonr/42555739/ • http://www.flickr.com/photos/evaekeblad/345203452/ • http://www.flickr.com/photos/oldonliner/1095360979/ • http://www.flickr.com/photos/imcomkorea/3496427357/ • http://www.flickr.com/photos/nhr/460382116/ • http://www.flickr.com/photos/evaekeblad/345203452/