Git Product home page Git Product logo

kons-9's Introduction

kons-9

An IDE For 3D Production

Teaser trailer for the project:

https://www.youtube.com/watch?v=THMzaVDaZP8

kons-9 is a new 3D computer graphics and animation software system being developed as an open source project under the MIT license. It broadly falls under the category of a 3D digital content creation tool, while providing interesting and unique features not found in other systems. The intention is to develop a flexible and extensible system in which can be built a wide variety of application and domain specific tools and packages.

The unique differentiating aspect of kons-9 is that it combines the power of a software development IDE with the visual tools of 3D graphics authoring system. It does this by being implemented in Common Lisp, an object-oriented dynamic language which provides powerful facilities for exploratory development and rapid prototyping within a live interactive software environment.

This allows for unlimited extensibility of the system by both developers and users. In fact, this unique aspect of kons-9 erases the distinction between developers and end users. Code developed within the kons-9 framework is always first class, not limited to some arbitrary API or scripting language. The source code for the system is available for extension, customization and exploration, and development in new directions, all within a REPL-based integrated development environment operating on a live image of a 3D scene.

Every user of kons-9 has at their disposal the same full range of facilities and tools as the original developers of the system. Therefore code developed by them is first class in the sense that it has all the capabilities of code written by the developers of the system. There is no concept of a limited scripting language separate from the source code of the software.

Users of kons-9 are able to modify 3D classes, subclass and extend them, and add new behaviors as desired. The system is highly extensible and customizable to suit different application domains and workflow needs.

kons-9 can be used as a traditional user interface driven 3D application by general artists, or as a REPL-based development environment by technical artists and software developers. These two approaches can be seamlessly combined into a flexible and powerful workflow, where non-technical users can immediately benefit from software tools and extensions developed by technical users.

Developers work in a live image of their 3D scene, able to immediately see the results of their code in action. There is no need for a separate compile, link, and load process. Nor does the system have to be restarted to be updated. The REPL-based development experience is highly interactive with a continuous and tight feedback loop. Class and function definitions can be modified on the fly and the results seen immediately in the 3D scene. Incremental and exploratory development is facilitated and encouraged by the nature of the system.

Demo of an early version of the software:

https://youtu.be/NJe4isZ7NHI

How To Join The kons-9 Team

kons-9 is an open source project under the MIT license. We welcome those wishing to contribute their time and skills.

If you wish to do so, please:

  • Watch the project.
  • Turn on Notifications so you are aware of the Discussions postings.
  • Read the Introductions thread in Discussions.
  • Post your own introduction on the thread.
  • Join the Discussions and look at the open Issues.

How To Run kons-9

This code currently runs in SBCL on MacOS, Linux, and Windows. The system currently uses OpenGL as a graphics engine, though we are working on moving to Vulkan/Metal.

Download the code and load the local directory:

(push (uiop:getcwd) ql:*local-project-directories*)

Load the system:

(ql:quickload "kons-9")

Run the following code to open a 3D view window:

(in-package :kons-9)
(run)

Open test/demo-kernel.lisp and start evaluating the blocks of code for the demos. Things should appear in the graphics window. Try the other demo files as well.

Have fun.

Run the Testsuite as a Batch Job

Use development script development/testsuite to run the testsuite as a batch job. Specific tests can be requested by adding one argument to the command line, such as

development/testsuite exercise-clamp
development/testsuite testsuite-utils

The following command lists all available tests

development/testsuite list-all-available-tests

Run the Testsuite from the REPL

Load the system:

(ql:quickload "kons-9/testsuite")

List all available tests with

(kons-9/testsuite:list-available-tests)

Tests are implemented as regular functions and can be run with statements similar to

(kons-9/testsuite:run-all-tests)

or

(kons-9/testsuite:exercise-clamp)
(kons-9/testsuite:testsuite-utils)

Users not familiar with Confidence may want to review the quick introduction to Confidence.

API reference

The Kons-9 API reference manual is a work-in-progress.

This manual is generated using the PAX framework and the directives in src/api/api.lisp.

Updates are automatically published from the main branch using Github Actions.

Please contribute to the documentation as you study the Kons-9 source code!

Building the documentation

Build the documentation in HTML format from a Kons-9 Lisp image:

(require :kons-9/api-docs)
(pax:update-asdf-system-html-docs kons-9::@api :kons-9)

See PAX: Utilities for Generating Documentation. See also PAX: Documenting in Emacs for live Emacs-based documentation browsing.

Updating API example transcripts

PAX automatically verifies that all examples produce their expected results (see PAX: Transcripts). If the consistency checks fail then so will the documentation build and its associated Github Action.

To update a transcript, or create a new one, place the point immediately after the example code inside a docstring and run the Emacs command mgl-pax-transcribe-last-expression (see PAX: Transcribing with Emacs). See the examples in api.lisp for reference.

PAX transcripts should be formatted using this markdown syntax:

```cl-transcript (:dynenv pax-dynenv)
...lisp code...
```

The cl-transcript directive tells PAX to make consistency checks.

The :dynenv directive ensures that the checks are made in a suitable environment e.g. with a fixed random seed.

Pitfalls

  1. PAX transcript consistency-checks are sensitive to whitespace. Be careful not to edit the whitespace in the generated example output or else the consistency checks will fail. (Be careful of Emacs modes like ws-butler potentially causing problems by overzealously stripping trailing whitespace from inside string literals.)

  2. PAX emacs commands only started respecting the :dynenv directive in version 0.2.1 which at this time of writing has not yet landed in Quicklisp. If you update transcripts using an older version of the PAX Emacs Lisp code the environment (random seed) won't be locked down and the consistency checks might fail.

kons-9's People

Contributors

awolven avatar bigos avatar foretspaisibles avatar jmc-design avatar kaiwulf avatar kaveh808 avatar kayomarz avatar lukego avatar mikelevins avatar nsmoker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kons-9's Issues

plugin/procedural-polygon fails to compile

Branch: main
Commit: [7ff3015]
Platform: macOS 12.5.1, SBCL 2.2.6

Steps to reproduce:

  1. Start SBCL
  2. Load kons-9.asdf
  3. (asdf:load-system :kons-9)

Expected result: System loads. Can create demo window.

Actual result: COMPILE-FILE-ERROR while compiling "src/plugins/procedural-polygon"

Compiling the file separately yields:
procedural-polygon.lisp:86:1:
warning:
Duplicate definition for MAKE-CIRCLE found in one file.
--> DEFUN PROGN
==>
(EVAL-WHEN (:COMPILE-TOPLEVEL)
(SB-C:%COMPILER-DEFUN 'KONS-9::MAKE-CIRCLE T NIL NIL))

Text engine problem - black window

Branch: main
Platform: Devuan GNU/Linux x86_64, SBCL version 2.1.1.
Commit: 7ff3015
I have downloaded the latest sources and now when I try to start (run) or (run-1) I get a black window or a window with the background as in the gif. If I comment (:file "src/graphics/opengl/text") in kons-9.asd and the lines corresponding to the text engine in minimal-ui.lisp the window starts correctly. I think Kaveh had the same problem. I will investigate, see if I can make in work.

Peek 2022-09-03 11-28

sbcl MacOS port

Port the system to sbcl/MacOS/OpenGL. Need to get off CCL, as it doesn't run on the M1 chip.

Problem running kons-9

The problem is most likely because this system is so ancient, but FYI I was unsuccessful trying to run kons-9 on my only remaining Apple H/W:

Mac OS X 10.6.8
CCL 1.3

ASDF could not load kons-9 because Objective-C runtime exception:
-[NSCachedWhiteColor CGColor]: unrecognized selector sent to instance 0x146120.

Error: Objective-C runtime exception:
-[NSCachedWhiteColor CGColor]: unrecognized selector sent to instance 0x146120
While executing: CCL::CHECK-NS-EXCEPTION, in process Listener(4).

Explore Vulkan graphics

An idea...

We could take opengl.lisp as our display API and see if we can write a drop-in replacement using Vulkan.

Implement 3d picking of shapes

[Need someone for this.]

Initially by clicking on just shapes in the 3D view.

Requires some knowledge of OpenGL.

Later, it can be extended to mesh parts (face, edge, vertex) of poly-mesh at some point.

SBCL Port

Here will be some things needed for SBCL to work, platform independent

Reorganize demos

  • Split into different files.
  • More documentation.
  • Better organization.

motion is-active? demo

When an object becomes inactive and then activated some time later, it will jump to the position it would have been in had it not been inactive.
Is this the desired behaviour, or should an object resume from where it was left off?

Optimize OpenGL Drawing

Use vertex arrays and the like to speed up the current naive drawing code in opengl.lisp.

Explore glop integration

Let's see if we can implement the glfw functionality using glop, which some of you prefer.

The idea would be a rewrite of minimal-ui.lisp using glop.

add find-closest-point method

Implement a method find-closest-point for the class polyhedron. Ignore the shape's transform.

The returned point must be on the surface of a face, on an edge, or at a vertex or the polyhedron.

get mouse dragging working

Thanks to @jolby and @mikelevins , we now have a branch for testing the SBCL port: merge-ccl-sbcl.

Can someone with GLFW experience see about getting the mouse-dragged function in minimal-ui.lisp working so we can have 3D navigation? You can copy the code for mouse navigation from the CCL folder, or just get the function to be called and I'll do the rest.

demo-uv-mesh error

Branch: main
Commit: 7ff3015
Platform: Devuan GNU/Linux x86_64, SBCL version 2.1.1

When I try to run the first demo in demo-uv-mesh.lisp I get the following error:

The value
  (#(1.5 0.0 0.0 1.0) #(-1.5 0.0 0.0 1.0))
is not of type
  VECTOR
when binding #:LOOP-ACROSS-VECTOR-0
   [Condition of type TYPE-ERROR]

Restarts:
 0: [ABORT] Abort compilation.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] abort thread (#<THREAD "worker" RUNNING {100454B3B3}>)

Backtrace:
  0: (TRANSFORM-POINTS! (#(1.5 0.0 0.0 1.0) #(-1.5 0.0 0.0 1.0)) #2A((1.0 0.0 0.0 0.0) (0.0 1.0 0.0 0.0) (0.0 0.0 1.0 0.0) (0.0 0.0 -0.75 1.0)))
  1: ((:METHOD SWEEP-EXTRUDE-AUX (UV-MESH T T T T)) #<UV-MESH UV-MESH-10, 0 points, 0 faces, dims (2 2) {100459FC43}> (#(1.5 0.0 0.0 1.0) #(-1.5 0.0 0.0 1.0)) NIL #(#(0.0 0.0 -0.75 1.0) #(0.0 0.0 0.75 1.0)..
  2: (SB-FASL::LOAD-FASL-GROUP #S(SB-FASL::FASL-INPUT :STREAM #<SB-SYS:FD-STREAM for "file /tmp/slimeMEUJRN.fasl" {100459C673}> :TABLE #(8 #<PACKAGE "KONS-9"> CLEAR-SCENE SYMBOL-VALUE *SCENE* ADD-SHAPE .....
  3: (SB-FASL::LOAD-AS-FASL #<SB-SYS:FD-STREAM for "file /tmp/slimeMEUJRN.fasl" {100459C673}> NIL NIL)
  4: ((FLET SB-FASL::THUNK :IN LOAD))
  5: (SB-FASL::CALL-WITH-LOAD-BINDINGS #<FUNCTION (FLET SB-FASL::THUNK :IN LOAD) {7FEA3CB7DE4B}> #<SB-SYS:FD-STREAM for "file /tmp/slimeMEUJRN.fasl" {100459C673}>)
  6: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) #<SB-SYS:FD-STREAM for "file /tmp/slimeMEUJRN.fasl" {100459C673}> T)
  7: (LOAD #P"/tmp/slimeMEUJRN.fasl" :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST T :EXTERNAL-FORMAT :DEFAULT)
  8: ((FLET SWANK/BACKEND:CALL-WITH-COMPILATION-HOOKS :IN "/home/starkaiser/.emacs.d/elpa/slime-20220712.817/swank/sbcl.lisp") #<FUNCTION (LAMBDA NIL :IN SWANK/BACKEND:SWANK-COMPILE-STRING) {100459C52B}>)
  9: ((FLET SWANK/BACKEND:SWANK-COMPILE-STRING :IN "/home/starkaiser/.emacs.d/elpa/slime-20220712.817/swank/sbcl.lisp") "(with-clear-scene ..)
 10: ((LAMBDA NIL :IN SWANK:COMPILE-STRING-FOR-EMACS))
 11: ((LAMBDA NIL :IN SWANK::COLLECT-NOTES))
 12: (SWANK::MEASURE-TIME-INTERVAL #<FUNCTION (LAMBDA NIL :IN SWANK::COLLECT-NOTES) {10023A7ECB}>)
 13: (SWANK::COLLECT-NOTES #<FUNCTION (LAMBDA NIL :IN SWANK:COMPILE-STRING-FOR-EMACS) {10023A7E7B}>)
 14: (SWANK::CALL-WITH-BUFFER-SYNTAX NIL #<FUNCTION (LAMBDA NIL :IN SWANK:COMPILE-STRING-FOR-EMACS) {10023A7E2B}>)
 15: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK:COMPILE-STRING-FOR-EMACS "(with-clear-scene ..)
 16: (EVAL (SWANK:COMPILE-STRING-FOR-EMACS "(with-clear-scene ..)
 17: (SWANK:EVAL-FOR-EMACS (SWANK:COMPILE-STRING-FOR-EMACS "(with-clear-scene ..)
 18: ((LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD))
 19: (SWANK/SBCL::CALL-WITH-BREAK-HOOK #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD) {52BFC9CB}>)
 20: ((FLET SWANK/BACKEND:CALL-WITH-DEBUGGER-HOOK :IN "/home/starkaiser/.emacs.d/elpa/slime-20220712.817/swank/sbcl.lisp") #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORK..
 21: (SWANK::CALL-WITH-BINDINGS ((*STANDARD-INPUT* . #<SWANK/GRAY::SLIME-INPUT-STREAM {1002543E53}>)) #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD) {52BFCC3B}>)
 22: ((LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD))
 23: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 24: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::RUN))
 25: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 26: ((FLET "WITHOUT-INTERRUPTS-BODY-4" :IN SB-THREAD::RUN))
 27: (SB-THREAD::RUN)
 28: ("foreign function: call_into_lisp")
 29: ("foreign function: funcall1")

Similar for demo 07. All other demos work.

The value
  (#(-0.5 -9.184851e-17 0.0 1.0) #(6.123234e-17 -0.5 0.0 1.0)
   #(0.5 3.061617e-17 0.0 1.0) #(0.0 0.5 0.0 1.0))

is not of type
  VECTOR
when binding #:LOOP-ACROSS-VECTOR-0
   [Condition of type TYPE-ERROR]

Restarts:
 0: [ABORT] Abort compilation.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] abort thread (#<THREAD "worker" RUNNING {10018F3753}>)

Backtrace:
  0: (TRANSFORM-POINTS! (#(-0.5 -9.184851e-17 0.0 1.0) #(6.123234e-17 -0.5 0.0 1.0) #(0.5 3.061617e-17 0.0 1.0) #(0.0 0.5 0.0 1.0)) #2A((0.874994019659956d0 -0.27896714553936425d0 -0.3956803937935073d0 0.0..
  1: ((:METHOD SWEEP-EXTRUDE-AUX (UV-MESH T T T T)) #<UV-MESH UV-MESH-12, 0 points, 0 faces, dims (4 65) {1001977063}> (#(-0.5 -9.184851e-17 0.0 1.0) #(6.123234e-17 -0.5 0.0 1.0) #(0.5 3.061617e-17 0.0 1.0..
  2: (SB-FASL::LOAD-FASL-GROUP #S(SB-FASL::FASL-INPUT :STREAM #<SB-SYS:FD-STREAM for "file /tmp/slimegpC8yR.fasl" {10019712B3}> :TABLE #(17 #<PACKAGE "KONS-9"> CLEAR-SCENE SYMBOL-VALUE *SCENE* MAKE-SINE-CU..
  3: (SB-FASL::LOAD-AS-FASL #<SB-SYS:FD-STREAM for "file /tmp/slimegpC8yR.fasl" {10019712B3}> NIL NIL)
  4: ((FLET SB-FASL::THUNK :IN LOAD))
  5: (SB-FASL::CALL-WITH-LOAD-BINDINGS #<FUNCTION (FLET SB-FASL::THUNK :IN LOAD) {7FEA3CB7DE4B}> #<SB-SYS:FD-STREAM for "file /tmp/slimegpC8yR.fasl" {10019712B3}>)
  6: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) #<SB-SYS:FD-STREAM for "file /tmp/slimegpC8yR.fasl" {10019712B3}> T)
  7: (LOAD #P"/tmp/slimegpC8yR.fasl" :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST T :EXTERNAL-FORMAT :DEFAULT)
  8: ((FLET SWANK/BACKEND:CALL-WITH-COMPILATION-HOOKS :IN "/home/starkaiser/.emacs.d/elpa/slime-20220712.817/swank/sbcl.lisp") #<FUNCTION (LAMBDA NIL :IN SWANK/BACKEND:SWANK-COMPILE-STRING) {100197116B}>)
  9: ((FLET SWANK/BACKEND:SWANK-COMPILE-STRING :IN "/home/starkaiser/.emacs.d/elpa/slime-20220712.817/swank/sbcl.lisp") "(with-clear-scene ..)
 10: ((LAMBDA NIL :IN SWANK:COMPILE-STRING-FOR-EMACS))
 11: ((LAMBDA NIL :IN SWANK::COLLECT-NOTES))
 12: (SWANK::MEASURE-TIME-INTERVAL #<FUNCTION (LAMBDA NIL :IN SWANK::COLLECT-NOTES) {100196076B}>)
 13: (SWANK::COLLECT-NOTES #<FUNCTION (LAMBDA NIL :IN SWANK:COMPILE-STRING-FOR-EMACS) {100196071B}>)
 14: (SWANK::CALL-WITH-BUFFER-SYNTAX NIL #<FUNCTION (LAMBDA NIL :IN SWANK:COMPILE-STRING-FOR-EMACS) {10019606CB}>)
 15: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK:COMPILE-STRING-FOR-EMACS "(with-clear-scene ..)
 16: (EVAL (SWANK:COMPILE-STRING-FOR-EMACS "(with-clear-scene ..)
 17: (SWANK:EVAL-FOR-EMACS (SWANK:COMPILE-STRING-FOR-EMACS "(with-clear-scene ..)
 18: ((LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD))
 19: (SWANK/SBCL::CALL-WITH-BREAK-HOOK #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD) {52BFC9CB}>)
 20: ((FLET SWANK/BACKEND:CALL-WITH-DEBUGGER-HOOK :IN "/home/starkaiser/.emacs.d/elpa/slime-20220712.817/swank/sbcl.lisp") #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORK..
 21: (SWANK::CALL-WITH-BINDINGS ((*STANDARD-INPUT* . #<SWANK/GRAY::SLIME-INPUT-STREAM {1002543E53}>)) #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD) {52BFCC3B}>)
 22: ((LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD))
 23: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 24: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::RUN))
 25: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 26: ((FLET "WITHOUT-INTERRUPTS-BODY-4" :IN SB-THREAD::RUN))
 27: (SB-THREAD::RUN)
 28: ("foreign function: call_into_lisp")
 29: ("foreign function: funcall1")

BUG: shading wrong when window re-opened

Looking for a volunteer for this.

This is a bug on both MacOS and Linux, so is probably an OpenGL issue.

Open window.
Create polyhedron.
Close window.
Open window.
Shading is much brighter.

I suspect some OpenGL state is not being reset properly.

bug: src/kernel/item not loaded

kons-9.asd does not load src/hernel/item.lisp in commit e85f7d9.

Adding (:file "src/kernel/scene-item") to the components before (:file "src/kernel/scene") appears to resolve the issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.