(FRONT) FRONT (2016)

New unique features of Javascript ES6 (updated).

  1. Main 82 points of Browser and Node difference: JavaScript can run in both web browsers and on servers (via Node.js) is a defining feature. While the core language is the same, the environments differ significantly:
    • Browser specific JavaScript: Focuses on interacting with the Document Object Model (DOM), handling user events, processing Event Bubbling and Custom Events, allow to attach Shadow DOM and make Web Components, making network requests, and managing browser-specific APIs. It operates within the constraints of the browser's security sandbox.
    • Node.js JavaScript: Provides access to the file system, network sockets, and other server-side resources. It uses modules and packages to manage dependencies and structure applications. Node.js uses a non-blocking, event-driven architecture based on the same event loop model as browser JavaScript.
    • Web Workers: Web Workers enable running JavaScript code in separate threads in the browser, allowing for concurrent processing without blocking the main thread. This is essential for handling computationally intensive tasks or long-running operations without affecting user interface responsiveness. While other languages might use threads, Web Workers operate within the context of the web browser and have their specific API.
  2. Interpreted language (with JIT compilation): While initially purely interpreted, modern JavaScript engines utilize Just-In-Time (JIT) compilation to improve performance. The interpreted nature of JavaScript allows for dynamic code evaluation and modification, but JIT compilation allows for performance optimizations closer to compiled languages.
  3. Global scope and implicit globals: In JavaScript, variables declared outside of any function have global scope, and undeclared variables can implicitly create global variables. This can lead to naming conflicts and unexpected behavior if not handled carefully. This behavior is less common in modern languages with stricter scoping rules.
  4. Variable hoisting: JavaScript hoists variable and function declarations to the top of their scope before execution. This can lead to unexpected behavior if variables are used before they are declared, appearing as if var declarations initialize with undefined. let and const offer stricter scoping but also exhibit hoisting with different behavior (Temporal Dead Zone). Hoisting in this form is uncommon in other languages.
  5. Dynamic Typing: JavaScript's type system is dynamic, meaning you don't need to specify the type of a variable.
  6. Expression, Assignment and Operator: There are different types of JS syntax constructions.
  7. Function Scope: JavaScript's var keyword has function scope, while let and const are block-scoped.
  8. Hoisting: JavaScript hoists variable and function declarations to the top of the scope.
  9. Automatic Semicolon Insertion (ASI): JavaScript has a feature called Automatic Semicolon Insertion (ASI). This means that even if you don't explicitly put semicolons at the end of your statements, the JavaScript engine will often infer where they should be. While this can make code cleaner, it can also lead to unexpected behavior if the engine guesses incorrectly.
  10. Flexible JSON integration: JavaScript has native support for JSON (JavaScript Object Notation), which simplifies data exchange and manipulation. While other languages can work with JSON using libraries, JavaScript's built-in support makes it highly convenient.
  11. Event loop and asynchronous programming: JavaScript's event loop and asynchronous nature are fundamental to its operation, especially in web browsers. This allows JavaScript to handle events, perform non-blocking operations, and manage concurrency without freezing the user interface. While other languages have mechanisms for asynchronous programming, JavaScript's built-in event loop makes it particularly well-suited for event-driven environments.
  12. Closures: JavaScript supports closures, which are functions that have access to variables in their outer scope, even after the outer function has returned. This allows you to create private variables and methods.
  13. Prototypal Inheritance: JavaScript uses prototypal inheritance, which is different from the class-based inheritance used in Java and C#. In prototypal inheritance, objects inherit properties from other objects via a prototype chain.
  14. First-Class Functions: JavaScript treats functions as first-class citizens, meaning they can be passed as arguments to other functions, returned as values, and assigned to variables.
  15. Asynchronous Operations: JavaScript is single-threaded, but it can perform asynchronous operations using callbacks and promises. This allows you to write non-blocking code that can handle multiple operations at once.
  16. null and undefined: JavaScript has two special values, null and undefined, which represent the absence of a value. null is typically used to represent the intentional absence of a value, while undefined is used to represent a variable that has not been assigned a value.
  17. Behaviors related to the Number type: JavaScript uses the IEEE 754 standard for representing numbers, which leads to some interesting consequences:
    • NaN (Not a Number): NaN is a special value representing the result of an invalid numerical operation. It has the unusual property that NaN !== NaN;
    • Infinity and -Infinity: JavaScript represents positive and negative infinity; Numeric type conversions and potential for loss of precision:
    • Converting between different numeric types (e.g., integers and floating-point numbers) can result in unexpected behavior due to rounding errors and limitations of floating-point representation;
  18. Symbol: JavaScript has a special data type called Symbol, which is used to create unique identifiers for object properties.
  19. BigInt: JavaScript has a special data type called BigInt, which is used to represent integers that are too large to be represented by the Number type.
  20. typeof Operator: The typeof operator in JavaScript is used to determine the type of a variable.
  21. instanceof Operator: The instanceof operator in JavaScript is used to determine if an object is an instance of a particular class.
  22. in Operator: The in operator in JavaScript is used to determine if a property exists in an object.
  23. for...in Loop: The for...in loop is used to iterate over the enumerable properties of an object. It's important to note that it iterates over property names (keys), not values. It's often used for debugging or inspecting objects.
  24. for...of Loop: The for...of loop is used to iterate over the values of an iterable object (like arrays, strings, maps, sets). It's generally preferred for iterating over collections.
  25. Modules: JavaScript has a module system (using import and export) that allows you to break your code into separate files and manage dependencies. This is a more recent addition to the language and is used for better code organization.
  26. Dynamic import (for lazy-loading modules): Dynamic import() enables loading modules on demand, reducing initial load times and improving application performance by only loading modules when they are needed.
  27. Strict Mode: JavaScript has a "strict mode" that can be enabled to enforce stricter parsing and error handling. It helps catch common mistakes and makes the code more robust. You can enable it by adding "use strict"; at the beginning of your JavaScript file or function.
  28. Arrow Functions: JavaScript has arrow functions (=>), which provide a more concise syntax for defining functions. They also have lexical scoping, meaning they inherit the this value from their surrounding context.
  29. Template Literals: JavaScript has template literals (using backticks `` ), which allow you to embed expressions inside strings. This makes string concatenation and formatting much easier.
  30. Destructuring Assignment: JavaScript allows you to extract values from objects or arrays using destructuring assignment. This is a convenient way to unpack data.
  31. Spread Syntax: JavaScript has the spread syntax (...), which allows you to expand an iterable (like an array) into individual elements. This is useful for passing arguments to functions or creating new arrays.
  32. Rest Parameters: JavaScript has rest parameters (...), which allow you to collect multiple arguments into an array. This is useful for handling a variable number of arguments.
  33. Promises: JavaScript has promises, which are a way to handle asynchronous operations. They are a more modern alternative to callbacks.
  34. Async/Await: JavaScript has async/await, which is a more recent addition to the language that makes it easier to write asynchronous code. It allows you to write code that looks like it's running sequentially, even though it's actually running asynchronously.
  35. Truthiness and falsiness: JavaScript has a unique concept of "truthiness" and "falsiness," where values that are not explicitly booleans are coerced to boolean values in certain contexts. The rules governing which values are considered truthy or falsy can be subtle.
  36. eval() function: JavaScript has the eval() function, which can execute arbitrary code represented as a string. While powerful, eval() is generally avoided due to security risks and performance implications. Its presence and flexibility are unusual compared to other mainstream languages.
  37. Property access flexibility: JavaScript objects can have properties added or removed dynamically at runtime, and properties can be accessed using either dot notation (object.property) or bracket notation (object["property"]). This dynamic nature distinguishes JavaScript from statically typed languages.
  38. Variadic functions (arguments object): JavaScript functions can accept a variable number of arguments via the implicit arguments object (though rest parameters are now preferred). This flexible approach to argument handling is less common in strongly typed languages.
  39. Function overloading (lack thereof): JavaScript does not support traditional function overloading like some other languages (e.g., Java, C++). If multiple functions with the same name are defined, the last definition will overwrite the previous ones. Instead, JavaScript relies on flexible argument handling and optional parameters within a single function.
  40. Lack of block-level scoping (prior to let and const): Prior to ES6, JavaScript only had function-level scoping, meaning variables declared inside a block (e.g., within an if statement or loop) were still accessible outside that block within the enclosing function. This behavior is different from languages with block-level scoping, where variables are only accessible within the block they are defined in. let and const introduce block scope, but the legacy behavior is still relevant for understanding older code.
  41. Built-in support for regular expressions: JavaScript has built-in support for regular expressions, making string manipulation and pattern matching easier. While libraries provide regular expression functionality in other languages, JavaScript's native support streamlines its use.
  42. Loose object literals: JavaScript's object literal notation is very flexible, allowing property keys to be unquoted in many cases and permitting dynamic property addition and deletion. While some languages have similar object creation syntax, JavaScript's loose rules are less common.
  43. Templates literals: Template literals, delimited by backticks, provide string interpolation and multiline strings with ease. While other languages might have similar features, template literals' integration with JavaScript, particularly in combination with tagged templates for custom string processing, is noteworthy.
  44. Implicit conversions with + operator: The + operator in JavaScript can act as both addition and string concatenation, leading to implicit type conversions. If one operand is a string, the other operand is coerced to a string before concatenation. This behavior, while convenient at times, requires caution.
  45. Reserved words as property names: While generally a bad practice, JavaScript technically allows reserved keywords (like for, if, while) to be used as property names of objects (using bracket notation). This can lead to confusing and difficult-to-maintain code.
  46. Immutability of primitives vs. mutability of objects: Primitive values (numbers, strings, booleans, null, undefined, symbols) in JavaScript are immutable, meaning their values cannot be changed after creation. Objects, however, are mutable, so their properties can be modified. This fundamental distinction is crucial to understanding JavaScript behavior.
  47. Various ways to define functions (function declarations, function expressions, arrow functions): JavaScript offers multiple ways to define functions, each with subtle differences in scope and behavior, particularly with the this keyword. This flexibility adds to the richness (and potential confusion) of the language.
  48. The prototype chain as a linked list: The prototype chain in JavaScript can be conceptualized as a linked list of objects. When a property or method is accessed, the JavaScript engine traverses this chain until it finds the desired member or reaches the end of the chain. Understanding this traversal process is key to working effectively with inheritance.
  49. Treatment of immediately invoked function expressions (IIFEs): JavaScript allows for immediately invoked function expressions, where a function is defined and immediately executed. This pattern is used for creating private scopes and managing global namespace pollution. While conceptually achievable in other languages, JavaScript's syntax makes IIFEs concise and idiomatic.
  50. Optional chaining and nullish coalescing: Newer versions of JavaScript introduced optional chaining (?.) and nullish coalescing (??), which provide concise ways to handle potentially null or undefined values, improving code readability and robustness. While similar concepts exist in other languages (like null-safe dereferencing), their integration into JavaScript's syntax makes them distinctive.
  51. Symbol data type: Symbols were introduced to provide unique and immutable values, primarily for use as object keys. They address specific needs in JavaScript related to creating private properties or defining unique registry entries, solving problems that aren't as prevalent in other languages.
  52. Iterable and iterator protocols: JavaScript provides protocols for iterable and iterator objects, enabling customized iteration over data structures using for...of loops. While other languages have similar concepts, JavaScript's specific protocol implementation and integration with the language are unique.
  53. Generators: Generators, denoted by the function* syntax, allow you to create iterative functions that pause execution and yield values on demand. This can be used for lazy evaluation of sequences, managing asynchronous operations, and building more complex control flow. While conceptually similar to coroutines or iterators in other languages, JavaScript's generators have their unique syntax and integration into the language's asynchronous model.
  54. Proxy objects: Proxy objects enable intercepting and customizing operations performed on other objects, such as property access, function calls, and more. This allows for creating powerful metaprogramming tools and implementing patterns like virtual properties, validation, and logging. While other languages have similar reflection capabilities, JavaScript proxies offer a distinct mechanism and integration.
  55. WeakMap and WeakSet: WeakMap and WeakSet are specialized collection objects where the references to keys (in WeakMap) or values (in WeakSet) are "weak." This means that if the object referred to in a WeakMap or WeakSet is no longer reachable elsewhere, the garbage collector can reclaim it, even if it's still referenced in the collection. This is highly useful for managing memory and avoiding memory leaks, addressing specific issues in JavaScript's dynamic environment.
  56. Unicode handling and potential for character encoding issues: JavaScript strings are based on UTF-16 encoding. While generally robust, there can be subtle issues related to combining characters, surrogate pairs, and handling characters outside the Basic Multilingual Plane (BMP). These are complexities not always present in languages with simpler character encoding models.
  57. Labelled statements (and why you should probably avoid them): JavaScript supports labelled statements, which can be used with break or continue to control loops in non-standard ways. However, they can make code harder to read and understand and are generally not recommended.
  58. debugger statement: JavaScript has a debugger statement that, when encountered during script execution with a debugger attached, will cause the debugger to break at that point. This is a specific feature for debugging and not commonly found in other languages in this form.
  59. Tail call elimination in strict mode (where supported): While tail call optimization in general isn't reliably implemented across JavaScript engines, strict mode can enable tail call elimination in some engines. This creates a subtle performance and recursion difference between strict and non-strict code. Lack of tail call optimization (in most engines): While the ECMAScript standard specifies tail call optimization (TCO), which can improve performance and prevent stack overflows in recursive functions, many JavaScript engines do not fully implement it. This limits the practicality of certain recursive patterns.
  60. Implicit creation of global objects (in non-strict mode): Assigning a value to an undeclared variable in non-strict mode implicitly creates a global variable. Strict mode prevents this, requiring explicit variable declarations.
  61. Events and Event Handling: Event listeners can be attached to DOM elements to respond to user interactions (clicks, key presses, etc.) or other browser events (page load, network events). Node.js also uses events heavily for handling asynchronous operations and managing server-side tasks. This event-driven architecture is a core part of JavaScript's concurrency model.
  62. yield keyword (Generators and Iterators): The yield keyword is used within generator functions (function*) to pause the generator's execution and return a value to the caller. Generators are an advanced feature that enable lazy evaluation of sequences, asynchronous programming, and custom iterable objects. This control flow mechanism is unique to JavaScript compared to many other languages.
  63. instanceof operator: The instanceof operator checks whether an object is an instance of a particular constructor or class. It's essential for working with inheritance and determining the type of objects at runtime. While conceptually similar to type checking in other languages, JavaScript's instanceof operates within its prototype-based inheritance system.
  64. Well-known Symbols: JavaScript has well-known symbols, which are built-in symbols that represent internal language behavior (e.g., Symbol.iterator, Symbol.asyncIterator). They allow you to customize or hook into certain language features, such as how iteration works with your custom objects. This level of language customization is unusual in other languages.
  65. Typed Arrays: Typed arrays provide a way to work with binary data in JavaScript, enabling efficient manipulation of data structures like images, audio, and network buffers. While other languages often have built-in support for binary data types, JavaScript's typed arrays bridge the gap between its high-level nature and the need to interact with raw binary data.
  66. Modules (ES modules and CommonJS): JavaScript now has standardized modules (ES modules) for organizing and sharing code. Prior to ES modules, Node.js popularized the CommonJS module format. These systems allow you to create reusable modules and manage dependencies in larger projects. While modules are common in other languages, JavaScript's module ecosystem has gone through a significant evolution.
  67. Metaprogramming with Reflect API: The Reflect API provides methods for interacting with JavaScript objects and properties in a reflective way. It allows you to perform operations that would typically require eval() but in a safer and more standardized manner.
  68. Property descriptors (get and set accessors): JavaScript's property descriptors allow for defining getters and setters on object properties, enabling computed properties and property-change notifications. While other languages may have properties, JavaScript's getter/setter syntax and behavior are unique.
  69. Internationalization (Intl) API: JavaScript's Intl API provides features for formatting numbers, dates, times, and strings according to different locales and languages. This built-in internationalization support streamlines localization in web applications.
  70. Atomics object and SharedArrayBuffer: Atomics provide methods for atomic operations on SharedArrayBuffer instances, which are used for shared-memory concurrency between Web Workers. They are essential for preventing Race Conditions and ensuring data consistency in multi-threaded JavaScript environments. These are lower-level features compared to most JavaScript development and are aimed at very specific performance-sensitive scenarios.
  71. SharedArrayBuffer and Atomics object(for multi-threading): SharedArrayBuffer and the Atomics object allow for sharing memory and synchronizing access between multiple Web Workers, enabling true shared-memory multi-threading in JavaScript. This feature addresses specific needs in performance-critical applications where parallel processing is required.
  72. WebAssembly (Wasm) integration: JavaScript seamlessly integrates with WebAssembly, allowing other languages to be compiled to Wasm and run efficiently in the browser. This opens up possibilities for high-performance applications and using other languages alongside JavaScript.
  73. DataView object: DataView provides a low-level interface for accessing and manipulating different data types within an ArrayBuffer. It's used when you need to work with binary data in a structured way, going beyond JavaScript's standard number and string representations.
  74. Symbol.asyncIterator: Async iterators provide a way to iterate over asynchronous data sources (e.g., streams, network requests). They are used with for await...of loops to handle asynchronous operations in a more structured and iterable manner. This builds on the iterator and generator concepts but adds the ability to pause iteration while waiting for asynchronous operations to complete.
  75. Top-level await (in modules): Top-level await allows using await outside of async functions within ES modules, streamlining asynchronous code at the module level. This simplifies module initialization and interaction with asynchronous operations.
  76. Weakly typed nature and implicit type coercion: While already touched upon with loose equality, it's important to emphasize the broader implications. JavaScript's weak typing allows for values of different types to be used in operations where a specific type might be expected, with the language attempting to coerce the values to compatible types. This can be convenient but also a source of subtle bugs.
  77. Coercion and Equality:
    • Type Coercion: JavaScript often performs type coercion, meaning it will automatically convert between different data types. This can lead to unexpected results when comparing values or performing operations. For example, 5 == "5" will evaluate to true because JavaScript will convert the string "5" to the number 5 before comparing them. However, 5 === "5" will evaluate to false because the strict equality operator (===) does not perform type coercion.
    • Loose equality comparison (==): JavaScript's loose equality (==) performs type coercion before comparison, leading to surprising results (e.g., 0 == false). While some languages might have implicit conversions, JavaScript's loose equality rules are notoriously nuanced. Strict equality (===) is generally preferred.
    • Implicit Type Coercion: JavaScript often performs implicit type coercion, converting values from one type to another to accommodate operations. This can lead to surprising results, especially with loose equality comparisons.
    • Strict Equality (===): Strict equality avoids type coercion and compares both value and type, ensuring more predictable behavior. This distinction between loose and strict equality is not common in other languages.
  78. Memory Management (Garbage Collection):
    • Mark-and-sweep algorithm: JavaScript typically uses a mark-and-sweep algorithm to identify and reclaim unreachable objects.
    • Memory leaks (caused by unintended references): Memory leaks can occur when objects are unintentionally kept alive due to lingering references, preventing the garbage collector from reclaiming them. Understanding closures and event listeners is crucial for avoiding these leaks.
    • Weak references (WeakMap and WeakSet): As mentioned earlier, WeakMap and WeakSet hold "weak" references to objects, allowing the garbage collector to reclaim objects even if they are still referenced in these collections, helping prevent memory leaks.
  79. Lack of traditional classes (prior to ES6): Before ES6 (ECMAScript 2015), JavaScript didn't have traditional classes like other object-oriented languages. While the introduction of class syntax provided a more familiar syntax, it's essentially syntactic sugar over the existing prototype-based inheritance system, which remains a core distinction.
  80. Classes in ES6:
    • class keyword (syntactic sugar over prototypes): While the class keyword provides a more familiar syntax for defining classes, it's important to remember that JavaScript classes are still built upon the underlying prototype-based inheritance system. This differs from class-based inheritance in languages like Java or C++.
    • static methods and properties: JavaScript classes support static methods and properties, which belong to the class itself rather than to instances of the class. This is useful for utility functions or shared data associated with the class.
    • extends keyword (for inheritance): The extends keyword allows classes to inherit from other classes, establishing an inheritance hierarchy. While inheritance exists in other languages, JavaScript's prototype-based approach has distinct implications for how inheritance works.
    • super keyword (calling parent class methods/constructor): The super keyword is used to call methods or the constructor of the parent class, enabling code reuse and overriding behavior.
    • Mixins (achieving multiple inheritance-like behavior): While JavaScript doesn't directly support multiple inheritance, mixins provide a way to achieve similar functionality by combining the properties and methods of multiple objects into a single object. This is a common pattern facilitated by JavaScript's flexible object model and prototype system.
    • Private class features (using #): Newer JavaScript versions introduced private class fields, methods, and accessors using the # prefix. This adds true data privacy to classes, a feature missing in earlier versions of JavaScript where private members were typically emulated using closures.
  81. Object Model: JavaScript's object model is remarkably flexible. In addition to prototype-based inheritance, consider these points:
    • Dynamic Property Addition/Deletion: You can add or remove properties from objects at runtime, which isn't possible in many statically typed languages.
    • Property Attributes (Configurable, Enumerable, Writable): JavaScript properties have attributes (configurable, enumerable, writable) that control how they can be modified or accessed. This level of control over property behavior is not always present in other languages.
    • Property Getters and Setters: As mentioned earlier, defining getters and setters allows you to intercept property access and modification, enabling computed properties and other dynamic behaviors.
    • Function Context and this (in detail): The behavior of this is a frequent source of confusion for developers coming from other languages. The value of this depends on how a function is called:
  82. Different context and hierarchy context:
    • Global Context: In non-strict mode, this in a function called globally refers to the global object (window in browsers, global in Node.js).
    • Function Context: When a function is called as a method of an object, this refers to the object.
    • Constructor Context: When a function is called with new (as a constructor), this refers to the newly created object.
    • Arrow functions and lexical this: Arrow functions do not have their own this binding. Instead, this inside an arrow function refers to the this value of the enclosing lexical scope. This difference from regular functions is unique to JavaScript.
    • Variable Scope and Hoisting: Variable scope and hoisting can have unexpected consequences:
    • Function Scope (and lack of block scope with var): Variables declared with var have function scope, meaning they are accessible throughout the entire function they are defined in, regardless of block boundaries. This is different from languages with block scope.
    • Hoisting of var declarations: var declarations are hoisted to the top of their scope, but they are initialized with undefined until the assignment in the code is reached. This can lead to variables appearing to exist before their declaration.
    • let and const (block scope and temporal dead zone): let and const introduce block scope, but they also exhibit hoisting behavior, creating a "temporal dead zone" where accessing the variable before its declaration results in a ReferenceError. This behavior of let/const is somewhat unusual compared to block-scoped variables in other languages.
  83. this Keyword: The this keyword in JavaScript can be confusing because it can refer to different things depending on how a function is called. In a method of an object, this refers to the object itself. In a standalone function, this might refer to the global object or be undefined.
  84. Explicit Binding (.call, .apply, .bind): The .call, .apply, and .bind methods allow you to explicitly set the value of this when calling a function. This flexible binding is unusual in other languages. call, apply, and bind. These methods provide powerful ways to manipulate the execution context (specifically the value of this) of a function. Explicit Control over this: In many languages, this (or self) is determined implicitly. JavaScript's .call, .apply, and .bind provide explicit control, enabling flexible function reuse and dynamic context setting.
    • Function borrowing: You can "borrow" methods from one object and use them on another by setting this appropriately.
    • Partial Application (with .bind): .bind allows you to create new functions with pre-filled arguments, a form of partial application that's powerful for functional programming.
    • Asynchronous Programming: .bind is frequently used in asynchronous programming to ensure that callbacks retain the correct this value, even when called later in the event loop.
    • Creating bound functions for event handlers: bind is essential for setting the correct context (this) when passing methods as event handlers.
  85. Dynamically Computed fields: Computed fields in JavaScript (often used in the context of objects or classes) are properties whose values are dynamically calculated based on other properties or data. They are not stored directly but are computed on demand whenever they are accessed. This allows you to create properties that automatically reflect changes in other data, ensuring consistency and reducing redundant calculations.
  86. Array like objects: In JavaScript, an array-like object is any object that resembles an array but isn't a true Array instance. Examples of Array-Like Objects: arguments, NodeList Objects (from querySelectorAll), HTMLCollection Objects. Array-like objects don't have the standard array prototype methods. This makes direct manipulation (e.g., using map, filter) impossible without first converting them to true arrays.



ES6 context:



Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23>  <24>  <25
Link to this page: http://www.vb-net.com/JavascriptES6/Index.htm
<TAGS>  <ARTICLES>  <FRONT>  <CORE>  <MVC>  <ASP>  <NET>  <DATA>  <TASK>  <XML>  <KIOSK>  <NOTES>  <SQL>  <LINUX>  <MONO>  <FREEWARE>  <DOCS> <TRAVELS> <FLOWERS> <RESUME> < THANKS ME>