# jQuery vs Google Closure Library vs ClojureScript Comparison A comprehensive comparison of jQuery 4.0.0 with Google Closure Library and ClojureScript (with Google Closure), providing equivalent code for every example in the jQuery documentation. --- ## Table of Contents 1. [Overview](#overview) 2. [Installation](#installation) 3. [Core Selection](#core-selection) 4. [Utility Functions](#utility-functions) 5. [DOM Manipulation](#dom-manipulation) 6. [Event Handling](#event-handling) 7. [Traversal](#traversal) 8. [Data Storage](#data-storage) 9. [AJAX](#ajax) 10. [Deferred/Promises](#deferredpromises) 11. [Callbacks](#callbacks) 12. [Animation](#animation) 13. [Security Features](#security-features) --- ## Overview | Aspect | jQuery 4.0.0 | Google Closure Library | ClojureScript + Closure | |--------|-------------|----------------------|------------------------| | **Status** | Active (Jan 2026) | Sunset (Aug 2024) | Active | | **Size** | ~30kb gzipped | Modular (tree-shaken) | Compiled & optimized | | **Philosophy** | Imperative, chaining | Object-oriented, modular | Functional, immutable | | **Browser compat** | Last 3 versions | Cross-browser normalized | Via Closure Compiler | | **Build system** | Optional | Closure Compiler | ClojureScript compiler | ### Key Differences **jQuery**: Designed for simplicity and DOM manipulation with a fluent chaining API. Excellent for quick prototyping and small projects. **Google Closure Library**: A comprehensive, modular library built for large-scale applications. Designed to work with the Closure Compiler for aggressive optimizations. Note: The library was sunset in August 2024. **ClojureScript**: A Clojure dialect that compiles to JavaScript. Automatically includes Google Closure Library and uses the Closure Compiler. Offers functional programming paradigms with immutable data structures. --- ## Installation ### jQuery 4.0.0 ```html ``` ```javascript // ES Module import $ from 'jquery'; // CommonJS const $ = require('jquery'); ``` ### Google Closure Library ```html ``` ```javascript // Modern ES modules (if using Closure Compiler) goog.module('myapp.main'); const dom = goog.require('goog.dom'); const events = goog.require('goog.events'); ``` ### ClojureScript ```clojure ;; deps.edn {:deps {org.clojure/clojurescript {:mvn/version "1.11.132"}}} ;; In your namespace (ns myapp.core (:require [goog.dom :as gdom] [goog.events :as gevents]) (:import [goog.events EventType])) ``` --- ## Core Selection ### jQuery: Select by ID ```javascript // jQuery const $header = $('#header'); ``` ### Google Closure ```javascript // Google Closure const header = goog.dom.getElement('header'); // or shorthand const header = goog.dom.$('header'); ``` ### ClojureScript ```clojure ;; ClojureScript with goog.dom (require '[goog.dom :as gdom]) (def header (gdom/getElement "header")) ;; Or using native JS interop (def header (.getElementById js/document "header")) ``` --- ### jQuery: Select by Class ```javascript // jQuery const $buttons = $('.btn'); ``` ### Google Closure ```javascript // Google Closure - single element const button = goog.dom.getElementByClass('btn'); // Multiple elements const buttons = goog.dom.getElementsByClass('btn'); ``` ### ClojureScript ```clojure ;; ClojureScript (def button (gdom/getElementByClass "btn")) (def buttons (gdom/getElementsByClass "btn")) ;; With dommy library (require '[dommy.core :as dommy :refer-macros [sel sel1]]) (def button (sel1 :.btn)) (def buttons (sel :.btn)) ``` --- ### jQuery: Select by Tag ```javascript // jQuery const $paragraphs = $('p'); ``` ### Google Closure ```javascript // Google Closure const paragraphs = goog.dom.getElementsByTagName('p'); // With class filter const items = goog.dom.getElementsByTagNameAndClass('div', 'item'); ``` ### ClojureScript ```clojure ;; ClojureScript (def paragraphs (gdom/getElementsByTagName "p")) ;; With dommy (def paragraphs (sel :p)) ``` --- ### jQuery: Select with Context ```javascript // jQuery const $items = $('.item', '#container'); ``` ### Google Closure ```javascript // Google Closure const container = goog.dom.getElement('container'); const items = goog.dom.getElementsByClass('item', container); // Using query selector const items = goog.dom.query('.item', container); ``` ### ClojureScript ```clojure ;; ClojureScript (def container (gdom/getElement "container")) (def items (gdom/getElementsByClass "item" container)) ;; With dommy (def items (sel container :.item)) ``` --- ### jQuery: Create Elements ```javascript // jQuery const $newDiv = $('
New paragraph
'); // jQuery - Prepend $('#container').prepend('First paragraph
'); // jQuery - Remove $('#element').remove(); // jQuery - Empty (remove children) $('#container').empty(); ``` ### Google Closure ```javascript // Google Closure goog.require('goog.dom'); const container = goog.dom.getElement('container'); // Append const newP = goog.dom.createDom('p', null, 'New paragraph'); goog.dom.appendChild(container, newP); // Prepend const firstP = goog.dom.createDom('p', null, 'First paragraph'); goog.dom.insertChildAt(container, firstP, 0); // Remove const element = goog.dom.getElement('element'); goog.dom.removeNode(element); // Empty (remove children) goog.dom.removeChildren(container); ``` ### ClojureScript ```clojure ;; ClojureScript with goog.dom (require '[goog.dom :as gdom]) (def container (gdom/getElement "container")) ;; Append (let [new-p (gdom/createDom "p" nil "New paragraph")] (gdom/appendChild container new-p)) ;; Prepend (let [first-p (gdom/createDom "p" nil "First paragraph")] (gdom/insertChildAt container first-p 0)) ;; Remove (gdom/removeNode (gdom/getElement "element")) ;; Empty (gdom/removeChildren container) ;; With dommy library (require '[dommy.core :as dommy :refer-macros [sel1]]) (dommy/append! (sel1 :#container) some-element) (dommy/remove! (sel1 :#element)) ``` --- ### jQuery: Class Manipulation ```javascript // jQuery $('#element').addClass('active'); $('#element').removeClass('inactive'); $('#element').toggleClass('visible'); $('#element').hasClass('active'); // returns boolean ``` ### Google Closure ```javascript // Google Closure goog.require('goog.dom.classlist'); const element = goog.dom.getElement('element'); goog.dom.classlist.add(element, 'active'); goog.dom.classlist.remove(element, 'inactive'); goog.dom.classlist.toggle(element, 'visible'); goog.dom.classlist.contains(element, 'active'); // returns boolean // Multiple classes goog.dom.classlist.addAll(element, ['class1', 'class2']); goog.dom.classlist.removeAll(element, ['class1', 'class2']); // Swap classes goog.dom.classlist.swap(element, 'old-class', 'new-class'); ``` ### ClojureScript ```clojure ;; ClojureScript with goog.dom.classlist (require '[goog.dom.classlist :as classlist]) (def element (gdom/getElement "element")) (classlist/add element "active") (classlist/remove element "inactive") (classlist/toggle element "visible") (classlist/contains element "active") ;; returns boolean ;; With dommy (require '[dommy.core :as dommy :refer-macros [sel1]]) (dommy/add-class! (sel1 :#element) :active) (dommy/remove-class! (sel1 :#element) :inactive) (dommy/toggle-class! (sel1 :#element) :visible) (dommy/has-class? (sel1 :#element) :active) ``` --- ### jQuery: CSS/Style Manipulation ```javascript // jQuery - Get style const color = $('#element').css('color'); // jQuery - Set single style $('#element').css('color', 'red'); // jQuery - Set multiple styles $('#element').css({ color: 'red', fontSize: '16px', backgroundColor: '#fff' }); ``` ### Google Closure ```javascript // Google Closure goog.require('goog.style'); const element = goog.dom.getElement('element'); // Get style const color = goog.style.getStyle(element, 'color'); // Set single style goog.style.setStyle(element, 'color', 'red'); // Set multiple styles goog.style.setStyle(element, { 'color': 'red', 'font-size': '16px', 'background-color': '#fff' }); // Other style utilities goog.style.setOpacity(element, 0.5); goog.style.setSize(element, 100, 200); // width, height goog.style.setPosition(element, 10, 20); // x, y goog.style.showElement(element, true); // show/hide ``` ### ClojureScript ```clojure ;; ClojureScript with goog.style (require '[goog.style :as gstyle]) (def element (gdom/getElement "element")) ;; Get style (def color (gstyle/getStyle element "color")) ;; Set single style (gstyle/setStyle element "color" "red") ;; Set multiple styles (gstyle/setStyle element #js {:color "red" :font-size "16px" :background-color "#fff"}) ;; With dommy (dommy/set-style! (sel1 :#element) :color "red") (dommy/set-style! (sel1 :#element) :font-size "16px") ``` --- ### jQuery: Text and HTML Content ```javascript // jQuery - Get/Set text const text = $('#element').text(); $('#element').text('New text content'); // jQuery - Get/Set HTML const html = $('#element').html(); $('#element').html('Bold text'); ``` ### Google Closure ```javascript // Google Closure goog.require('goog.dom'); const element = goog.dom.getElement('element'); // Get/Set text const text = goog.dom.getTextContent(element); goog.dom.setTextContent(element, 'New text content'); // Get/Set HTML (be careful with XSS) const html = element.innerHTML; element.innerHTML = 'Bold text'; // Safe HTML setting (with Trusted Types support) goog.require('goog.dom.safe'); goog.dom.safe.setInnerHtml(element, trustedHtml); ``` ### ClojureScript ```clojure ;; ClojureScript with goog.dom (def element (gdom/getElement "element")) ;; Get/Set text (def text (gdom/getTextContent element)) (gdom/setTextContent element "New text content") ;; Get/Set HTML (def html (.-innerHTML element)) (set! (.-innerHTML element) "Bold text") ;; With dommy (dommy/text (sel1 :#element)) (dommy/set-text! (sel1 :#element) "New text") (dommy/html (sel1 :#element)) (dommy/set-html! (sel1 :#element) "Bold") ``` --- ### jQuery: Attributes ```javascript // jQuery - Get attribute const href = $('a').attr('href'); // jQuery - Set attribute $('a').attr('href', 'https://example.com'); // jQuery - Set multiple attributes $('#img').attr({ src: 'image.jpg', alt: 'Description' }); // jQuery - Remove attribute $('#input').removeAttr('disabled'); ``` ### Google Closure ```javascript // Google Closure const element = goog.dom.getElement('link'); // Get attribute const href = element.getAttribute('href'); // Set attribute element.setAttribute('href', 'https://example.com'); // Set multiple with goog.dom goog.dom.setProperties(element, { 'href': 'https://example.com', 'target': '_blank' }); // Remove attribute element.removeAttribute('disabled'); ``` ### ClojureScript ```clojure ;; ClojureScript (def element (gdom/getElement "link")) ;; Get attribute (def href (.getAttribute element "href")) ;; Set attribute (.setAttribute element "href" "https://example.com") ;; Set multiple (gdom/setProperties element #js {:href "https://example.com" :target "_blank"}) ;; Remove (.removeAttribute element "disabled") ;; With dommy (dommy/attr (sel1 :a) :href) (dommy/set-attr! (sel1 :a) :href "https://example.com") (dommy/remove-attr! (sel1 :#input) :disabled) ``` --- ## Event Handling ### jQuery: Basic Event Binding ```javascript // jQuery - on() method $('#button').on('click', function(e) { console.log('Button clicked'); }); // jQuery - Shorthand $('#button').click(function() { console.log('Button clicked'); }); // jQuery - Multiple events $('#input').on('focus blur', function(e) { console.log('Focus state changed'); }); ``` ### Google Closure ```javascript // Google Closure goog.require('goog.events'); goog.require('goog.events.EventType'); const button = goog.dom.getElement('button'); // Basic listener goog.events.listen(button, goog.events.EventType.CLICK, function(e) { console.log('Button clicked'); }); // Multiple events const input = goog.dom.getElement('input'); goog.events.listen(input, [goog.events.EventType.FOCUS, goog.events.EventType.BLUR], function(e) { console.log('Focus state changed'); } ); ``` ### ClojureScript ```clojure ;; ClojureScript with goog.events (require '[goog.events :as gevents]) (import '[goog.events EventType]) (def button (gdom/getElement "button")) ;; Basic listener (gevents/listen button EventType.CLICK (fn [e] (println "Button clicked"))) ;; Multiple events (doseq [event-type [EventType.FOCUS EventType.BLUR]] (gevents/listen input event-type (fn [e] (println "Focus state changed")))) ;; With dommy (dommy/listen! (sel1 :#button) :click (fn [e] (println "Button clicked"))) ``` --- ### jQuery: Event Delegation ```javascript // jQuery - Event delegation $('#container').on('click', '.item', function(e) { console.log('Item clicked:', $(this).text()); }); ``` ### Google Closure ```javascript // Google Closure - Manual delegation goog.require('goog.events'); goog.require('goog.dom'); const container = goog.dom.getElement('container'); goog.events.listen(container, goog.events.EventType.CLICK, function(e) { // Check if target matches selector const target = e.target; if (goog.dom.classlist.contains(target, 'item')) { console.log('Item clicked:', goog.dom.getTextContent(target)); } // Or find closest matching ancestor const item = goog.dom.getAncestorByClass(target, 'item'); if (item) { console.log('Item clicked:', goog.dom.getTextContent(item)); } }); ``` ### ClojureScript ```clojure ;; ClojureScript - Manual delegation (gevents/listen (gdom/getElement "container") EventType.CLICK (fn [e] (let [target (.-target e)] (when (classlist/contains target "item") (println "Item clicked:" (gdom/getTextContent target)))))) ;; With dommy - built-in delegation (dommy/listen! [(sel1 :#container) :.item] :click (fn [e] (println "Item clicked:" (dommy/text (.-selectedTarget e))))) ``` --- ### jQuery: One-time Events ```javascript // jQuery - one() for single execution $('#button').one('click', function() { console.log('This only fires once'); }); ``` ### Google Closure ```javascript // Google Closure goog.events.listenOnce(button, goog.events.EventType.CLICK, function(e) { console.log('This only fires once'); }); ``` ### ClojureScript ```clojure ;; ClojureScript (gevents/listenOnce button EventType.CLICK (fn [e] (println "This only fires once"))) ;; With dommy (dommy/listen-once! (sel1 :#button) :click (fn [e] (println "This only fires once"))) ``` --- ### jQuery: Removing Event Handlers ```javascript // jQuery - Named handler for removal function clickHandler(e) { console.log('Clicked'); } $('#button').on('click', clickHandler); $('#button').off('click', clickHandler); // Remove all click handlers $('#button').off('click'); // Remove all handlers $('#button').off(); ``` ### Google Closure ```javascript // Google Closure function clickHandler(e) { console.log('Clicked'); } // Listen returns a key for removal const key = goog.events.listen(button, goog.events.EventType.CLICK, clickHandler); // Remove specific handler goog.events.unlistenByKey(key); // Or remove by parameters goog.events.unlisten(button, goog.events.EventType.CLICK, clickHandler); // Remove all handlers from element goog.events.removeAll(button); // Remove all handlers of specific type goog.events.removeAll(button, goog.events.EventType.CLICK); ``` ### ClojureScript ```clojure ;; ClojureScript (defn click-handler [e] (println "Clicked")) ;; Store the key (def key (gevents/listen button EventType.CLICK click-handler)) ;; Remove by key (gevents/unlistenByKey key) ;; Remove by parameters (gevents/unlisten button EventType.CLICK click-handler) ;; Remove all (gevents/removeAll button) ;; With dommy (dommy/listen! (sel1 :#button) :click click-handler) (dommy/unlisten! (sel1 :#button) :click click-handler) ``` --- ### jQuery: Focus Event Order (W3C in 4.0) ```javascript // jQuery 4.0 order (W3C compliant): // blur → focusout → focus → focusin const $input = $('#myInput'); $input.on('blur', () => console.log('1. blur')); $input.on('focusout', () => console.log('2. focusout')); $input.on('focus', () => console.log('3. focus')); $input.on('focusin', () => console.log('4. focusin')); ``` ### Google Closure ```javascript // Google Closure - Uses native event order const input = goog.dom.getElement('myInput'); goog.events.listen(input, goog.events.EventType.BLUR, function() { console.log('blur'); }); goog.events.listen(input, goog.events.EventType.FOCUS, function() { console.log('focus'); }); // focusin/focusout via FocusHandler for cross-browser support goog.require('goog.events.FocusHandler'); const focusHandler = new goog.events.FocusHandler(input); goog.events.listen(focusHandler, goog.events.FocusHandler.EventType.FOCUSIN, function() { console.log('focusin'); }); ``` ### ClojureScript ```clojure ;; ClojureScript (gevents/listen input EventType.BLUR #(println "blur")) (gevents/listen input EventType.FOCUS #(println "focus")) ;; For focusin/focusout (import '[goog.events FocusHandler]) (def focus-handler (FocusHandler. input)) (gevents/listen focus-handler (.-FOCUSIN FocusHandler.EventType) #(println "focusin")) ``` --- ## Traversal ### jQuery: .find() ```javascript // jQuery - Find all paragraphs inside #content $('#content').find('p').addClass('styled'); // Chained traversal $('#nav') .find('li') .find('a') .addClass('nav-link'); ``` ### Google Closure ```javascript // Google Closure const content = goog.dom.getElement('content'); const paragraphs = goog.dom.getElementsByTagName('p', content); goog.array.forEach(paragraphs, function(p) { goog.dom.classlist.add(p, 'styled'); }); // Or with query const links = goog.dom.query('#nav li a'); goog.array.forEach(links, function(a) { goog.dom.classlist.add(a, 'nav-link'); }); ``` ### ClojureScript ```clojure ;; ClojureScript (let [content (gdom/getElement "content") paragraphs (gdom/getElementsByTagName "p" content)] (doseq [p (array-seq paragraphs)] (classlist/add p "styled"))) ;; With dommy (doseq [p (sel (sel1 :#content) :p)] (dommy/add-class! p :styled)) ``` --- ### jQuery: .filter() ```javascript // jQuery - Filter by selector $('li').filter('.active').css('font-weight', 'bold'); // Filter by function $('input').filter(function() { return $(this).val().length > 0; }).addClass('has-value'); ``` ### Google Closure ```javascript // Google Closure goog.require('goog.array'); // Filter by class const items = goog.dom.getElementsByTagName('li'); const activeItems = goog.array.filter(items, function(li) { return goog.dom.classlist.contains(li, 'active'); }); goog.array.forEach(activeItems, function(li) { goog.style.setStyle(li, 'font-weight', 'bold'); }); // Filter by function const inputs = goog.dom.getElementsByTagName('input'); const filledInputs = goog.array.filter(inputs, function(input) { return input.value.length > 0; }); ``` ### ClojureScript ```clojure ;; ClojureScript (->> (array-seq (gdom/getElementsByTagName "li")) (filter #(classlist/contains % "active")) (run! #(gstyle/setStyle % "font-weight" "bold"))) ;; Filter inputs with values (->> (array-seq (gdom/getElementsByTagName "input")) (filter #(> (count (.-value %)) 0)) (run! #(classlist/add % "has-value"))) ;; With dommy (->> (sel :li) (filter #(dommy/has-class? % :active)) (run! #(dommy/set-style! % :font-weight "bold"))) ``` --- ### jQuery: .closest() ```javascript // jQuery - Find parent form $('input').on('blur', function() { const $form = $(this).closest('form'); validateForm($form); }); ``` ### Google Closure ```javascript // Google Closure goog.require('goog.dom'); goog.events.listen(input, 'blur', function(e) { const form = goog.dom.getAncestorByTagNameAndClass(e.target, 'form'); validateForm(form); }); // By class const container = goog.dom.getAncestorByClass(element, 'container'); ``` ### ClojureScript ```clojure ;; ClojureScript (gevents/listen input "blur" (fn [e] (let [form (gdom/getAncestorByTagNameAndClass (.-target e) "form")] (validate-form form)))) ;; By class (def container (gdom/getAncestorByClass element "container")) ``` --- ### jQuery: .has() ```javascript // jQuery - Only select divs that contain a span $('div').has('span').addClass('has-span'); ``` ### Google Closure ```javascript // Google Closure const divs = goog.dom.getElementsByTagName('div'); goog.array.forEach(divs, function(div) { if (goog.dom.getElementsByTagName('span', div).length > 0) { goog.dom.classlist.add(div, 'has-span'); } }); ``` ### ClojureScript ```clojure ;; ClojureScript (->> (array-seq (gdom/getElementsByTagName "div")) (filter #(pos? (.-length (gdom/getElementsByTagName "span" %)))) (run! #(classlist/add % "has-span"))) ``` --- ### jQuery: .index() ```javascript // jQuery $('li.active').index(); // Position among siblings const $items = $('li'); $items.index($('.active')); // Position in collection ``` ### Google Closure ```javascript // Google Closure goog.require('goog.array'); // Among siblings const active = goog.dom.getElementByClass('active'); const siblings = goog.dom.getChildren(active.parentNode); const index = goog.array.indexOf(siblings, active); // In collection const items = goog.dom.getElementsByTagName('li'); const activeItem = goog.dom.getElementByClass('active'); const indexInCollection = goog.array.indexOf(items, activeItem); ``` ### ClojureScript ```clojure ;; ClojureScript (let [active (gdom/getElementByClass "active") siblings (gdom/getChildren (.-parentNode active))] (.indexOf (array-seq siblings) active)) ``` --- ### jQuery: .add() ```javascript // jQuery - Combine selections $('p') .add('span') .add('div.highlight') .addClass('styled'); ``` ### Google Closure ```javascript // Google Closure - Combine into array const combined = goog.array.concat( goog.array.toArray(goog.dom.getElementsByTagName('p')), goog.array.toArray(goog.dom.getElementsByTagName('span')), goog.array.toArray(goog.dom.getElementsByClass('highlight')) ); goog.array.forEach(combined, function(el) { goog.dom.classlist.add(el, 'styled'); }); ``` ### ClojureScript ```clojure ;; ClojureScript (let [combined (concat (array-seq (gdom/getElementsByTagName "p")) (array-seq (gdom/getElementsByTagName "span")) (array-seq (gdom/getElementsByClass "highlight")))] (run! #(classlist/add % "styled") combined)) ``` --- ## Data Storage ### jQuery: .data() ```javascript // jQuery - Set data $('#element').data('userId', 123); $('#element').data('config', { theme: 'dark', lang: 'en' }); // Get data const userId = $('#element').data('userId'); // 123 const config = $('#element').data('config'); // Get all data const allData = $('#element').data(); // HTML5 data attributes are auto-loaded //Safe content
'); $('#container').html(trustedContent); ``` ### Google Closure ```javascript // Google Closure - Built-in safe DOM methods goog.require('goog.dom.safe'); goog.require('goog.html.SafeHtml'); // Create safe HTML const safeHtml = goog.html.SafeHtml.create('p', {}, 'Safe content'); // Set inner HTML safely goog.dom.safe.setInnerHtml(container, safeHtml); ``` ### ClojureScript ```clojure ;; ClojureScript (require '[goog.dom.safe :as safe] '[goog.html.SafeHtml :as SafeHtml]) (def safe-html (SafeHtml/create "p" nil "Safe content")) (safe/setInnerHtml container safe-html) ``` --- ## Summary: Choosing Between Libraries | Use Case | Recommendation | |----------|---------------| | Quick prototyping | jQuery - simplest API | | Large-scale app | ClojureScript - functional, optimized | | Legacy codebase | jQuery + migrate plugin | | Functional programming | ClojureScript | | Maximum optimization | ClojureScript (Closure Compiler) | | React/modern framework | Consider native APIs or framework tools | ### Migration Path If migrating from jQuery: 1. **To Google Closure**: Replace jQuery calls with `goog.dom`, `goog.events`, `goog.style` 2. **To ClojureScript**: Use `goog.dom` namespace or wrapper libraries like `dommy` ### Key Takeaways - **jQuery** provides the most concise syntax for DOM manipulation - **Google Closure** offers modular, optimizable code (but is sunset) - **ClojureScript** combines functional programming with Closure Library benefits - Modern browsers support many jQuery features natively (`querySelector`, `fetch`, `classList`) --- ## Resources ### jQuery - [jquery.com](https://jquery.com) - [api.jquery.com](https://api.jquery.com) ### Google Closure Library - [google.github.io/closure-library](https://google.github.io/closure-library) - [Closure Cheatsheet](https://anton.shevchuk.name/wp-demo/closure-tutorials/cheatsheet.html) ### ClojureScript - [clojurescript.org](https://clojurescript.org) - [ClojureScript Google Closure Reference](https://clojurescript.org/reference/google-closure-library) - [Dommy Library](https://github.com/plumatic/dommy) - [cljs-ajax](https://github.com/JulianBirch/cljs-ajax) --- *Comparison document for jQuery 4.0.0 (January 2026) vs Google Closure Library vs ClojureScript*