├── .gitignore ├── CNAME ├── README.md ├── _config.yml ├── _layouts └── default.html ├── hal.css ├── hal_specification.md ├── info-model.png └── resource_blot.png /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | hal.stateless.co -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HAL - Hypertext Application Language 2 | 3 | ## A lean hypermedia type 4 | 5 | HAL is a simple way of linking with JSON or XML. 6 | 7 | It provides a small set of conventions on top of JSON and XML for 8 | expressing hyperlinks to, and embeddedness of, related resources. 9 | 10 | The spec is here: [hal\_specification.md][1]. 11 | 12 | For a friendlier, more practical introduction to HAL you can read this 13 | article: [JSON Linking with HAL][2]. 14 | 15 | The JSON variant of HAL (application/hal+json) has now been published as 16 | an internet draft: 17 | [draft-kelly-json-hal][5]. 18 | 19 | ## Discussion Group 20 | 21 | If you have any questions or feedback about HAL, you can message the 22 | [HAL-discuss mailing list][3]. 23 | 24 | ## Contributing 25 | If you think some part of the spec needs changing, just fork this repo 26 | and raise a pull request with your changes. 27 | 28 | ## Code/Libraries 29 | hal_specification.md contains [a list of libraries for working with HAL][4]. 30 | 31 | [1]: https://github.com/mikekelly/hal_specification/blob/master/hal_specification.md 32 | [2]: http://blog.stateless.co/post/13296666138/json-linking-with-hal 33 | [3]: http://groups.google.com/group/hal-discuss 34 | [4]: https://github.com/mikekelly/hal_specification/wiki/Libraries 35 | [5]: http://tools.ietf.org/html/draft-kelly-json-hal 36 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | safe: true 2 | auto: false 3 | server: false 4 | server_port: 4000 5 | baseurl: / 6 | url: http://localhost:4000 7 | 8 | source: . 9 | destination: ./_site 10 | plugins: ./_plugins 11 | 12 | future: true 13 | lsi: false 14 | pygments: true 15 | markdown: redcarpet 16 | permalink: date 17 | 18 | maruku: 19 | use_tex: false 20 | use_divs: false 21 | png_engine: blahtex 22 | png_dir: images/latex 23 | png_url: /images/latex 24 | 25 | rdiscount: 26 | extensions: [] 27 | 28 | kramdown: 29 | auto_ids: true, 30 | footnote_nr: 1 31 | entity_output: as_char 32 | toc_levels: 1..6 33 | use_coderay: false 34 | 35 | coderay: 36 | coderay_wrap: div 37 | coderay_line_numbers: inline 38 | coderay_line_numbers_start: 1 39 | coderay_tab_width: 4 40 | coderay_bold_every: 10 41 | coderay_css: style 42 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% if page.title %} {{ page.title }} | {% endif %} The Hypertext Application Language 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 | {{ content }} 17 |
18 | 19 | 20 | 21 |
22 | 23 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /hal.css: -------------------------------------------------------------------------------- 1 | html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } 2 | 3 | body{ 4 | color:#444; 5 | font-family: Helvetica, sans-serif; 6 | font-size:12px; 7 | line-height:1.5em; 8 | padding:1em; 9 | margin:auto; 10 | max-width:960px; 11 | width: 960px; 12 | background:#fefefe; 13 | } 14 | 15 | a{ color: #0645ad; text-decoration:none;} 16 | a:visited{ color: #0b0080; } 17 | a:hover{ color: #06e; } 18 | a:active{ color:#faa700; } 19 | a:focus{ outline: thin dotted; } 20 | a:hover, a:active{ outline: 0; } 21 | 22 | ::-moz-selection{background:rgba(255,255,0,0.3);color:#000} 23 | ::selection{background:rgba(255,255,0,0.3);color:#000} 24 | 25 | a::-moz-selection{background:rgba(255,255,0,0.3);color:#0645ad} 26 | a::selection{background:rgba(255,255,0,0.3);color:#0645ad} 27 | 28 | p{ 29 | margin:1em 0; 30 | } 31 | 32 | img{ 33 | max-width:100%; 34 | } 35 | 36 | h1,h2,h3,h4,h5,h6{ 37 | font-weight:normal; 38 | color:#111; 39 | line-height:1em; 40 | } 41 | h4,h5,h6{ font-weight: bold; } 42 | h1{ font-size:2.5em; } 43 | h2{ font-size:2em; } 44 | h3{ font-size:1.5em; } 45 | h4{ font-size:1.2em; } 46 | h5{ font-size:1em; } 47 | h6{ font-size:0.9em; } 48 | 49 | blockquote{ 50 | color:#666666; 51 | margin:0; 52 | padding-left: 3em; 53 | border-left: 0.5em #EEE solid; 54 | } 55 | hr { display: block; height: 2px; border: 0; border-top: 1px solid #aaa;border-bottom: 1px solid #eee; margin: 1em 0; padding: 0; } 56 | pre, code, kbd, samp { color: #000; font-family: monospace, monospace; _font-family: 'courier new', monospace; font-size: 0.98em; } 57 | pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } 58 | 59 | b, strong { font-weight: bold; } 60 | 61 | dfn { font-style: italic; } 62 | 63 | ins { background: #ff9; color: #000; text-decoration: none; } 64 | 65 | mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; } 66 | 67 | sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } 68 | sup { top: -0.5em; } 69 | sub { bottom: -0.25em; } 70 | 71 | ul, ol { margin: 1em 0; padding: 0 0 0 2em; } 72 | li p:last-child { margin:0 } 73 | dd { margin: 0 0 0 2em; } 74 | 75 | img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } 76 | 77 | table { border-collapse: collapse; border-spacing: 0; } 78 | td { vertical-align: top; } 79 | 80 | @media only screen and (min-width: 480px) { 81 | body{font-size:14px;} 82 | } 83 | 84 | @media only screen and (min-width: 768px) { 85 | body{font-size:16px;} 86 | } 87 | 88 | @media print { 89 | * { background: transparent !important; color: black !important; filter:none !important; -ms-filter: none !important; } 90 | body{font-size:12pt; max-width:100%;} 91 | a, a:visited { text-decoration: underline; } 92 | hr { height: 1px; border:0; border-bottom:1px solid black; } 93 | a[href]:after { content: " (" attr(href) ")"; } 94 | abbr[title]:after { content: " (" attr(title) ")"; } 95 | .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } 96 | pre, blockquote { border: 1px solid #999; padding-right: 1em; page-break-inside: avoid; } 97 | tr, img { page-break-inside: avoid; } 98 | img { max-width: 100% !important; } 99 | @page :left { margin: 15mm 20mm 15mm 10mm; } 100 | @page :right { margin: 15mm 10mm 15mm 20mm; } 101 | p, h2, h3 { orphans: 3; widows: 3; } 102 | h2, h3 { page-break-after: avoid; } 103 | } 104 | 105 | div.highlight { 106 | background-color: #f8f8ff; 107 | border: 1px solid #DDD; 108 | padding: 15px; 109 | font-size: 14px; 110 | line-height: 16px; 111 | font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace; 112 | } 113 | 114 | /* pygmentize -S default -f html */ 115 | .hll { background-color: #ffffcc } 116 | .c { color: #408080; font-style: italic } /* Comment */ 117 | .err { border: 1px solid #FF0000 } /* Error */ 118 | .k { color: #008000; font-weight: bold } /* Keyword */ 119 | .o { color: #666666 } /* Operator */ 120 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 121 | .cp { color: #BC7A00 } /* Comment.Preproc */ 122 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 123 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 124 | .gd { color: #A00000 } /* Generic.Deleted */ 125 | .ge { font-style: italic } /* Generic.Emph */ 126 | .gr { color: #FF0000 } /* Generic.Error */ 127 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 128 | .gi { color: #00A000 } /* Generic.Inserted */ 129 | .go { color: #808080 } /* Generic.Output */ 130 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 131 | .gs { font-weight: bold } /* Generic.Strong */ 132 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 133 | .gt { color: #0040D0 } /* Generic.Traceback */ 134 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 135 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 136 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 137 | .kp { color: #008000 } /* Keyword.Pseudo */ 138 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 139 | .kt { color: #B00040 } /* Keyword.Type */ 140 | .m { color: #666666 } /* Literal.Number */ 141 | .s { color: #BA2121 } /* Literal.String */ 142 | .na { color: #7D9029 } /* Name.Attribute */ 143 | .nb { color: #008000 } /* Name.Builtin */ 144 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 145 | .no { color: #880000 } /* Name.Constant */ 146 | .nd { color: #AA22FF } /* Name.Decorator */ 147 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 148 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 149 | .nf { color: #0000FF } /* Name.Function */ 150 | .nl { color: #A0A000 } /* Name.Label */ 151 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 152 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 153 | .nv { color: #19177C } /* Name.Variable */ 154 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 155 | .w { color: #bbbbbb } /* Text.Whitespace */ 156 | .mf { color: #666666 } /* Literal.Number.Float */ 157 | .mh { color: #666666 } /* Literal.Number.Hex */ 158 | .mi { color: #666666 } /* Literal.Number.Integer */ 159 | .mo { color: #666666 } /* Literal.Number.Oct */ 160 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 161 | .sc { color: #BA2121 } /* Literal.String.Char */ 162 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 163 | .s2 { color: #BA2121 } /* Literal.String.Double */ 164 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 165 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 166 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 167 | .sx { color: #008000 } /* Literal.String.Other */ 168 | .sr { color: #BB6688 } /* Literal.String.Regex */ 169 | .s1 { color: #BA2121 } /* Literal.String.Single */ 170 | .ss { color: #19177C } /* Literal.String.Symbol */ 171 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 172 | .vc { color: #19177C } /* Name.Variable.Class */ 173 | .vg { color: #19177C } /* Name.Variable.Global */ 174 | .vi { color: #19177C } /* Name.Variable.Instance */ 175 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 176 | -------------------------------------------------------------------------------- /hal_specification.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | # HAL - Hypertext Application Language 5 | ## A lean hypermedia type 6 | 7 | * __Author:__ [Mike Kelly][1] <[mike@stateless.co](mailto:mike@stateless.co)> 8 | * __Created:__ 2011-06-13 9 | * __Updated:__ 2013-09-18 (Updated) 10 | 11 | ## Summary 12 | HAL is a simple format that gives a consistent and easy way to 13 | hyperlink between resources in your API. 14 | 15 | Adopting HAL will make your API explorable, and its documentation easily 16 | discoverable from within the API itself. In short, it will make your API 17 | easier to work with and therefore more attractive to client developers. 18 | 19 | APIs that adopt HAL can be easily served and consumed using open source 20 | libraries available for most major programming languages. It's also 21 | simple enough that you can just deal with it as you would any other 22 | JSON. 23 | 24 | ## About The Author 25 | Mike Kelly is a software engineer from the UK. He runs an [API 26 | consultancy][1] helping companies design and build beautiful APIs that 27 | developers love. 28 | 29 | ## Quick links 30 | * [A demo API using HAL called HAL Talk][12] 31 | * [A list of libraries for working with HAL (Obj-C, Ruby, JS, PHP, C#, 32 | etc.)][14] 33 | * [A list of public hypermedia APIs using HAL][15] 34 | * [Discussion group (questions, feedback, etc)][2] 35 | 36 | ## General Description 37 | HAL provides a set of conventions for expressing hyperlinks in either 38 | JSON or XML. 39 | 40 | **The rest of a HAL document is just plain old JSON or XML.** 41 | 42 | Instead of using ad-hoc structures, or spending valuable time designing 43 | your own format; you can adopt HAL's conventions and focus on building 44 | and documenting the data and transitions that make up your API. 45 | 46 | HAL is a little bit like HTML for machines, in that it is generic and 47 | designed to drive many different types of application via hyperlinks. 48 | The difference is that HTML has features for helping 'human actors' move 49 | through a web application to achieve their goals, whereas HAL is 50 | intended for helping 'automated actors' move through a web API to 51 | achieve their goals. 52 | 53 | Having said that, **HAL is actually very human-friendly too**. Its 54 | conventions make the documentation for an API discoverable from the API 55 | messages themselves. This makes it possible for developers to jump 56 | straight into a HAL-based API and explore its capabilities, without the 57 | cognitive overhead of having to map some out-of-band documentation onto 58 | their journey. 59 | 60 | ## Examples 61 | 62 | The example below is how you might represent a collection of orders with 63 | hal+json. Things to look for: 64 | 65 | * The URI of the main resource being represented ('/orders') expressed 66 | with a self link 67 | * The 'next' link pointing to the next page of orders 68 | * A templated link called 'ea:find' for searching orders by id 69 | * The multiple 'ea:admin' link objects contained in an array 70 | * Two properties of the orders collection; 'currentlyProcessing' and 71 | 'shippedToday' 72 | * Embedded order resources with their own links and properties 73 | * The compact URI (curie) named 'ea' for expanding the name of the 74 | links to their documentation URL 75 | 76 | ### application/hal+json 77 | ```javascript 78 | { 79 | "_links": { 80 | "self": { "href": "/orders" }, 81 | "curies": [{ "name": "ea", "href": "http://example.com/docs/rels/{rel}", "templated": true }], 82 | "next": { "href": "/orders?page=2" }, 83 | "ea:find": { 84 | "href": "/orders{?id}", 85 | "templated": true 86 | }, 87 | "ea:admin": [{ 88 | "href": "/admins/2", 89 | "title": "Fred" 90 | }, { 91 | "href": "/admins/5", 92 | "title": "Kate" 93 | }] 94 | }, 95 | "currentlyProcessing": 14, 96 | "shippedToday": 20, 97 | "_embedded": { 98 | "ea:order": [{ 99 | "_links": { 100 | "self": { "href": "/orders/123" }, 101 | "ea:basket": { "href": "/baskets/98712" }, 102 | "ea:customer": { "href": "/customers/7809" } 103 | }, 104 | "total": 30.00, 105 | "currency": "USD", 106 | "status": "shipped" 107 | }, { 108 | "_links": { 109 | "self": { "href": "/orders/124" }, 110 | "ea:basket": { "href": "/baskets/97213" }, 111 | "ea:customer": { "href": "/customers/12369" } 112 | }, 113 | "total": 20.00, 114 | "currency": "USD", 115 | "status": "processing" 116 | }] 117 | } 118 | } 119 | ``` 120 | 121 | ## The HAL Model 122 | 123 | The HAL conventions revolve around representing two simple concepts: _Resources_ and _Links_. 124 | 125 | ### Resources 126 | Resources have: 127 | 128 | * Links (to URIs) 129 | * Embedded Resources (i.e. other resources contained within them) 130 | * State (your bog standard JSON or XML data) 131 | 132 | ### Links 133 | Links have: 134 | 135 | * A target (a URI) 136 | * A relation aka. 'rel' (the name of the link) 137 | * A few other optional properties to help with deprecation, content 138 | negotiation, etc. 139 | 140 | Below is an image that roughly illustrates how a HAL representation is 141 | structured: 142 | 143 | ![The HAL Information model][4] 144 | 145 | ## How HAL is used in APIs 146 | HAL is designed for building APIs in which clients navigate around the 147 | resources by following links. 148 | 149 | Links are identified by link relations. Link relations are the lifeblood 150 | of a hypermedia API: they are how you tell client developers about 151 | what resources are available and how they can be interacted with, and 152 | they are how the code they write will select which link to traverse. 153 | 154 | Link relations are not just an identifying string in HAL, though. They 155 | are actually URLs, which developers can follow in order to read the 156 | documentation for a given link. This is what is known as 157 | "discoverability". The idea is that a developer can enter into your API, 158 | read through documentation for the available links, and then 159 | follow-their-nose through the API. 160 | 161 | HAL encourages the use of link relations to: 162 | 163 | * Identify links and embedded resources within the representation 164 | * Infer the expected structure and meaning of target resources 165 | * Signalling what requests and representations can be submitted to target resources 166 | 167 | ## How to serve HAL 168 | HAL has a media type for both the JSON and XML variants, whos names are 169 | `application/hal+json` and `application/hal+xml` respectively. 170 | 171 | When serving HAL over HTTP, the `Content-Type` of the response should 172 | contain the relevant media type name. 173 | 174 | ## The structure of a HAL document 175 | 176 | ### Minimum valid document 177 | A HAL document must at least contain an empty resource. 178 | 179 | An empty JSON object: 180 | 181 | ```javascript 182 | {} 183 | ``` 184 | 185 | ### Resources 186 | In most cases, resources should have a self URI 187 | 188 | Represented via a 'self' link: 189 | 190 | ```javascript 191 | { 192 | "_links": { 193 | "self": { "href": "/example_resource" } 194 | } 195 | } 196 | ``` 197 | 198 | ### Links 199 | Links must be contained directly within a resource: 200 | 201 | Links are represented as JSON object contained within a `_links` hash 202 | that must be a direct property of a resource object: 203 | 204 | ```javascript 205 | { 206 | "_links": { 207 | "next": { "href": "/page=2" } 208 | } 209 | } 210 | ``` 211 | 212 | #### Link Relations 213 | Links have a relation (aka. 'rel'). This indicates the semantic - 214 | the meaning - of a particular link. 215 | 216 | Link rels are the main way of distinguishing between a resource's links. 217 | 218 | It's basically just a key within the `_links` hash, associating the link meaning 219 | (the 'rel') with the link object that contains data like the actual 'href' value: 220 | 221 | ```javascript 222 | { 223 | "_links": { 224 | "next": { "href": "/page=2" } 225 | } 226 | } 227 | ``` 228 | 229 | #### API Discoverability 230 | Link rels should be URLs which reveal documentation about the 231 | given link, making them "discoverable". URLs are generally quite long 232 | and a bit nasty for use as keys. To get around this, HAL provides 233 | "CURIEs" which are basically named tokens that you can define in the 234 | document and use to express link relation URIs in a friendlier, more 235 | compact fashion i.e. `ex:widget` instead of 236 | `http://example.com/rels/widget`. The details are available in the 237 | section on CURIEs a bit further down. 238 | 239 | ### Representing Multiple Links With The Same Relation 240 | A resource may have multiple links that share the same link relation. 241 | 242 | For link relations that may have multiple links, we use an array of 243 | links. 244 | 245 | ```javascript 246 | { 247 | "_links": { 248 | "items": [{ 249 | "href": "/first_item" 250 | },{ 251 | "href": "/second_item" 252 | }] 253 | } 254 | } 255 | ``` 256 | 257 | **Note:** If you're unsure whether the link should be singular, assume it 258 | will be multiple. If you pick singular and find you need to change it, 259 | you will need to create a new link relation or face breaking existing 260 | clients. 261 | 262 | ### CURIEs 263 | 264 | "CURIE"s help providing links to resource documentation. 265 | 266 | HAL gives you a reserved link relation 'curies' which you can use to hint at the location of resource documentation. 267 | 268 | ```javascript 269 | "_links": { 270 | "curies": [ 271 | { 272 | "name": "doc", 273 | "href": "http://haltalk.herokuapp.com/docs/{rel}", 274 | "templated": true 275 | } 276 | ], 277 | 278 | "doc:latest-posts": { 279 | "href": "/posts/latest" 280 | } 281 | } 282 | ``` 283 | 284 | There can be multiple links in the 'curies' section. They come with a 'name' and a templated 'href' which must 285 | contain the `{rel}` placeholder. 286 | 287 | Links in turn can then prefix their 'rel' with a CURIE name. Associating the `latest-posts` link with the `doc` 288 | documentation CURIE results in a link 'rel' set to `doc:latest-posts`. 289 | 290 | To retrieve documentation about the `latest-posts` resource, the client will expand the associated CURIE link 291 | with the actual link's 'rel'. This would result in a URL `http://haltalk.herokuapp.com/docs/latest-posts` which 292 | is expected to return documentation about this resource. 293 | 294 | 295 | ## To be continued... 296 | This relatively informal specification of HAL is incomplete and still in 297 | progress. For now, if you would like to have a full understanding please 298 | read the [formal specification][13]. 299 | 300 | ## RFC 301 | The JSON variant of HAL (application/hal+json) has now been published as 302 | an internet draft: [draft-kelly-json-hal][13]. 303 | 304 | ## Acknowledgements 305 | 306 | * Darrel Miller 307 | * Mike Amundsen 308 | * Mark Derricutt 309 | * Herman Radtke 310 | * Will Hartung 311 | * Steve Klabnik 312 | * everyone on hal-discuss 313 | 314 | Thanks for the help :) 315 | 316 | ## Notes/todo 317 | 318 | [1]: http://stateless.co/ 319 | [2]: http://groups.google.com/group/hal-discuss 320 | [3]: http://blog.stateless.co/post/13296666138/json-linking-with-hal 321 | [4]: http://stateless.co/info-model.png 322 | [5]: http://tools.ietf.org/html/rfc2119 323 | [6]: http://tools.ietf.org/html/rfc5988#section-5.1 324 | [7]: http://tools.ietf.org/html/rfc5988 325 | [8]: http://tools.ietf.org/html/rfc5988#section-5.3 326 | [9]: http://tools.ietf.org/html/rfc5988#section-5.4 327 | [10]: http://www.w3.org/TR/curie/ 328 | [11]: http://tools.ietf.org/html/rfc6570 329 | [12]: http://haltalk.herokuapp.com/ 330 | [13]: http://tools.ietf.org/html/draft-kelly-json-hal 331 | [14]: https://github.com/mikekelly/hal_specification/wiki/Libraries 332 | [15]: https://github.com/mikekelly/hal_specification/wiki/APIs 333 | -------------------------------------------------------------------------------- /info-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikekelly/hal_specification/4489093925ffaa13bd8be5af2f20caa8dcf1f142/info-model.png -------------------------------------------------------------------------------- /resource_blot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikekelly/hal_specification/4489093925ffaa13bd8be5af2f20caa8dcf1f142/resource_blot.png --------------------------------------------------------------------------------