commit 7ec86162d57e687baeee203c7329e0de72546922 Author: Florent Revest Date: Sun Jun 25 16:39:19 2017 +0200 Initial commit. diff --git a/.assemblerc.yml b/.assemblerc.yml new file mode 100644 index 0000000..5de7888 --- /dev/null +++ b/.assemblerc.yml @@ -0,0 +1,77 @@ +# ============================================= +# ASSEMBLE CONFIG +# ============================================= + +# Dest config +root: _asteroidos.org +dest: <%= site.root %> + +# ============================================= +# SOURCE CONFIG +# ============================================= + +# Assets > fonts, icons, images etc. +assets: assets +images: <%= site.assets %>/images +fonts: <%= site.assets %>/fonts + +# Styles +styles: styles + +# Scripts +scripts: scripts + +# Pages +pages: pages + +# ============================================= +# TEMPLATES +# ============================================= + +# Base directory for templates +templates: templates + +# Partials +includes: <%= site.templates %>/includes +snippets: <%= site.templates %>/snippets + +# Layouts +layouts: <%= site.templates %>/layouts +layoutext: .hbs +layout: content + +# ============================================= +# EXTENSIONS +# ============================================= + +helpers: <%= site.templates %>/_helpers +plugins: + # npm + - assemble-contrib-permalinks + + # local + - <%= site.templates %>/_plugins/navigation.js + - <%= site.templates %>/_plugins/holder-404-avoid.js + + +# ============================================= +# SITE METADATA +# ============================================= + +# Site metadata +brand: asteroidos.org +title: AsteroidOS +lead: AsteroidOS - An open-source operating system for smartwatches. +description: > + AsteroidOS is an open-source operating system for smartwatches. + +# URLs +homepage: http://asteroidos.org + +# ============================================= +# SEO/SEM +# ============================================= + +analytics: + google: false + google_site_id: false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..845d282 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# Enforce Unix newlines, in case users don't have core.autocrlf set. +*.* text=lf +*.* text eol=lf +*.* eol=lf + +*.jpg binary +*.gif binary +*.png binary +*.jpeg binary \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5312b75 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# live site +_gh_pages +_asteroidos.org + +# node.js +node_modules +npm-debug.log + +# local dev +tmp +temp +vendor +TODO.md +*.sublime-* +.idea diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..9617e7a --- /dev/null +++ b/.jshintrc @@ -0,0 +1,14 @@ +{ + "esnext": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "sub": true, + "undef": true, + "boss": true, + "eqnull": true, + "node": true +} diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..f2f646f --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,209 @@ +/* + * asteroidos.org + * + * Copyright (c) 2017, Florent Revest, Alexis Sellier, Less Core Team, contributors. + * Licensed under the MIT license. + */ + +'use strict'; + +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + + // Project metadata + pkg: grunt.file.readJSON('package.json'), + site: grunt.file.readYAML('.assemblerc.yml'), + + jshint: { + options: { + jshintrc: '.jshintrc' + }, + all: ['Gruntfile.js', '<%= site.helpers %>/*.js'] + }, + + // Build HTML from templates and data + assemble: { + options: { + flatten: true, + production: false, + assets: '<%= site.dest %>/public', + + // Metadata + pkg: '<%= pkg %>', // extend the context with `pkg` + site: '<%= site %>', // extend the context with `site` + + // Templates + partials: '<%= site.includes %>/*.hbs', + layoutdir: '<%= site.layouts %>', + layoutext: '<%= site.layoutext %>', + layout: '<%= site.layout %>', + + // Extensions + // mixins: ['<%= site.mixins %>/utils.js'], + helpers: ['<%= site.helpers %>/*.js'], + plugins: ['<%= site.plugins %>'], + + // `compose` helper options + compose: {cwd: 'pages'}, + + // markdown options + marked: { + process: true, + + // highlight.js options + prefix: 'lang-' + } + }, + site: { + options: { + permalinks: {preset: 'pretty'}, + partials: ['pages/**/*.md'] + }, + src: '<%= site.pages %>/*.hbs', + dest: '<%= site.dest %>/' + }, + wiki: { + options: { + permalinks: {preset: 'pretty'}, + partials: ['pages/**/*.md'] + }, + src: '<%= site.pages %>/wiki/*.hbs', + dest: '<%= site.dest %>/wiki/' + }, + install: { + options: { + permalinks: {preset: 'pretty'}, + partials: ['pages/**/*.md'] + }, + src: '<%= site.pages %>/install/*.hbs', + dest: '<%= site.dest %>/install/' + } + }, + + prettify: { + site: { + files: [ + { + expand: true, + cwd: '<%= site.dest %>', + src: '*.html', + dest: '<%= site.dest %>/', + ext: '.html' + } + ] + } + }, + + connect: { + options: { + port: 9000, + livereload: 35729, + hostname: 'localhost' + }, + livereload: { + options: { + open: true, + base: ['<%= site.dest %>'] + } + } + }, + + // Compile Less to CSS + less: { + options: { + paths: ['styles/bootstrap', 'styles/components'] + }, + site: { + src: ['styles/index.less'], + dest: '<%= assemble.options.assets %>/css/index.css' + } + }, + + // Copy source assets to _gh_pages + copy: { + assets: { + files: [ + { + expand: true, + cwd: '<%= site.assets %>/public', + src: ['**'], + dest: '<%= site.dest %>/public/' + }, + { + expand: true, + cwd: '<%= site.assets %>/root', + src: ['*'], + dest: '<%= site.dest %>/', + rename: function (dest, src) { + dest = dest + src.replace(/^_/, ''); + return dest; + } + } + ] + } + }, + + watch: { + options: {livereload: true }, + styles: { + files: ['<%= site.styles %>/**/*.less'], + tasks: ['less:site'] + }, + pages: { + files: ['<%= site.pages %>/**/*.hbs'], + tasks: ['assemble:site'] + }, + wiki: { + files: ['<%= site.pages %>/**/**/*.hbs'], + tasks: ['assemble:wiki'] + }, + install: { + files: ['<%= site.pages %>/**/**/*.hbs'], + tasks: ['assemble:install'] + }, + templates: { + files: ['<%= site.templates %>/**/*.hbs'], + tasks: ['assemble:site'] + }, + assets: { + files: ['<%= site.assets %>/**/*.*'], + tasks: ['copy'] + } + } + }); + + // Load npm plugins to provide necessary tasks. + grunt.loadNpmTasks('assemble'); + grunt.loadNpmTasks('assemble-less'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-prettify'); + grunt.loadNpmTasks('grunt-repos'); + grunt.loadNpmTasks('grunt-sync-pkg'); + grunt.loadNpmTasks('grunt-http-download'); + + grunt.registerTask('design', [ + 'copy', + 'less:site', + 'assemble:site', + 'assemble:wiki', + 'assemble:install', + 'connect', + 'watch' + ]); + + // Default tasks to be run. + grunt.registerTask('default', [ + 'jshint', + 'copy', + 'less:site', + 'assemble:site', + 'assemble:wiki', + 'assemble:install' + ]); +}; diff --git a/LICENSE-CC b/LICENSE-CC new file mode 100644 index 0000000..1d658d6 --- /dev/null +++ b/LICENSE-CC @@ -0,0 +1,319 @@ +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at http://creativecommons.org/. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..da10a8f --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,23 @@ +Copyright (c) 2017 Florent Revest +Copyright (c) 2013 Alexis Sellier, Less.js, contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..74eb064 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# asteroidos.org + +> Official website and documentation for AsteroidOS + +## Quickstart + +Assemble and Grunt are used to build the site. To get started: + +1. Clone this repository +2. In the root of the repo, run `npm install` +3. Run the `grunt` command to build the site + +If all worked properly, you should have your website ready in an '_asteroidos.org' folder + +## License +This website is a fork of lesscss.org + +Copyright (c) 2017, Florent Revest, Alexis Sellier, Less Core Team, Contributors +Content released under [Creative Commons](./LICENSE-CC). +Source code released under the [MIT License](./LICENSE-MIT). diff --git a/assets/public/font/ionicons.eot b/assets/public/font/ionicons.eot new file mode 100644 index 0000000..9f95a73 Binary files /dev/null and b/assets/public/font/ionicons.eot differ diff --git a/assets/public/font/ionicons.svg b/assets/public/font/ionicons.svg new file mode 100644 index 0000000..2a47a0f --- /dev/null +++ b/assets/public/font/ionicons.svg @@ -0,0 +1,2230 @@ + + + + + +Created by FontForge 20120731 at Wed Jan 14 22:40:14 2015 + By Adam Bradley +Created by Adam Bradley with FontForge 2.0 (http://fontforge.sf.net) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/public/font/ionicons.ttf b/assets/public/font/ionicons.ttf new file mode 100644 index 0000000..590a6c1 Binary files /dev/null and b/assets/public/font/ionicons.ttf differ diff --git a/assets/public/font/ionicons.woff b/assets/public/font/ionicons.woff new file mode 100644 index 0000000..5bb6aec Binary files /dev/null and b/assets/public/font/ionicons.woff differ diff --git a/assets/public/ico/favicon.ico b/assets/public/ico/favicon.ico new file mode 100644 index 0000000..299caa3 Binary files /dev/null and b/assets/public/ico/favicon.ico differ diff --git a/assets/public/img/about1.jpg b/assets/public/img/about1.jpg new file mode 100644 index 0000000..c9e217e Binary files /dev/null and b/assets/public/img/about1.jpg differ diff --git a/assets/public/img/about2.jpg b/assets/public/img/about2.jpg new file mode 100644 index 0000000..3cd1852 Binary files /dev/null and b/assets/public/img/about2.jpg differ diff --git a/assets/public/img/about3.jpg b/assets/public/img/about3.jpg new file mode 100644 index 0000000..332fbad Binary files /dev/null and b/assets/public/img/about3.jpg differ diff --git a/assets/public/img/about4.jpg b/assets/public/img/about4.jpg new file mode 100644 index 0000000..567e6e2 Binary files /dev/null and b/assets/public/img/about4.jpg differ diff --git a/assets/public/img/anthias.jpg b/assets/public/img/anthias.jpg new file mode 100644 index 0000000..7fa1223 Binary files /dev/null and b/assets/public/img/anthias.jpg differ diff --git a/assets/public/img/bass.jpg b/assets/public/img/bass.jpg new file mode 100644 index 0000000..b429da2 Binary files /dev/null and b/assets/public/img/bass.jpg differ diff --git a/assets/public/img/boot-process.jpg b/assets/public/img/boot-process.jpg new file mode 100644 index 0000000..b20ce18 Binary files /dev/null and b/assets/public/img/boot-process.jpg differ diff --git a/assets/public/img/community.jpg b/assets/public/img/community.jpg new file mode 100644 index 0000000..0abdcb7 Binary files /dev/null and b/assets/public/img/community.jpg differ diff --git a/assets/public/img/dory.jpg b/assets/public/img/dory.jpg new file mode 100644 index 0000000..a4a6931 Binary files /dev/null and b/assets/public/img/dory.jpg differ diff --git a/assets/public/img/graphic-stack.jpg b/assets/public/img/graphic-stack.jpg new file mode 100644 index 0000000..008c04c Binary files /dev/null and b/assets/public/img/graphic-stack.jpg differ diff --git a/assets/public/img/install-1.jpg b/assets/public/img/install-1.jpg new file mode 100644 index 0000000..a4b3657 Binary files /dev/null and b/assets/public/img/install-1.jpg differ diff --git a/assets/public/img/install-2.jpg b/assets/public/img/install-2.jpg new file mode 100644 index 0000000..ef67061 Binary files /dev/null and b/assets/public/img/install-2.jpg differ diff --git a/assets/public/img/iwantyou.jpg b/assets/public/img/iwantyou.jpg new file mode 100644 index 0000000..7714646 Binary files /dev/null and b/assets/public/img/iwantyou.jpg differ diff --git a/assets/public/img/lenok.jpg b/assets/public/img/lenok.jpg new file mode 100644 index 0000000..85ec71a Binary files /dev/null and b/assets/public/img/lenok.jpg differ diff --git a/assets/public/img/logo.png b/assets/public/img/logo.png new file mode 100644 index 0000000..4261ed7 Binary files /dev/null and b/assets/public/img/logo.png differ diff --git a/assets/public/img/openembedded.png b/assets/public/img/openembedded.png new file mode 100644 index 0000000..82b7a55 Binary files /dev/null and b/assets/public/img/openembedded.png differ diff --git a/assets/public/img/sparrow.jpg b/assets/public/img/sparrow.jpg new file mode 100644 index 0000000..66c6697 Binary files /dev/null and b/assets/public/img/sparrow.jpg differ diff --git a/assets/public/img/sprat.jpg b/assets/public/img/sprat.jpg new file mode 100644 index 0000000..9108e14 Binary files /dev/null and b/assets/public/img/sprat.jpg differ diff --git a/assets/public/img/swift.jpg b/assets/public/img/swift.jpg new file mode 100644 index 0000000..4139590 Binary files /dev/null and b/assets/public/img/swift.jpg differ diff --git a/assets/public/img/tetra.jpg b/assets/public/img/tetra.jpg new file mode 100644 index 0000000..3c38cce Binary files /dev/null and b/assets/public/img/tetra.jpg differ diff --git a/assets/public/img/watch.png b/assets/public/img/watch.png new file mode 100644 index 0000000..7c400f0 Binary files /dev/null and b/assets/public/img/watch.png differ diff --git a/assets/public/js/application.js b/assets/public/js/application.js new file mode 100644 index 0000000..1f6a067 --- /dev/null +++ b/assets/public/js/application.js @@ -0,0 +1,103 @@ +/*! + * Adapted from Bootstrap docs JavaScript + */ + + +!function ($) { + + $(function () { + + // IE10 viewport hack for Surface/desktop Windows 8 bug + // + // See Getting Started docs for more information + if (navigator.userAgent.match(/IEMobile\/10\.0/)) { + var msViewportStyle = document.createElement('style') + msViewportStyle.appendChild( + document.createTextNode( + '@-ms-viewport{width:auto!important}' + ) + ) + document.querySelector('head').appendChild(msViewportStyle) + } + + var $window = $(window) + var $body = $(document.body) + + $body.scrollspy({ + target: '.sidebar', + offset: 20 // required to select the right thing. if this is smaller then you are at the top of one section + // but the next section is highlighted + }); + + $window.on('load', function () { + $body.scrollspy('refresh') + }); + + $('.docs-container [href=#]').click(function (e) { + e.preventDefault() + }); + + + $('.source-link').each(function () { + var id = $(this).data('content'); + var content = $('').append($('#' + id)).html(); + $(this).attr('data-content', content); + + // Keep popovers open when hovered + $(this).popover({ + trigger: 'manual', + container: 'body', + placement: 'left', + template: '

', + html: true, + delay: {show: 50, hide: 750} + }).on('mouseenter', function () { + var self = this; + $(this).popover('show'); + $(this).addClass('active'); + $(this).addClass('popover-source'); + + $('.popover').on('mouseleave', function () { + $(self).popover('hide'); + $(self).removeClass('active'); + }); + + }).on('mouseleave', function () { + var self = this; + setTimeout(function () { + if (!$('.popover:hover').length) { + $(self).popover('hide'); + $(self).removeClass('active'); + } + }, 100); + }); + }); + + + // back to top + setTimeout(function () { + var $sideBar = $('.sidebar') + + $sideBar.affix({ + offset: { + top: function () { + var offsetTop = $sideBar.offset().top + var sideBarMargin = parseInt($sideBar.children(0).css('margin-top'), 10) + var navOuterHeight = $('.docs-nav').height() + + return (this.top = offsetTop - navOuterHeight - sideBarMargin) + }, + bottom: function () { + return (this.bottom = $('.footer').outerHeight(true)) + } + } + }) + }, 100); + + setTimeout(function () { + $('.top').affix() + }, 100); + + }) + +}(jQuery) diff --git a/assets/public/js/bootstrap.min.js b/assets/public/js/bootstrap.min.js new file mode 100644 index 0000000..cf1170f --- /dev/null +++ b/assets/public/js/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.isLoading=!1};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",f.resetText||d.data("resetText",d[e]()),d[e](f[b]||this.options[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},b.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});return this.$element.trigger(j),j.isDefaultPrevented()?void 0:(this.sliding=!0,f&&this.pause(),this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid.bs.carousel",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid.bs.carousel")},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid.bs.carousel")),f&&this.cycle(),this)};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("collapse in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);!e&&f.toggle&&"show"==c&&(c=!c),e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(b){a(d).remove(),a(e).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(''}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(a(c).is("body")?window:c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);{var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})}},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(b.RESET).addClass("affix");var a=this.$window.scrollTop(),c=this.$element.offset();return this.pinnedOffset=c.top-a},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"top"==this.affixed&&(e.top+=d),"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(b.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:c-h-this.$element.height()}))}}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery); \ No newline at end of file diff --git a/assets/root/.gitignore b/assets/root/.gitignore new file mode 100644 index 0000000..abc5cb7 --- /dev/null +++ b/assets/root/.gitignore @@ -0,0 +1,8 @@ +node_modules +npm-debug.log + +tmp +temp +TODO.md + +*.sublime-* diff --git a/assets/root/LICENSE-CC b/assets/root/LICENSE-CC new file mode 100644 index 0000000..1d658d6 --- /dev/null +++ b/assets/root/LICENSE-CC @@ -0,0 +1,319 @@ +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at http://creativecommons.org/. diff --git a/assets/root/LICENSE-MIT b/assets/root/LICENSE-MIT new file mode 100644 index 0000000..da10a8f --- /dev/null +++ b/assets/root/LICENSE-MIT @@ -0,0 +1,23 @@ +Copyright (c) 2017 Florent Revest +Copyright (c) 2013 Alexis Sellier, Less.js, contributors. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/assets/root/_CNAME b/assets/root/_CNAME new file mode 100644 index 0000000..a775604 --- /dev/null +++ b/assets/root/_CNAME @@ -0,0 +1 @@ +asteroidos.org diff --git a/package.json b/package.json new file mode 100644 index 0000000..2c30e40 --- /dev/null +++ b/package.json @@ -0,0 +1,64 @@ +{ + "name": "asteroidos.org", + "description": "Official website for AsteroidOS", + "version": "1.0.0", + "homepage": "https://github.com/AsteroidOS/asteroidos.org", + "author": "The AsteroidOS project", + "repository": { + "type": "git", + "url": "https://github.com/AsteroidOS/asteroidos.org.git" + }, + "bugs": { + "url": "https://github.com/AsteroidOS/asteroidos.org/issues" + }, + "license": "(MIT OR CC-BY-3.0)", + "main": "Gruntfile.js", + "devDependencies": { + "assemble": "^0.4.42", + "assemble-contrib-permalinks": "^0.3.6", + "assemble-less": "^0.7.0", + "chalk": "^0.5.1", + "cheerio": "^0.17.0", + "cwd": "^0.3.7", + "fs-utils": "^0.4.3", + "git-branch": "^0.1.2", + "git-repo-name": "^0.2.0", + "git-username": "^0.2.0", + "github": "^0.2.2", + "github-repo-url": "^0.2.1", + "gray-matter": "^0.5.0", + "grunt": "^0.4.5", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-connect": "^0.8.0", + "grunt-contrib-copy": "^0.5.0", + "grunt-contrib-jshint": "^1.0.0", + "grunt-contrib-watch": "^0.6.1", + "grunt-http-download": "^0.1.0", + "grunt-prettify": "^0.3.5", + "grunt-repos": "^0.1.2", + "grunt-sync-pkg": "^0.1.2", + "handlebars": "^2.0.0", + "handlebars-helper-datetime": "^0.1.0", + "handlebars-helper-feed": "^0.1.1", + "handlebars-helper-slugify": "^0.2.0", + "highlight.js": "^9.11.0", + "lodash": "^2.4.1", + "marked": "^0.3.2", + "marked-extras": "^0.2.4", + "relative": "^0.1.6", + "remote-origin-url": "^0.2.1", + "request": "^2.42.0", + "strip-indent": "^1.0.0", + "template": "^0.2.1", + "verbalize": "^0.1.2" + }, + "keywords": [ + "handlebars-helper-datetime", + "handlebars-helper-feed", + "handlebars-helper-slugify", + "less css", + "less", + "less.js", + "lesscss" + ] +} diff --git a/pages/about.hbs b/pages/about.hbs new file mode 100644 index 0000000..b9cd680 --- /dev/null +++ b/pages/about.hbs @@ -0,0 +1,40 @@ +--- +title: About +slug: about +--- + +
+ +
+ +
+
+

Freedom & Privacy

+

We believe that when it comes to wearable devices, users should have full control over their machines and data. AsteroidOS has been created from the ground-up with modularity and freedom in mind. For this reason, it is a free and open-source project.

+
+
+
+ +
+
+
+

Ready for your wrist

+

AsteroidOS unleashes the potential of your watch with up to 48 hours of autonomy and a set of apps including everything you need on a smartwatch: an agenda, an alarm clock, a calculator, a music controller, settings, a stopwatch, a timer and a weather forecast app.

+
+
+ +
+
+

Proven building blocks

+

AsteroidOS is built upon a rock-solid base system. Qt 5.9 and QML are used for fast and easy app development. OpenEmbedded provides a full GNU/Linux distribution and libhybris allows easy porting to most Android and Android Wear watches.

+
+
+
+ +
+
+
+

Community-friendly

+

Since its creation in 2015, AsteroidOS has been led by Florent Revest, but is open towards external contribution and collaboration. The project is still in active development and if you want to help, make sure to check the Get Involved page.

+
+
diff --git a/pages/community.hbs b/pages/community.hbs new file mode 100644 index 0000000..92135d6 --- /dev/null +++ b/pages/community.hbs @@ -0,0 +1,46 @@ +--- +title: Get Involved +slug: community +--- + + + +

AsteroidOS is driven by a vibrant community. If you are interested in making wearable devices more open, here are a couple of ways to join us:

+ +
+ Developing:

+ Developers can use QtQuick and qml-asteroid to create apps, components or watchfaces. C and C++ can also be used for middlewares maintenance. +
+
+ Porting:

+ Those who are comfortable with Linux systems can port AsteroidOS to new smartwatches and help maintain the OpenEmbedded layers. +
+
+ Designing:

+ Designers can join the UI & UX taskforce to brainstorm on the future of AsteroidOS, conduct usability reports and create mockups or wireframes for developers. +
+
+ Translating:

+ Internationalization requires contributions from many different persons. Everyone can create, review or maintain AsteroidOS translations on Weblate. +
+
+ Testing:

+ AsteroidOS is still in development and nightly builds are known to contain bugs. Testers can report and fix bugs or give new ideas on the bug tracker. +
+
+ Donating:

+ Donations are exclusively used to buy unsupported smartwatches or cover basic costs such as the server. +
+ + + +
+ +
+
+ Others:

+ Enthusiasts can join the community on IRC, Twitter and GitHub or even at various events such as Meetups, QtCon, FOSDEM, workshops and others... +
+
+ +
diff --git a/pages/contact.hbs b/pages/contact.hbs new file mode 100644 index 0000000..3779762 --- /dev/null +++ b/pages/contact.hbs @@ -0,0 +1,17 @@ +--- +title: Contact +slug: contact +--- + +

Community

+General discussions around AsteroidOS happen on the #asteroid IRC channel on Freenode. Logs are available here. If you don't have an IRC client, use the webchat below: + + +

Media & Press

+If you are a journalist looking for more content or details about AsteroidOS, email: media@asteroidos.org + +

Partners

+If you are an OEM or ODM interested in professional services around AsteroidOS, email: partners@asteroidos.org + +

Others

+For other reasons, email: contact@asteroidos.org diff --git a/pages/index.hbs b/pages/index.hbs new file mode 100644 index 0000000..e491321 --- /dev/null +++ b/pages/index.hbs @@ -0,0 +1,15 @@ +--- +title: Hack your wrist +slug: index +lead: "AsteroidOS is an open-source operating system for smartwatches." +layout: content +--- +
+
+
+

{{ title }}

+

{{ lead }}

+ Learn more + Get AsteroidOS +
+
diff --git a/pages/install.hbs b/pages/install.hbs new file mode 100644 index 0000000..9c6aa98 --- /dev/null +++ b/pages/install.hbs @@ -0,0 +1,56 @@ +--- +title: Install +slug: install +--- + +

AsteroidOS can be installed as an alternative operating system on various smartwatches. Instructions for each model can be found thereafter:

+ +
+
+ Asus Zenwatch 1 (anthias) +
+
+
+ LG G Watch Urbane (bass) +
+
+
+ LG G Watch (dory) +
+
+
+ LG G Watch R (lenok) +
+
+
+ Asus Zenwatch 2 (sparrow & wren) +
+
+
+ Samsung Gear Live (sprat) +
+
+
+ Asus Zenwatch 3 (swift) +
+
+
+ Sony Smartwatch 3 (tetra) +
+ + + +
    +
  1. Will I be able to go back to the previous operating system after installing AsteroidOS on my watch?
  2. + When installing AsteroidOS, you can choose between replacing your previous OS or keeping a "dual-boot". If you decide to replace your previous OS, it is advised to make a backup of your userdata and boot partitions before flashing AsteroidOS, you will then be able to re-flash the previous OS later. +
  3. Where can I find a phone synchronization app?
  4. + A synchronization client for Android phones named "AsteroidOSSync" is already available to download on F-Droid. +
  5. What features will and won't be working on my watch with AsteroidOS?
  6. + Take a look at the table in the Porting Status page of the documentation for detailed information on your current model's support. +
  7. My watch is not listed on this page, what can I do?
  8. + You should refer to the Porting Status page of the documentation and check if a port of AsteroidOS to your watch is possible or in progress. If you are interested in porting AsteroidOS yourself to a new watch, please take a look at the Porting Guide page and get in touch with us via IRC. +
  9. I do not want to flash a prebuilt image on my watch, can I compile AsteroidOS myself?
  10. + Take a look at the Building AsteroidOS page of the documentation for detailed instructions on how to compile AsteroidOS yourself. +
diff --git a/pages/install/anthias.hbs b/pages/install/anthias.hbs new file mode 100644 index 0000000..9d78792 --- /dev/null +++ b/pages/install/anthias.hbs @@ -0,0 +1,5 @@ +--- +title: Asus Zenwatch 1 +deviceName: anthias +layout: aw-install +--- diff --git a/pages/install/bass.hbs b/pages/install/bass.hbs new file mode 100644 index 0000000..2197414 --- /dev/null +++ b/pages/install/bass.hbs @@ -0,0 +1,6 @@ +--- +title: LG G Watch Urbane +deviceName: bass +section: install +layout: aw-install +--- diff --git a/pages/install/dory.hbs b/pages/install/dory.hbs new file mode 100644 index 0000000..47312b4 --- /dev/null +++ b/pages/install/dory.hbs @@ -0,0 +1,5 @@ +--- +title: LG G Watch +deviceName: dory +layout: aw-install +--- diff --git a/pages/install/lenok.hbs b/pages/install/lenok.hbs new file mode 100644 index 0000000..258585e --- /dev/null +++ b/pages/install/lenok.hbs @@ -0,0 +1,5 @@ +--- +title: LG G Watch R +deviceName: lenok +layout: aw-install +--- diff --git a/pages/install/sparrow.hbs b/pages/install/sparrow.hbs new file mode 100644 index 0000000..af0ec20 --- /dev/null +++ b/pages/install/sparrow.hbs @@ -0,0 +1,5 @@ +--- +title: Asus Zenwatch 2 +deviceName: sparrow +layout: aw-install +--- diff --git a/pages/install/sprat.hbs b/pages/install/sprat.hbs new file mode 100644 index 0000000..1e74595 --- /dev/null +++ b/pages/install/sprat.hbs @@ -0,0 +1,5 @@ +--- +title: Samsung Gear Live +deviceName: sprat +layout: aw-install +--- diff --git a/pages/install/swift.hbs b/pages/install/swift.hbs new file mode 100644 index 0000000..a622423 --- /dev/null +++ b/pages/install/swift.hbs @@ -0,0 +1,5 @@ +--- +title: Asus Zenwatch 3 +deviceName: swift +layout: aw-install +--- diff --git a/pages/install/tetra.hbs b/pages/install/tetra.hbs new file mode 100644 index 0000000..4b7ec57 --- /dev/null +++ b/pages/install/tetra.hbs @@ -0,0 +1,5 @@ +--- +title: Sony Smartwatch 3 +deviceName: tetra +layout: aw-install +--- diff --git a/pages/wiki/bluetooth.hbs b/pages/wiki/bluetooth.hbs new file mode 100644 index 0000000..36710a6 --- /dev/null +++ b/pages/wiki/bluetooth.hbs @@ -0,0 +1,111 @@ +--- +title: Bluetooth +layout: documentation +--- + +

An app named AsteroidOSSync can be downloaded on Android to synchronize data from a phone to an AsteroidOS watch. Several profiles are already coded: Notifications, Weather, Music and Battery, more could come in the future.

+ + +

On the phone, AsteroidOSSync uses the SweetBlue library to access the Bluetooth Low Energy capabilities of Bluedroid as a central device. It scans for watches and implements the client part of the aforementioned profiles.

+

On the watch, data are received by a BCM20715 BT chip from Broadcom, this chip needs a proprietary firmware which is uploaded by the patchram systemd service. Once the firmware is uploaded an hci0 interface is created and can be set up with hciconfig.

+

The Linux Kernel can then receive BLE payloads. A newer Bluetooth subsystem (4.1) has been backported to provide newer MGMT API functionalities needed by the userspace (e.g: DBus advertisement). This MGMT API is only used by the BlueZ5’s bluetoothd daemon which exposes various DBus abstraction API. Bluetoothd also had to be patched to expose more complete advertisement payloads.

+

Simple and common interactions with the bluetoothd’s DBus API like checking for the powered/connected status are implemented in org.asteroid.utils.BluetoothStatus of qml-asteroid. This class is for example used in asteroid-launcher, asteroid-music and asteroid-settings.

+

More complex interactions with bluetoothd are implemented in asteroid-btsyncd, a user-space daemon running as a standard user (ceres) and acting as a DBus multiplexer between BlueZ and the apps. On the BlueZ side it registers BLE Services, Characteristics and Advertisement payloads. On the user side, it exposes specific API for each and every usage needed. For example, it communicates with asteroid-music with to the MPRIS API, with asteroid-launcher based on the FreeDesktop’s notification API or with asteroid-weather thanks to data saved in the dconf “register”.

+ + +

In order to use BT PAN on AsteroidOS, you first need to modify the default image. Start by adding the following packages to the IMAGE_INSTALL variable of asteroid/src/meta-asteroid/classes/asteroid-image.bbclass:

+
adb shell tail -F /var/log/messages
+

You also need to modify the bluez5’s main configuration in asteroid/src/src/meta-asteroid/recipes-connectivity/bluez5/bluez5/main.conf to

+
[General]
+#ControllerMode = le
+DiscoverableTimeout = 180
+

Finally, modify build/conf/bblayers.conf to add the following line to BBLAYERS:

+
adb shell tail -F /var/log/messages
+

After above changes, you can rebuild a new asteroid rootfs and push it to the watch with the usual bitbake asteroid-image and adb push.

+

In order to watch logs and check on progress, open up first a first terminal and run:

+
adb shell tail -F /var/log/messages
+

In a new terminal, download and push the bt-pan helper script: (more info)

+
adb shell mkdir /tmp/bluetooth
+wget https://raw.githubusercontent.com/mk-fg/fgtk/master/bt-pan
+chmod +x ./bt-pan
+adb push bt-pan /tmp/bluetooth
+

Now, fix up DNS and make sure localhost is a known thing by modifying (if needed) resolv.conf and hosts

+
sh-4.3# cat /etc/resolv.conf
+nameserver 8.8.8.8
+nameserver ::1
+sh-4.3# cat /etc/hosts
+127.0.0.1 localhost
+

Make sure you can see bluetooth in connman:

+
sh-4.3# connmanctl technologies
+...
+/net/connman/technology/bluetooth
+Name = Bluetooth
+Type = bluetooth
+Powered = True
+Connected = False
+Tethering = False
+

You can now use bluetoothctl to establish a connection to your computer (more info)

+
sh-4.3# bluetoothctl
+[NEW] Controller 20:70:02:A0:1F:AC dory [default]
+[NEW] Device 3C:15:C2:C7:DA:95 my-rmbp2
+agent on
+default-agent
+discoverable on
+pairable on
+scan on
+pair 3C:15:C2:C7:DA:95
+trust 3C:15:C2:C7:DA:95
+

Launch bt-pan client which triggers bnep0 creation from connman (you will see it in /var/log/messages)

+
sh-4.3# /tmp/bluetooth/bt-pan --debug client 3C:15:C2:C7:DA:95
+DEBUG:root:Using local device (addr: 20:70:02:A0:1F:AC): /org/bluez/hci0
+DEBUG:root:Using remote device (addr: 3C:15:C2:C7:DA:95): /org/bluez/hci0/dev_3C_15_C2_C7_DA_95
+DEBUG:root:Connected to network (dev_remote: /org/bluez/hci0/dev_3C_15_C2_C7_DA_95, addr: 3C:15:C2:C7:DA:95) uuid 'nap' with iface: bnep0
+DEBUG:root:Finished
+

At this point your default route should still be rndis0 (USB OTG) instead of bnep0:

+
sh-4.3# ip route
+default via 192.168.2.1 dev rndis0
+192.168.2.0/24 dev rndis0 proto kernel scope link src 192.168.2.15
+

If the ip/bcast/netmask fields are missing on bnep0:

+
sh-4.3# ifconfig bnep0
+bnep0 Link encap:Ethernet HWaddr 20:70:02:A0:1F:AC
+inet6 addr: fe80::2270:2ff:fea0:1fac%1202001524/64 Scope:Link
+UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
+RX packets:39 errors:0 dropped:0 overruns:0 frame:0
+TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
+collisions:0 txqueuelen:1000
+RX bytes:10504 (10.2 KiB) TX bytes:148 (148.0 B)
+

Fix it with ifconfig and verify it worked:

+
sh-4.3# ifconfig bnep0 192.168.2.2 netmask 255.255.255.0 broadcast 192.168.2.255
+sh-4.3# ifconfig bnep0
+bnep0 Link encap:Ethernet HWaddr 20:70:02:A0:1F:AC
+inet addr:192.168.2.2 Bcast:192.168.2.255 Mask:255.255.255.0
+inet6 addr: fe80::2270:2ff:fea0:1fac%1201331708/64 Scope:Link
+UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
+RX packets:134 errors:0 dropped:0 overruns:0 frame:0
+TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
+collisions:0 txqueuelen:1000
+RX bytes:40369 (39.4 KiB) TX bytes:252 (252.0 B)
+

Now that both routes are available, data are still going over rndis0 instead of bnep0:

+
sh-4.3# ip route
+default via 192.168.2.1 dev rndis0
+192.168.2.0/24 dev rndis0 proto kernel scope link src 192.168.2.15
+192.168.2.0/24 dev bnep0 proto kernel scope link src 192.168.2.2
+

Delete default route and aad a new default one over bnep0

+
sh-4.3# ip route delete default
+sh-4.3# ip route change default via 192.168.2.1 dev bnep0
+

Verify default is now over bnep0:

+
sh-4.3# ip route
+default via 192.168.2.1 dev bnep0
+192.168.2.0/24 dev rndis0 proto kernel scope link src 192.168.2.15
+192.168.2.0/24 dev bnep0 proto kernel scope link src 192.168.2.2
+

You can now test your connection via ping and nslookup

+
sh-4.3# ping -c 1 8.8.8.8
+PING 8.8.8.8 (8.8.8.8): 56 data bytes
+64 bytes from 8.8.8.8: seq=0 ttl=42 time=80.094 ms
+sh-4.3# nslookup www.google.com
+Server: 8.8.8.8
+Address 1: 8.8.8.8 google-public-dns-a.google.com
diff --git a/pages/wiki/boot-process.hbs b/pages/wiki/boot-process.hbs new file mode 100644 index 0000000..3b8e709 --- /dev/null +++ b/pages/wiki/boot-process.hbs @@ -0,0 +1,45 @@ +--- +title: Boot Process +layout: documentation +--- + +

This page describes the basis of the AsteroidOS’ boot process. It’s focused on the LG G Watch but it should be similar on most other Android watches.

+ + +

The first component loaded by the LG G Watch is the bootloader, this component is proprietary and can’t be modified, by default it is locked and only allows to boot Android, but we can access it by swiping the screen from top left to bottom right when booting up or with the “adb reboot bootloader” from a PC connected to a running Android or AsteroidOS instance.

+

This bootloader supports the “fastboot” protocol which is also the name of the command used on the computer to communicate with the bootloader. Fastboot allows to unlock the bootloader and then to flash partitions remotely and boot selected kernels. The bootloader can load three kernels, the one flashed on the BOOT partition, the one flashed on the RECOVERY partition and one sent via usb with the “fastboot boot boot.img” command. Kernels are stored in the boot.img format which is a concatenation of a kernel (sometimes with device tree) and an initramdisk. The boot.img format can be packed or unpacked with the mkbootimg and unmkbootimg tools. The AsteroidOS’s kernel is a slightly modified Android Kernel with, for example, a backported Bluetooth subsystem. The AsteroidOS’s ramdisk mostly load the init program of the rootfs which is systemd by default.

+

Systemd loads many components like

+ + + + +

The default initramfs has a section to enable adbd on the watch before booting into the rootfs. You can enable it by appending enable_adb to the boot kernel’s parameters, and when you boot the watch, you will be able to access adb shell.

+

For example, the bass watch initscript and kernel configuration line.

+

Troubleshooting systemd

+

If you see the AsteroidOS logo (even for a split second), the watch is able to boot into the rootfs and launch systemd.

+

Logs are normally stored in a tmpfs filesystem which is lost whenever the watch is rebooted. To disable the tmpfs mount, first mount the sdcard card containing the rootfs, and then the rootfs:

+
# . /machine.conf
+# mkdir /sdcard /rfs
+# mount /dev/$sdcard_partition /sdcard
+# mount -o loop /sdcard/media/0/linux/rootfs.ext2 /rfs
+
+

You can then disable the /var/volatile tmpfs mount and enable systemd journal logging (/var/log is a symlink to /var/volatile/log):

+
# sed -i '/volatile/d' /rfs/etc/fstab
+# mkdir /rfs/var/log/journal
+
+

Once you reboot into the rootfs partition (it’ll fail again), you can hop back into the adb shell and read the journal:

+
# chroot /rfs /bin/journalctl
+
diff --git a/pages/wiki/building-asteroidos.hbs b/pages/wiki/building-asteroidos.hbs new file mode 100644 index 0000000..ade95a0 --- /dev/null +++ b/pages/wiki/building-asteroidos.hbs @@ -0,0 +1,36 @@ +--- +title: Building AsteroidOS +layout: documentation +--- + +

If you decide to compile AsteroidOS from source be aware that it’s a simple process but the first build might take you a lot of time. Report any problem to the issues tracker:

+ + + + +

Start by cloning the main repository using the following command:

+
git clone https://github.com/AsteroidOS/asteroid.git
+cd asteroid/
+
+

This repository only contains a shell script that populates src/ with OpenEmbedded and the appropriate layers. Then, it setups the environment for a bitbake build. This command will setup a build for dory, the LG G Watch, but you can also build an image for bass, the LG G Watch Urbane, sparrow, the Asus Zenwatch 2 and tetra the Sony Smartwatch 3.

+
. ./prepare-build.sh dory    # Be careful that this script must be sourced and not only ran.
+
+

Now that the environment is correctly setup, you should be in the build directory. You can now ‘bake’ your asteroid system. Make sure you have the following build dependencies:

+
git build-essential diffstat gawk chrpath texinfo
+
+ + +

And then you can run:

+
bitbake asteroid-image
+
+ + +

After a while, the generated image should be available in build/tmp-glibc/deploy/images/dory/.

Install AsteroidOS using your usual device's instructions. diff --git a/pages/wiki/code-of-conduct.hbs b/pages/wiki/code-of-conduct.hbs new file mode 100644 index 0000000..13e5c11 --- /dev/null +++ b/pages/wiki/code-of-conduct.hbs @@ -0,0 +1,67 @@ +--- +title: Code of Conduct +layout: documentation +--- + +

We believe that our mission is best served in an environment that is friendly, safe, and accepting; free from intimidation or harassment.

+

Towards this end, certain behaviors and practices will not be tolerated.

+ + + + + +

We expect all members of the AsteroidOS community to abide by this Code of Conduct at all times in all AsteroidOS community venues, online and in person, and in one-on-one communications pertaining to AsteroidOS affairs.

+

This policy covers the usage of AsteroidOS public infrastructure, including the AsteroidOS IRC channel, as well as other AsteroidOS websites, AsteroidOS related events, and any other services offered by or on behalf of the AsteroidOS community. It also applies to behavior in the context of the AsteroidOS project communities, including but not limited to public GitHub repositories, communication channels, social media, mailing lists, and public events.

+

This Code of Conduct is in addition to, and does not in any way nullify or invalidate, any other terms or conditions related to use of AsteroidOS services.

+

The definitions of various subjective terms such as “discriminatory”, “hateful”, or “confusing” will be decided at the sole discretion of the AsteroidOS abuse team.

+ + +

We are committed to providing a friendly, safe and welcoming environment for all, regardless of gender identity, sexual orientation, disability, ethnicity, religion, age, physical appearance, body size, race, or similar personal characteristics.

+

We ask that you please respect that people have differences of opinion regarding technical choices, and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a single right answer. A difference of technology preferences is not a license to be rude.

+

Any spamming, trolling, flaming, baiting, or other attention-stealing behavior is not welcome, and will not be tolerated.

+

Harassing other users is never tolerated, whether via public or private media.

+

Avoid using offensive or harassing nicknames, or other identifiers that might detract from a friendly, safe, and welcoming environment for all.

+

Harassment includes, but is not limited to: harmful or prejudicial verbal or written comments related to gender identity, sexual orientation, disability, ethnicity, religion, age, physical appearance, body size, race, or similar personal characteristics; inappropriate use of nudity, sexual images, and/or sexually explicit language in public spaces; threats of physical or non- physical harm; deliberate intimidation, stalking or following; harassing photography or recording; sustained disruption of talks or other events; inappropriate physical contact; and unwelcome sexual attention.

+ +

If you believe someone is harassing you or has otherwise violated this Code of Conduct, please contact kido on irc.freenode.net to sen an abuse report. If this is the initial report of a problem, please include as much detail as possible. It is easiest for us to address issues when we have more context.

+ +

All content published to public AsteroidOS infrastructure is hosted at the sole discretion of AsteroidOS team.

+

Unacceptable behavior from any community member will not be tolerated.

+

Anyone asked to stop unacceptable behavior is expected to comply immediately.

+

If a community member engages in unacceptable behavior, the AsteroidOS team may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning.

+ +

If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify the AsteroidOS abuse team. We will do our best to ensure that your grievance is handled appropriately.

+

In general, we will choose the course of action that we judge as being most in the interest of fostering a safe and friendly community.

+

On IRC, let one of the ops know if you think that someone has transgressed against the Code of Conduct.

+ +

Please contact kido on irc.freenode.net if you need to report a problem or address a grievance related to an abuse report.

+

You are also encouraged to contact us if you are curious about something that might be “on the line” between appropriate and inappropriate content. We are happy to provide guidance to help you be a successful part of this community.

+ +

This is a living document and may be updated from time to time.

+ +

This Code of Conduct is based on the IPFS Code of Conduct.

+

This document may be reused under a Creative Commons Attribution-ShareAlike License.

diff --git a/pages/wiki/creating-an-asteroid-app.hbs b/pages/wiki/creating-an-asteroid-app.hbs new file mode 100644 index 0000000..04d9691 --- /dev/null +++ b/pages/wiki/creating-an-asteroid-app.hbs @@ -0,0 +1,65 @@ +--- +title: Creating an Asteroid app +layout: documentation +--- + +

The app creation process of AsteroidOS needs a Software Development Kit generated by OpenEmbedded. You can either grab a prebuilt SDK here (this is a self-contained script) and install it on your system or you can build it yourself as follow.

+ +

If you’ve already got an OpenEmbedded build directory via the ‘Building AsteroidOS’ page, cd to that directory. Else, create one with:

+
git clone https://github.com/AsteroidOS/asteroid
+cd asteroid/
+
+

Then, build the cross compilation toolchain with:

+
. ./prepare-build.sh dory
+bitbake meta-toolchain-qt5
+
+ +

If you downloaded a prebuilt SDK, run the downloaded script. If you followed the previous steps, this will have generated the same installation script in tmp-glibc/deploy/sdk/, you can run it as follow:

+
./tmp-glibc/deploy/sdk/oecore-x86_64-armv7ve-neon-toolchain-nodistro.0.sh
+
+

This script will install the cross compiler and ARM libraries in /usr/local/oecore-x86_64 by default, along with a script that needs to be sourced before every build. If you want to build a simple project via the terminal, this can be done like that:

+
source /usr/local/oecore-x86_64/environment-setup-armv7ve-neon-oe-linux-gnueabi
+qmake
+make
+
+ +

Before running QtCreator you must run the previously mentioned script:

+
source /usr/local/oecore-x86_64/environment-setup-armv7ve-neon-oe-linux-gnueabi
+qtcreator
+
+

This can be done automatically by prepending “source /usr/local/oecore-x86_64/environment-setup-armv7ve-neon-oe-linux-gnueabi” before #!/bin/sh in /usr/bin/qtcreator.sh

+

Now that you are in QtCreator go to ‘Tools->Options->Build & Run‘ and

+ +

TODO: try to setup ‘Tools->Options->Devices‘ for automatic app installation over SSH.

+ +

Asteroid-Stopwatch can act as a cool QML demo app available to make the first step into AsteroidOS development easier. You can clone it, build it, install it and then modify it to follow your needs:

+
git clone https://github.com/AsteroidOS/asteroid-stopwatch
+cd asteroid-stopwatch/
+source /usr/local/oecore-x86_64/environment-setup-armv7ve-neon-oe-linux-gnueabi
+qmake
+make
+adb push asteroid-stopwatch /usr/bin/
+adb push asteroid-stopwatch.desktop /usr/share/applications/
+
+

If it wasn’t already installed, a new icon should have already appeared on asteroid-launcher, try to run it and you should get a QtQuick Controls Calendar component.

+

You can start by modifying occurrences of “asteroid-calendar” to your app’s name. Then you can change the *.desktop file which describes the icon on the apps launcher. Then modify main.qml to describe your UI. To get started with QML development you can read the official tutorial.

+ +

If you want to start your app from the command line, open a shell with adb shell, connect to the standard user and use invoker:

+
su ceres
+invoker --type=qtcomponents-qt5 /usr/bin/asteroid-stopwatch
+

If you want to disable screen locking for easier development you can enable the demo mode of mce with:

+
mcetool -D on
diff --git a/pages/wiki/documentation.hbs b/pages/wiki/documentation.hbs new file mode 100644 index 0000000..603e150 --- /dev/null +++ b/pages/wiki/documentation.hbs @@ -0,0 +1,36 @@ +--- +title: Documentation +slug: documentation +layout: documentation +--- + + + + + + + + +Work in progress... diff --git a/pages/wiki/emulator.hbs b/pages/wiki/emulator.hbs new file mode 100644 index 0000000..53538ef --- /dev/null +++ b/pages/wiki/emulator.hbs @@ -0,0 +1,15 @@ +--- +title: Emulator +layout: documentation +--- +
+

Support

+

The emulator support is a work-in-progress and does not provide any satisfactory experience yet. The graphic stack is known to be buggy and contributions are highly welcome.

+
+ +

OpenEmbedded can generate images for various emulators. Hence, it is very easy to compile AsteroidOS for the “qemux86” target with:

+
. ./prepare-build.sh qemux86
+bitbake asteroid-image
+
+

The preferred emulator is actually VirtualBox. You can open VBox, create a new virtual machine based on Linux 2.6 (32-bit) with 1024 MB of RAM and use the existing virtual hard disk file generated by OpenEmbedded in build/tmp-glibc/deploy/images/qemux86/asteroid-image-qemux86.vmdk

+

The usual graphic stack asteroid-launcher works on is based on the hwcomposer QPA which uses libhybris’s EGL and Android’s code. On VirtualBox, asteroid-launcher runs on the eglfs QPA which uses Mesa’s software rendering on top of the KMS interface offered by the virtualbox guest drivers.

diff --git a/pages/wiki/graphic-stack.hbs b/pages/wiki/graphic-stack.hbs new file mode 100644 index 0000000..862069e --- /dev/null +++ b/pages/wiki/graphic-stack.hbs @@ -0,0 +1,12 @@ +--- +title: Graphic Stack +layout: documentation +--- + +

The AsteroidOS’s graphic stack is pretty similar to the one present in SailfishOS or WebOS-Ports. This page is a quick summary of what’s involved in showing an app.

+

User apps, like asteroid-settings, are small software developed using QML and qml-asteroid. Behind the hood, Qt5 uses the QtWayland “QPA” module API for client windows to show up on screen. A communication is established via the “wayland-egl” protocol with the Wayland compositor. This means that user apps don’t necessarily have to be developed with Qt as long as the library supports the Wayland protocol.

+

The Wayland compositor which by default is asteroid-launcher (and could be replaced by GlacierUI for example) is based on Lipstick from the Nemomobile project which allows us to quickly design an interface with QML and qml-asteroid. Behind the hood, two different modules are used: once again QtWayland but this time the compositor API is used which allows us to handle the wayland-egl communication with the client. The QPA module used by asteroid-launcher is qt5-qpa-hwcomposer which uses the libhardware.so glibc binding provided by libhybris in /usr/lib.

+

This libhardware.so is only a front-end to the android’s libhardware.so provided in /system/lib/ and imported from an Android Wear installation. The android’s libhardware.so can not be directly used by qt5-qpa-hwcomposer because there is a libc incompatibility, android libraries are linked against bionic instead of glibc so a compatibility layer is needed: that’s the job of libhybris. Finally this bionic libhardware.so load some proprietary binary blobs which are able to communicate with the GPU and to show something on-screen.

+

Libhybris is used to re-use Android drivers from AsteroidOS, SailfishOS, NemoMobile, WebOS-Ports or Ubuntu Touch. It’s clearly a hack and not a perfect solution as it relies on some proprietary binary blobs but it’s often the only way to get reliable hardware acceleration on Android devices and it works really well. It’s worth noticing that Ubuntu Touch uses Mir instead of Wayland which is used by all the other projects, including AsteroidOS.

+ + diff --git a/pages/wiki/licenses.hbs b/pages/wiki/licenses.hbs new file mode 100644 index 0000000..4775ff7 --- /dev/null +++ b/pages/wiki/licenses.hbs @@ -0,0 +1,8 @@ +--- +title: Licenses +layout: documentation +--- + +

An AsteroidOS image is made of plenty of components and it’s hard to describe the full details of the licenses that are in used in the system. When building the system from sources with OpenEmbedded, one can find the exhaustive set of licenses in the build/tmp-glibc/deploy/licenses directory.

+

In order to give a very general overview of the licenses that are in used. All the apps are distributed under GPLv3. QML-Asteroid is distributed under LGPL-2.1. asteroid-launcher is distributed under BSD. The wallpapers are covered by the CC BY 2.0 and the logo by CC BY SA 2.0.

+

It’s also worth noticing that on most watches, a few amount of proprietary blobs and firmware need to be used for GPU acceleration and Bluetooth. They are isolated components which can be found in the /vendor/ directory and they are used via libhybris.

diff --git a/pages/wiki/openembedded.hbs b/pages/wiki/openembedded.hbs new file mode 100644 index 0000000..93f0c1e --- /dev/null +++ b/pages/wiki/openembedded.hbs @@ -0,0 +1,12 @@ +--- +title: OpenEmbedded +layout: documentation +--- + +

OpenEmbedded is the build system used by AsteroidOS, it allows to easily maintain embedded linux distributions. OE is also used by project such as WebOS-Ports, SHR or Ångström. OpenEmbedded is supported by the Yocto project from the Linux Foundation and provides a rock-solid basis for AsteroidOS.

+

OpenEmbedded uses the bitbake tool which is developed in python to generate images (like asteroid-image) from packages (like asteroid-launcher-dev) built from recipes (ex: asteroid-launcher_git.bb) provided in layers (ex: meta-asteroid).

+

Layers are git repositories containing a bunch of related recipes, example of layers include board support packages like meta-dory-hybris or meta-rockchip which describe a way to support a new machine, but also UI layers like meta-xfce or meta-gnome which describe the building process of graphic components.

+

A recipe describe how to fetch, patch, configure, compile, install, package (in .rpm, .deb or .ipk) and test a piece of software. Bitbake handles all those operations and dependencies between them and between recipes. In the end it can generate images or SDK for multiple targets.

+

Contributing to the AsteroidOS’s OE architecture mostly consists in maintaining the meta-asteroid and meta-*-hybris repositories which contain the recipes related to Asteroid and the watches BSPs.

+

In depth info can be found in the Mega-Manual.

+ diff --git a/pages/wiki/porting-guide.hbs b/pages/wiki/porting-guide.hbs new file mode 100644 index 0000000..f4afe12 --- /dev/null +++ b/pages/wiki/porting-guide.hbs @@ -0,0 +1,101 @@ +--- +title: Porting Guide +layout: documentation +--- + +

An AsteroidOS hardware adaptation layer consists of :

+ +
+ +

In order to add the support of your watch to AsteroidOS, you’ll need to write an OpenEmbedded layer. Start by making sure you are familiar with the core concepts behind OpenEmbedded by reading the two related documentation pages.

+ +

The easiest way to create an OpenEmbedded layer for hardware adaptation is to modify one that already exists. If you want to base your port on an Android 5.5.1 base, you should base your layer on meta-dory-hybris. If you want to base your port on an Android 6 base, you should base your layer on meta-swift-hybris.

+

Start by cloning the most appropriate layer into an src/meta-XXX-hybris/ directory in your AsteroidOS build tree. From now on, XXX will be a reference to your watch’s codename. Once you have that layer setup, roughly replace all references to the previous codename with XXX in the layer and add the path to your layer in your build/conf/bblayers.conf file.

+

The layer should describe a machine configuration to bitbake in conf/machine/XXX.conf. The definition of a machine allows to install hardware-specific packages in a generated rootfs and to give very general information about the hardware adaptation like the kernel or egl providers that should be used. Having a new machine also allows to modify other layers’ recipes based on the build’s target. For example a .bbappend file using the _XXX suffix appropriately can modify built files, apply patchesadd build dependencies, add runtime dependencies or change compilation flags. bbappends are very powerful but should be used scarcely to avoid conflicts with other layers.

+

An hardware adaptation layer does not only modify other recipes with bbappend, it also provides a couple of new recipes that are hardware-specific. You can usually find two very important recipes: the kernel recipe and the Android’s blobs recipe. Those recipes will need extra-care and are the topic of the two following paragraphs.

+ +

The kernel recipe describes how to fetch/patch/configure/compile/install/package the vendor kernel. All of those steps may need to be modified from your base recipe.

+

First of all, you need to find the git repository, branch and commit containing the source code of the watch you want to work on. Adapt SRC_URI and SRCREV accordingly.

+

Then, try to find your watch’s defconfig in the kernel’s arch/arm/configs/ directory. Copy this base defconfig onto meta-XXX-hybris/recipes-kernel/linux/linux-XXX/defconfig and use the check-config script of meta-asteroid with the -w flag to fix a couple of configuration values.

+

If you need to patch your kernel’s tree, add the path to the patches to SRC_URI.

+

The output of a kernel compilation is a single zImage. In order to be started by your watch’s bootloader, this image needs to be packed with an initramfs into a single boot.img file. (for more information cf. Boot Process) Three different tools can be used to pack the boot.img file: abootimg, mkboot and mkbootimg. Since some watches only work with one of those tools (without any apparent reason), you can inherit one of the provided bbclass and adapt the config accordingly.

+

Extra-Note: The Yocto project provides a handy manual on how to work with the Linux kernel with OpenEmbedded.

+ +

In order to get a full AsteroidOS environment, you will need to install the Android HALs required by the usage of libhybris in various AsteroidOS components.

+

Actually, only a very limited set of libs from Android is needed. Some of those libs (like bionic) need to be patched and must be recompiled from source. Hence, you’ll need to start by cloning a modified and stripped down Android source tree to compile the needed drivers. You can find detailed info on the build process that has been used for dory in README-system-dir. You’ll most likely need to adapt those instructions to your own need, thus you are strongly encouraged to document your steps in your own README-system-dir for reproducibility and in order to help future porters.

+

Once you’ll get your first /system/ directory, you can modify meta-XXX-hybris/recipes-android/android/android_XXX-*.bb to use your prebuilt tarball. The next steps in hardware adaptation will most likely require you to iterate various modifications to this system directory so don’t get too emotionally attached to this tarball yet.

+ +

If you boot your generated boot.img from your watch’s bootloader, fastboot should load your kernel which will load the initramfs’s init script which will eventually load you rootfs’s init system. (for more information cf. Boot Process) You can usually know if those steps have successfully been completed when the watch stays up and running and shows the AsteroidOS boot logo for a while (shown by psplash which is ran by systemd on the rootfs). In case your boot stops earlier, you have a boot problem to debug.

+

You need to proceed by elimination to find what causes your boot to fail. First of all, disable the ramfs -> rootfs switch by adding a bash infinite loop early in your ramdisk’s init script. If you notice your watch does not crash anymore, you may have an issue with your rootfs. The Troubleshooting section of the Boot Process page should help you retrieve your systemd logs and isolate the cause of your boot problem.

+

If your watch keeps on crashing, you may have a problem with your kernel. Start by making sure you tried the different boot.img packing tools. If the problem persists, you’ll want to retrieve your kernel’s message logs. This can usually be retrieved from a /proc/last_kmsg virtual file in Android Wear when enabling the CONFIG_ANDROID_RAM_CONSOLE kernel option. Analyzing the logs should also help narrowing down the issue to a faulty driver or config.

+ +

If you have your AsteroidOS system running, you will want to get a shell access to it with adb over USB. Try to run adb devices from your computer when your watch has been booted for a few seconds and check if you see your device. If you don’t, you may have a problem with your USB setup.

+

First of all, try to replicate the config of your Android Wear’s init scripts in your ramdisk’s init script. Once you’re sure the USB config is the same, you should try to run adbd from your ramdisk instead of the rootfs, if it solves the problem you may have an issue with usb_moded not starting adbd properly.

+

If the problem is the same, you may have a problem with your kernel’s config or drivers. First of all, make sure CONFIG_USB_G_ANDROID is still enabled in the generated build/tmp-glibc/work/XXX-oe-linux-gnueabi/linux-XXX/*/git/.config as it is quite common to find bitbake removing this option. If the option is still there, your kernel may need special patches.

+ +

As soon as you’ll get access to a shell on AsteroidOS, you may find yourself without asteroid-launcher running. Checking the system logs with “journalctl –no-pager” or “systemctl –no-pager” usually shows a segfault from the lipstick process. This is to be expected on your first run and there is nothing to worry about. In order to reproduce the bug, you can start lipstick manually with:

+

XDG_RUNTIME_DIR=/run/user/1000 EGL_PLATFORM=hwcomposer lipstick –platform hwcomposer

+

asteroid-launcher uses lipstick which uses the hwcomposer QPA which uses libhybris which uses the Android graphic HAL to display things on screen. You may need to adapt the Android graphic HAL to answer the needs of hybris. (usually a matter of starting the right android boot services, having the right files placed in the right directories, having the right system.prop options etc…)

+

For more information on the Graphic Stack you may want to refer to the associated documentation page. For more information on how to debug an issue, check the Troubleshooting paragraph of this page.

+ +

Once you’ll get asteroid-launcher displaying things on screen, you may have no touch feedback from the UI. If that is the case, you’ll need to modify the lipstick’s start command to use a different evdevtouch file. For example, tetra uses this bbappend to use /dev/input/event1 instead of the default event0.

+ +

Smartwatches usually don’t carry speakers but they often have microphones. AsteroidOS does not use those microphones yet but it’s usually easy to support and should be supported for the future of the project. AsteroidOS uses pulseaudio for its audio stack. pulseaudio takes benefits from the pulseaudio-droid-card module to use the Android’s Audio HAL. In order to test the microphone, you can install and run parec from the build/tmp-glibc/work/armv7ve-neon-oe-linux-gnueabi/pulseaudio/9.0-r0/packages-split/pulseaudio-misc/ package. If you lack an audio interface, make sure you loaded the audio firmware.

+

In case a problem persist, enabling extra debug information from pulseaudio can give you detailed info on the cause of the issue.

+ +

Smartwatches make extensive use of Bluetooth for connectivity. The AsteroidOS project comes with a set of Bluetooth Low Energy profiles implemented in the asteroid-btsyncd server daemon and AsteroidOSSync client. (for more information cf. Bluetooth) Bluetooth required a few extra steps to work on your port.

+

asteroid-btsyncd uses BlueZ’s DBus API to create a BLE server. Those APIs require a recent Bluetooth subsystem in your kernel. Unfortunately, Android Wear watches usually come with outdated kernels and a newer BT subsystem needs to be backported. The patch used in dory can be found here and should be adaptable to your kernel’s tree with very few conflicts.

+

Most Android Wear smartwatches carry a Broadcom BT chip that requires a proprietary firmware to be applied with a tool named brcm-patchram-plus. This tool is called from a systemd service named patchram.service, your HW adaptation layer should include a modified patchram.service file that uses the provided vendor’s firmware and tty line. Information about the config you should use can be found in the Android’s libbt-broadcom repository.

+

With a backported BT subsystem and patched BT firmware, you should already be able to get Bluetooth connectivity on your port but with very limited battery life. Broadcom’s bluetooth’s low power mode is handled by a kernel module named Bluesleep (or more recently Nitrous) that expects custom information to be written in /proc/lpm/. With BlueZ, this proc interface is never used hence the kernel driver must be adapted to receive HCI events from the BT subsystem with a patch. Finally, brcm-patchram-plus must also be compiled with a special flag defining the target device and the low power mode options to use.

+ +

In AsteroidOS, sensors can be used by developers through the QtSensors API that uses the sensorfw backend. Sensorfwd is a sensor daemon that can use libhybris to interface with the Android’s Sensors HAL.

+

In order to use sensors on Asteroid, you need to make sure libhybris recognizes your sensors by running the test_sensors command. For more information on how to debug an issue, check the Troubleshooting paragraph of this page.

+ +

In AsteroidOS, vibrations can be used by developers through the QtFeedback and ngfd APIs that usually rely on a libhybris backend which uses the Android’s vibration HAL.

+

In order to use vibration on Asteroid with the Android HAL, you need to make sure libhybris recognizes your vibrator by running the test_vibrator command. For more information on how to debug an issue, check the Troubleshooting paragraph of this page.

+

A much cleaner way to vibrate in AsteroidOS would be to use an ffmemless kernel driver and the sensorfwd’s ffmemless backend but most watches don’t come with such a kernel driver and it would need to be developed.

+ +

WLAN is not used by AsteroidOS’s user-interface yet but it should be supported for the future of the project. Some information about setting up a Wi-Fi interface can be found in the last paragraph of the SSH documentation page.

+ +

While porting AsteroidOS to your watch, you will most likely meet all kind of problems. In order to debug what’s going wrong with your setup you should install debug tools such as strace and gdb and the required debug sybols to your generated rootfs. For example, you can temporarily append the “strace gdb asteroid-launcher-dbg” packages to the asteroid-image class.

+

Once you come up with more information about your bug with strace and gdb, your first reflex should be to search the asteroid’s IRC logs for similar issues. The SailfishOS porters community is another great place to search for information, you may also want to try your chance at searching the merproject’s IRC logs.

+

If you still couldn’t find a solution to your problem in the logs, don’t hesitate to ask questions on the #asteroid IRC channel. There should be several porters able to help you.

+ +

That’s it, you can finally use AsteroidOS on your watch! Sharing your work with the rest community should be the final step to ensure your layer will be maintained through time. Start by requesting on IRC the creation of a new AsteroidOS/meta-XXX-hybris repository and send a pull request to this repository. Your work will be carefully reviewed and commented before being integrated upstream. You’ll also need to send a pull-request to the AsteroidOS/asteroid repository to integrate your machine to prepare-build.sh and join the very privileged circle of AsteroidOS porters! Make sure your work is correctly detailed on the Porting Status page and share a photo of your watch for public twitter announcement.

+
diff --git a/pages/wiki/porting-status.hbs b/pages/wiki/porting-status.hbs new file mode 100644 index 0000000..8c4ede9 --- /dev/null +++ b/pages/wiki/porting-status.hbs @@ -0,0 +1,200 @@ +--- +title: Porting Status +layout: documentation +--- + +

This page aims at gathering info about the currently supported platforms and porting efforts.

+ +

The Android Wear smartwatches are the most widespread and easy to support. The source code of their kernels is usually easily available and the drivers can be supported with libhybris. Those watches are the current priority of AsteroidOS.

+

Supported watches:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BrandModelCodenameMaintainerDisplayTouchAudioBluetoothSensorsHapticsUSBWLANNote
AsusZenWatchanthiaslocusfXXXXXXXSluggish UI
AsusZenWatch 2sparrow/wrenLrs121/dlandauXXXXX
AsusZenWatch 3swiftanYcXXXXX
LGG WatchdorykidoXXXXXXXBest support
LGG Watch RlenokatxXXXXX
LGG Watch UrbanebassTheAppleManXXXXXXX
SamsungGear Livespratkido/nobodyXXXXXX
SonySmartWatch 3tetrakidoXXXXX
HuaweiWatchsturgeonbencord0Just boots
+

Possible ports not supported yet:

+ +

Impossible ports because of lack of pinouts:

+ + +

The Samsung Gear S2, S2 Classic and S3 might be supported by AsteroidOS in the future but they will require more work than the other watches. Someone already got interested in the S2 port but gave up because he couldn’t find the kernel’s defconfig.

+ +

There are many Android (non-Wear) smartwatches available for a lower price. (e.g: the Omate *, Sony SW, Intex iRist, zWatch etc…) It might be more difficult to get access to the kernel’s or android tree of those devices but libhybris could also make running AsteroidOS on top of them possible.

+

Other low-end smartwatches using cheap Mediatek SoCs aren’t able to run a Linux kernel and can’t be supported by AsteroidOS

diff --git a/pages/wiki/ssh.hbs b/pages/wiki/ssh.hbs new file mode 100644 index 0000000..4366b04 --- /dev/null +++ b/pages/wiki/ssh.hbs @@ -0,0 +1,51 @@ +--- +title: SSH +layout: documentation +--- + +

By default, you can get a remote shell on you smartwatch with the Android Debug Bridge tool and the “adb shell” command. However this shell suffers from a many limitations and you might prefer to get a standard SSH connection. To do so you need to setup a TCP connection with your watch. The procedure is different if you want to do it over USB or Wi-Fi (if your watch supports Wi-Fi)

+ +

To use SSH over USB’s gadget mode you need to tell Connman to setup a manual IP for your watch. First of all, you need to get your usb’s UID thanks to the “get-services” tool which is available in the “connman-tests” package under /usr/lib/connman/test/. The first line of this command’s output should contain something like “gadget_UID_usb”, note this UID and replace it when needed in the commands below.

+

Create a /var/lib/connman/gadget_UID_usb/ directory and in that directory create a “settings” file containing:

+
[gadget_*UID*_usb]
+Favorite=true
+IPv4.method=manual
+IPv4.netmask_prefixlen=24
+IPv4.local_address=192.168.0.133
+IPv4.gateway=192.168.0.1
+AutoConnect=true
+Name=Wired
+IPv6.method=off
+IPv6.privacy=disabled
+
+

Now from your computer, setup your usb interface with the 192.168.0.1 IP and then you’ll be able to connect to your watch with:

+
ssh ceres@192.168.0.133
+
+

/!\ This UID and the gadget’s mac address both seem to be re-generated at every boot so this config isn’t persistent. We should try to find a solution.

+ +

Dropbear is already running on the watch so we just need an IP address configured to connect.

+

Ensure wireless drivers are enabled for the watch.

+

Build your asteroid-image with iproute2 and wpa-supplicant. In meta-{watch}-hybris/conf/machine/{watch}.conf add iproute2 and wpa-supplicant to IMAGE_INSTALL:

+
IMAGE_INSTALL += "android-tools android-system msm-fb-refresher brcm-patchram-plus iproute2 wpa-supplicant"
+
+

Once your image is installed on the watch, open up an adb shell:

+
# mkdir /etc/wpa_supplicant
+# cp /etc/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
+# systemctl enable --now wpa_supplicant@wlan0
+# wpa_cli
+> scan
+> scan_results
+> add_network
+> set_network X ssid "MYSSID"
+> set_network X psk "MYPSK"
+> enable_network X
+> select_network X
+> save_config
+# ip a show dev wlan0
+
+

The watch should automatically get an IPv6 address from your network or you can set a static IPv4. You can disconnect from adb and connect via SSH.

+

By default, there is no root or ceres password, and no firewall rules.

diff --git a/pages/wiki/translating-asteroidos.hbs b/pages/wiki/translating-asteroidos.hbs new file mode 100644 index 0000000..ee20978 --- /dev/null +++ b/pages/wiki/translating-asteroidos.hbs @@ -0,0 +1,14 @@ +--- +title: Translating AsteroidOS +layout: documentation +--- + +

AsteroidOS translations, aside from the app name, are managed through Weblate, a Free/Open Source web translation platform. To be able to use it, you will have to register an account, although you can also log in through a few popular third-party services. The rest of this page assumes you have an account.

+ +

Updating translations for an existing language is quite simple. Simply go to the AsteroidOS Weblate page, choose the project and language you want to translate and start translating. If you want to update the app name, please create a GitHub pull request or issue with the appropriate change to the .desktop file, or join #asteroid on Freenode to tell us about the desired change.

+ +

If the language you want to translate to is not supported yet, please join #asteroid on Freenode to tell us which language you’d like to see supported and discuss with us what the correct app names would be in that language and we’ll set it up for you.

diff --git a/pages/wiki/watchfaces-creation.hbs b/pages/wiki/watchfaces-creation.hbs new file mode 100644 index 0000000..1147395 --- /dev/null +++ b/pages/wiki/watchfaces-creation.hbs @@ -0,0 +1,38 @@ +--- +title: Watchfaces Creation +layout: documentation +--- + +

Watchface creation is fairly simple, requiring only QML knowledge. This guide will walk you through the steps.

+ +
+

First, clone the https://github.com/AsteroidOS/asteroid-launcher repository as it contains all watchfaces. Then, navigate to the watchfaces directory. In here, copy 000-default-digital.qml to a new file to use as a base for watchface creation.

+
+ +
+

To test your watchface locally, I personally open the qml file using qmlscene: qmlscene xxx-my-watchface.qml. Of course, other QML previewing tools should work too.

+
+
+

To be able to test properly, replace all references to wallClock.time with new Date(), place an image in the same directory named background.jpg and put the following code just below the first Item statement:

+
  Image {
+      source: "background.jpg"
+      width: 160
+      height: 160
+  }
+
+
+

The above code allows you to see what the watchface would look like on an actual device, as qmlscene by default uses a pure white background.

+
+ +
+

Make sure to replace all instances of new Date() with wallClock.time and remove the background Image statement. Then, simply push it to the watch: adb push xxx-my-watchface.qml /usr/share/asteroid-launcher/watchfaces/. You can then go to watchfaces in the AsteroidOS settings. If you also pushed an xxx-my-watchface.jpg file, this will be used as preview. Otherwise, you will have to tap a white square to activate it.

+
+
+

If you want to update the watchface, you have to push the new version to the device. Do note that AsteroidOS may cache the watchface. The easiest way to fix this is to “restart” the device by running the following command: adb shell systemctl restart user@1000.

+
diff --git a/styles/bootstrap/alerts.less b/styles/bootstrap/alerts.less new file mode 100644 index 0000000..3eab066 --- /dev/null +++ b/styles/bootstrap/alerts.less @@ -0,0 +1,67 @@ +// +// Alerts +// -------------------------------------------------- + + +// Base styles +// ------------------------- + +.alert { + padding: @alert-padding; + margin-bottom: @line-height-computed; + border: 1px solid transparent; + border-radius: @alert-border-radius; + + // Headings for larger alerts + h4 { + margin-top: 0; + // Specified for the h4 to prevent conflicts of changing @headings-color + color: inherit; + } + // Provide class for links that match alerts + .alert-link { + font-weight: @alert-link-font-weight; + } + + // Improve alignment and spacing of inner content + > p, + > ul { + margin-bottom: 0; + } + > p + p { + margin-top: 5px; + } +} + +// Dismissable alerts +// +// Expand the right padding and account for the close button's positioning. + +.alert-dismissable { + padding-right: (@alert-padding + 20); + + // Adjust close link position + .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; + } +} + +// Alternate styles +// +// Generate contextual modifier classes for colorizing the alert. + +.alert-success { + .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text); +} +.alert-info { + .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text); +} +.alert-warning { + .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text); +} +.alert-danger { + .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text); +} diff --git a/styles/bootstrap/badges.less b/styles/bootstrap/badges.less new file mode 100644 index 0000000..0b69753 --- /dev/null +++ b/styles/bootstrap/badges.less @@ -0,0 +1,51 @@ +// +// Badges +// -------------------------------------------------- + + +// Base classes +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: @font-size-small; + font-weight: @badge-font-weight; + color: @badge-color; + line-height: @badge-line-height; + vertical-align: baseline; + white-space: nowrap; + text-align: center; + background-color: @badge-bg; + border-radius: @badge-border-radius; + + // Empty badges collapse automatically (not available in IE8) + &:empty { + display: none; + } +} + +// Hover state, but only for links +a.badge { + &:hover, + &:focus { + color: @badge-link-hover-color; + text-decoration: none; + cursor: pointer; + } +} + +// Quick fix for labels/badges in buttons +.btn .badge { + position: relative; + top: -1px; +} + +// Account for counters in navs +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: @badge-active-color; + background-color: @badge-active-bg; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} diff --git a/styles/bootstrap/bootstrap.less b/styles/bootstrap/bootstrap.less new file mode 100644 index 0000000..08cd79b --- /dev/null +++ b/styles/bootstrap/bootstrap.less @@ -0,0 +1,41 @@ +// Reset +@import "normalize.less"; +@import "print.less"; + +// Core CSS +@import "scaffolding.less"; +@import "type.less"; +@import "code.less"; +@import "grid.less"; +@import "tables.less"; +@import "forms.less"; +@import "buttons.less"; + +// Components +@import "component-animations.less"; +@import "ionicons.less"; +@import "dropdowns.less"; +@import "button-groups.less"; +@import "input-groups.less"; +@import "navs.less"; +@import "navbar.less"; +@import "breadcrumbs.less"; +@import "pagination.less"; +@import "pager.less"; +@import "labels.less"; +@import "badges.less"; +@import "jumbotron.less"; +@import "thumbnails.less"; +@import "alerts.less"; +@import "progress-bars.less"; +@import "media.less"; +@import "list-group.less"; +@import "panels.less"; +@import "wells.less"; +@import "close.less"; + +// Components w/ JavaScript +@import "modals.less"; +@import "tooltip.less"; +@import "popovers.less"; +@import "carousel.less"; diff --git a/styles/bootstrap/breadcrumbs.less b/styles/bootstrap/breadcrumbs.less new file mode 100644 index 0000000..60b33ea --- /dev/null +++ b/styles/bootstrap/breadcrumbs.less @@ -0,0 +1,23 @@ +// +// Breadcrumbs +// -------------------------------------------------- + + +.breadcrumb { + padding: 8px 15px; + margin-bottom: @line-height-computed; + list-style: none; + background-color: @breadcrumb-bg; + border-radius: @border-radius-base; + > li { + display: inline-block; + + li:before { + content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space + padding: 0 5px; + color: @breadcrumb-color; + } + } + > .active { + color: @breadcrumb-active-color; + } +} diff --git a/styles/bootstrap/button-groups.less b/styles/bootstrap/button-groups.less new file mode 100644 index 0000000..43ada11 --- /dev/null +++ b/styles/bootstrap/button-groups.less @@ -0,0 +1,248 @@ +// +// Button groups +// -------------------------------------------------- + +// Button carets +// +// Match the button text color to the arrow/caret for indicating dropdown-ness. + +.caret { + .btn-default & { + border-top-color: @btn-default-color; + } + .btn-primary &, + .btn-success &, + .btn-warning &, + .btn-danger &, + .btn-info & { + border-top-color: #fff; + } +} +.dropup { + & .btn-default .caret { + border-bottom-color: @btn-default-color; + } + .btn-primary, + .btn-success, + .btn-warning, + .btn-danger, + .btn-info { + .caret { + border-bottom-color: #fff; + } + } +} + +// Make the div behave like a button +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; // match .btn alignment given font-size hack above + > .btn { + position: relative; + float: left; + // Bring the "active" button to the front + &:hover, + &:focus, + &:active, + &.active { + z-index: 2; + } + &:focus { + // Remove focus outline when dropdown JS adds it after closing the menu + outline: none; + } + } +} + +// Prevent double borders when buttons are next to each other +.btn-group { + .btn + .btn, + .btn + .btn-group, + .btn-group + .btn, + .btn-group + .btn-group { + margin-left: -1px; + } +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + .clearfix(); + + .btn-group { + float: left; + } + // Space out series of button groups + > .btn, + > .btn-group { + + .btn, + + .btn-group { + margin-left: 5px; + } + } +} + +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} + +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group > .btn:first-child { + margin-left: 0; + &:not(:last-child):not(.dropdown-toggle) { + .border-right-radius(0); + } +} +// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + .border-left-radius(0); +} + +// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group) +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child { + > .btn:last-child, + > .dropdown-toggle { + .border-right-radius(0); + } +} +.btn-group > .btn-group:last-child > .btn:first-child { + .border-left-radius(0); +} + +// On active and open, don't show outline +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + + +// Sizing +// +// Remix the default button sizing classes into new ones for easier manipulation. + +.btn-group-xs > .btn { .btn-xs(); } +.btn-group-sm > .btn { .btn-sm(); } +.btn-group-lg > .btn { .btn-lg(); } + + +// Split button dropdowns +// ---------------------- + +// Give the line between buttons some depth +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} + +// The clickable button for toggling the menu +// Remove the gradient and set the same inset shadow as the :active state +.btn-group.open .dropdown-toggle { + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); +} + + +// Reposition the caret +.btn .caret { + margin-left: 0; +} +// Carets in other button sizes +.btn-lg .caret { + border-width: @caret-width-large @caret-width-large 0; + border-bottom-width: 0; +} +// Upside down carets for .dropup +.dropup .btn-lg .caret { + border-width: 0 @caret-width-large @caret-width-large; +} + + +// Vertical button groups +// ---------------------- + +.btn-group-vertical { + > .btn, + > .btn-group { + display: block; + float: none; + width: 100%; + max-width: 100%; + } + + // Clear floats so dropdown menus can be properly placed + > .btn-group { + .clearfix(); + > .btn { + float: none; + } + } + + > .btn + .btn, + > .btn + .btn-group, + > .btn-group + .btn, + > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; + } +} + +.btn-group-vertical > .btn { + &:not(:first-child):not(:last-child) { + border-radius: 0; + } + &:first-child:not(:last-child) { + border-top-right-radius: @border-radius-base; + .border-bottom-radius(0); + } + &:last-child:not(:first-child) { + border-bottom-left-radius: @border-radius-base; + .border-top-radius(0); + } +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child { + > .btn:last-child, + > .dropdown-toggle { + .border-bottom-radius(0); + } +} +.btn-group-vertical > .btn-group:last-child > .btn:first-child { + .border-top-radius(0); +} + + + +// Justified button groups +// ---------------------- + +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; + .btn { + float: none; + display: table-cell; + width: 1%; + } +} + + +// Checkbox and radio options +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; +} diff --git a/styles/bootstrap/buttons.less b/styles/bootstrap/buttons.less new file mode 100644 index 0000000..a090960 --- /dev/null +++ b/styles/bootstrap/buttons.less @@ -0,0 +1,158 @@ +// +// Buttons +// -------------------------------------------------- + + +// Base styles +// -------------------------------------------------- + +// Core styles +.btn { + display: inline-block; + margin-bottom: 0; // For input.btn + font-weight: @btn-font-weight; + text-align: center; + vertical-align: middle; + cursor: pointer; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid transparent; + white-space: nowrap; + .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base); + .user-select(none); + + &:focus { + .tab-focus(); + } + + &:hover, + &:focus { + color: @btn-default-color; + text-decoration: none; + } + + &:active, + &.active { + outline: 0; + background-image: none; + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + cursor: not-allowed; + pointer-events: none; // Future-proof disabling of clicks + .opacity(.65); + .box-shadow(none); + } + +} + + +// Alternate buttons +// -------------------------------------------------- + +.btn-default { + .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border); +} +.btn-primary { + .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border); +} +// Warning appears as orange +.btn-warning { + .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border); +} +// Danger and error appear as red +.btn-danger { + .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border); +} +// Success appears as green +.btn-success { + .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border); +} +// Info appears as blue-green +.btn-info { + .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border); +} + + +// Link buttons +// ------------------------- + +// Make a button look and behave like a link +.btn-link { + color: @link-color; + font-weight: normal; + cursor: pointer; + border-radius: 0; + + &, + &:active, + &[disabled], + fieldset[disabled] & { + background-color: transparent; + .box-shadow(none); + } + &, + &:hover, + &:focus, + &:active { + border-color: transparent; + } + &:hover, + &:focus { + color: @link-hover-color; + text-decoration: underline; + background-color: transparent; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @btn-link-disabled-color; + text-decoration: none; + } + } +} + + +// Button Sizes +// -------------------------------------------------- + +.btn-lg { + // line-height: ensure even-numbered height of button next to large input + .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large); +} +.btn-sm, +.btn-xs { + // line-height: ensure proper height of button next to small input + .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); +} +.btn-xs { + padding: 1px 5px; +} + + +// Block button +// -------------------------------------------------- + +.btn-block { + display: block; + width: 100%; + padding-left: 0; + padding-right: 0; +} + +// Vertically space out multiple block buttons +.btn-block + .btn-block { + margin-top: 5px; +} + +// Specificity overrides +input[type="submit"], +input[type="reset"], +input[type="button"] { + &.btn-block { + width: 100%; + } +} diff --git a/styles/bootstrap/carousel.less b/styles/bootstrap/carousel.less new file mode 100644 index 0000000..59e4fad --- /dev/null +++ b/styles/bootstrap/carousel.less @@ -0,0 +1,220 @@ +// +// Carousel +// -------------------------------------------------- + + +// Wrapper for the slide container and indicators +.carousel { + position: relative; +} + +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; + + > .item { + display: none; + position: relative; + .transition(.6s ease-in-out left); + + // Account for jankitude on images + > img, + > a > img { + .img-responsive(); + line-height: 1; + } + } + + > .active, + > .next, + > .prev { display: block; } + + > .active { + left: 0; + } + + > .next, + > .prev { + position: absolute; + top: 0; + width: 100%; + } + + > .next { + left: 100%; + } + > .prev { + left: -100%; + } + > .next.left, + > .prev.right { + left: 0; + } + + > .active.left { + left: -100%; + } + > .active.right { + left: 100%; + } + +} + +// Left/right controls for nav +// --------------------------- + +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: @carousel-control-width; + .opacity(@carousel-control-opacity); + font-size: @carousel-control-font-size; + color: @carousel-control-color; + text-align: center; + text-shadow: @carousel-text-shadow; + // We can't have this transition here because webkit cancels the carousel + // animation if you trip this while in the middle of another animation. + + // Set gradients for backgrounds + &.left { + #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001)); + } + &.right { + left: auto; + right: 0; + #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5)); + } + + // Hover/focus state + &:hover, + &:focus { + color: @carousel-control-color; + text-decoration: none; + .opacity(.9); + } + + // Toggles + .icon-prev, + .icon-next, + .glyphicon-chevron-left, + .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; + } + .icon-prev, + .glyphicon-chevron-left { + left: 50%; + } + .icon-next, + .glyphicon-chevron-right { + right: 50%; + } + .icon-prev, + .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; + } + + .icon-prev { + &:before { + content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039) + } + } + .icon-next { + &:before { + content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A) + } + } +} + +// Optional indicator pips +// +// Add an unordered list with the following class and add a list item for each +// slide your carousel holds. + +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; + + li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid @carousel-indicator-border-color; + border-radius: 10px; + cursor: pointer; + } + .active { + margin: 0; + width: 12px; + height: 12px; + background-color: @carousel-indicator-active-bg; + } +} + +// Optional captions +// ----------------------------- +// Hidden by default for smaller viewports +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: @carousel-caption-color; + text-align: center; + text-shadow: @carousel-text-shadow; + & .btn { + text-shadow: none; // No shadow for button elements in carousel-caption + } +} + + +// Scale up controls for tablets and up +@media screen and (min-width: @screen-sm-min) { + + // Scale up the controls a smidge + .carousel-control { + .glyphicons-chevron-left, + .glyphicons-chevron-right, + .icon-prev, + .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + } + + // Show and left align the captions + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + + // Move up the indicators + .carousel-indicators { + bottom: 20px; + } +} diff --git a/styles/bootstrap/close.less b/styles/bootstrap/close.less new file mode 100644 index 0000000..9b4e74f --- /dev/null +++ b/styles/bootstrap/close.less @@ -0,0 +1,33 @@ +// +// Close icons +// -------------------------------------------------- + + +.close { + float: right; + font-size: (@font-size-base * 1.5); + font-weight: @close-font-weight; + line-height: 1; + color: @close-color; + text-shadow: @close-text-shadow; + .opacity(.2); + + &:hover, + &:focus { + color: @close-color; + text-decoration: none; + cursor: pointer; + .opacity(.5); + } + + // Additional properties for button version + // iOS requires the button element instead of an anchor tag. + // If you want the anchor version, it requires `href="#"`. + button& { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + } +} diff --git a/styles/bootstrap/code.less b/styles/bootstrap/code.less new file mode 100644 index 0000000..54ab46a --- /dev/null +++ b/styles/bootstrap/code.less @@ -0,0 +1,53 @@ +// +// Code (inline and blocK) +// -------------------------------------------------- + + +// Inline and block code styles +code, +kbd, +pre, +samp { + font-family: @font-family-monospace; +} + +// Inline code +code { + padding: 2px 4px; + font-size: 90%; + color: @code-color; + background-color: @code-bg; + white-space: nowrap; + border-radius: @border-radius-base; +} + +// Blocks of code +pre { + display: block; + padding: ((@line-height-computed - 1) / 2); + margin: 0 0 (@line-height-computed / 2); + font-size: (@font-size-base - 1); // 14px to 13px + line-height: @line-height-base; + word-break: break-all; + word-wrap: break-word; + color: @pre-color; + background-color: @pre-bg; + border: 1px solid @pre-border-color; + border-radius: @border-radius-base; + + // Account for some code outputs that place code tags in pre tags + code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; + } +} + +// Enable scrollable blocks of code +.pre-scrollable { + max-height: @pre-scrollable-max-height; + overflow-y: scroll; +} diff --git a/styles/bootstrap/component-animations.less b/styles/bootstrap/component-animations.less new file mode 100644 index 0000000..1efe45e --- /dev/null +++ b/styles/bootstrap/component-animations.less @@ -0,0 +1,29 @@ +// +// Component animations +// -------------------------------------------------- + +// Heads up! +// +// We don't use the `.opacity()` mixin here since it causes a bug with text +// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552. + +.fade { + opacity: 0; + .transition(opacity .15s linear); + &.in { + opacity: 1; + } +} + +.collapse { + display: none; + &.in { + display: block; + } +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + .transition(height .35s ease); +} diff --git a/styles/bootstrap/dropdowns.less b/styles/bootstrap/dropdowns.less new file mode 100644 index 0000000..e6bd187 --- /dev/null +++ b/styles/bootstrap/dropdowns.less @@ -0,0 +1,192 @@ +// +// Dropdown menus +// -------------------------------------------------- + + +// Dropdown arrow/caret +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: @caret-width-base solid @dropdown-caret-color; + border-right: @caret-width-base solid transparent; + border-left: @caret-width-base solid transparent; + // Firefox fix for https://github.com/twbs/bootstrap/issues/9538. Once fixed, + // we can just straight up remove this. + border-bottom: 0 dotted; +} + +// The dropdown wrapper (div) +.dropdown { + position: relative; +} + +// Prevent the focus on the dropdown toggle when closing dropdowns +.dropdown-toggle:focus { + outline: 0; +} + +// The dropdown menu (ul) +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: @zindex-dropdown; + display: none; // none by default, but block on "open" of the menu + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; // override default ul + list-style: none; + font-size: @font-size-base; + background-color: @dropdown-bg; + border: 1px solid @dropdown-fallback-border; // IE8 fallback + border: 1px solid @dropdown-border; + border-radius: @border-radius-base; + .box-shadow(0 6px 12px rgba(0,0,0,.175)); + background-clip: padding-box; + + // Aligns the dropdown menu to right + &.pull-right { + right: 0; + left: auto; + } + + // Dividers (basically an hr) within the dropdown + .divider { + .nav-divider(@dropdown-divider-bg); + } + + // Links within the dropdown menu + > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: @line-height-base; + color: @dropdown-link-color; + white-space: nowrap; // prevent links from randomly breaking onto new lines + } +} + +// Hover/Focus state +.dropdown-menu > li > a { + &:hover, + &:focus { + text-decoration: none; + color: @dropdown-link-hover-color; + background-color: @dropdown-link-hover-bg; + } +} + +// Active state +.dropdown-menu > .active > a { + &, + &:hover, + &:focus { + color: @dropdown-link-active-color; + text-decoration: none; + outline: 0; + background-color: @dropdown-link-active-bg; + } +} + +// Disabled state +// +// Gray out text and ensure the hover/focus state remains gray + +.dropdown-menu > .disabled > a { + &, + &:hover, + &:focus { + color: @dropdown-link-disabled-color; + } +} +// Nuke hover/focus effects +.dropdown-menu > .disabled > a { + &:hover, + &:focus { + text-decoration: none; + background-color: transparent; + background-image: none; // Remove CSS gradient + .reset-filter(); + cursor: not-allowed; + } +} + +// Open state for the dropdown +.open { + // Show the menu + > .dropdown-menu { + display: block; + } + + // Remove the outline when :focus is triggered + > a { + outline: 0; + } +} + +// Dropdown section headers +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: @font-size-small; + line-height: @line-height-base; + color: @dropdown-header-color; +} + +// Backdrop to catch body clicks on mobile, etc. +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: @zindex-dropdown - 10; +} + +// Right aligned dropdowns +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +// Allow for dropdowns to go bottom up (aka, dropup-menu) +// +// Just add .dropup after the standard .dropdown class and you're set, bro. +// TODO: abstract this so that the navbar fixed styles are not placed here? + +.dropup, +.navbar-fixed-bottom .dropdown { + // Reverse the caret + .caret { + // Firefox fix for https://github.com/twbs/bootstrap/issues/9538. Once this + // gets fixed, restore `border-top: 0;`. + border-top: 0 dotted; + border-bottom: 4px solid @dropdown-caret-color; + content: ""; + } + // Different positioning for bottom up menu + .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; + } +} + + +// Component alignment +// +// Reiterate per navbar.less and the modified component alignment there. + +@media (min-width: @grid-float-breakpoint) { + .navbar-right { + .dropdown-menu { + .pull-right > .dropdown-menu(); + } + } +} + diff --git a/styles/bootstrap/forms.less b/styles/bootstrap/forms.less new file mode 100644 index 0000000..f6bbce5 --- /dev/null +++ b/styles/bootstrap/forms.less @@ -0,0 +1,366 @@ +// +// Forms +// -------------------------------------------------- + + +// Normalize non-controls +// +// Restyle and baseline non-control form elements. + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: @line-height-computed; + font-size: (@font-size-base * 1.5); + line-height: inherit; + color: @legend-color; + border: 0; + border-bottom: 1px solid @legend-border-color; +} + +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} + + +// Normalize form controls + +// Override content-box in Normalize (* isn't specific enough) +input[type="search"] { + .box-sizing(border-box); +} + +// Position radios and checkboxes better +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; /* IE8-9 */ + line-height: normal; +} + +// Set the height of select and file controls to match text inputs +input[type="file"] { + display: block; +} + +// Make multiple select elements height not fixed +select[multiple], +select[size] { + height: auto; +} + +// Fix optgroup Firefox bug per https://github.com/twbs/bootstrap/issues/7611 +select optgroup { + font-size: inherit; + font-style: inherit; + font-family: inherit; +} + +// Focus for select, file, radio, and checkbox +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + .tab-focus(); +} + +// Fix for Chrome number input +// Setting certain font-sizes causes the `I` bar to appear on hover of the bottom increment button. +// See https://github.com/twbs/bootstrap/issues/8350 for more. +input[type="number"] { + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + height: auto; + } +} + +// Adjust output element +output { + display: block; + padding-top: (@padding-base-vertical + 1); + font-size: @font-size-base; + line-height: @line-height-base; + color: @input-color; + vertical-align: middle; +} + +// Placeholder +// +// Placeholder text gets special styles because when browsers invalidate entire +// lines if it doesn't understand a selector/ +.form-control { + .placeholder(); +} + + +// Common form controls +// +// Shared size and type resets for form controls. Apply `.form-control` to any +// of the following form controls: +// +// select +// textarea +// input[type="text"] +// input[type="password"] +// input[type="datetime"] +// input[type="datetime-local"] +// input[type="date"] +// input[type="month"] +// input[type="time"] +// input[type="week"] +// input[type="number"] +// input[type="email"] +// input[type="url"] +// input[type="search"] +// input[type="tel"] +// input[type="color"] + +.form-control { + display: block; + width: 100%; + height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border) + padding: @padding-base-vertical @padding-base-horizontal; + font-size: @font-size-base; + line-height: @line-height-base; + color: @input-color; + vertical-align: middle; + background-color: @input-bg; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid @input-border; + border-radius: @input-border-radius; + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); + .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s"); + + // Customize the `:focus` state to imitate native WebKit styles. + .form-control-focus(); + + // Disabled and read-only inputs + // Note: HTML5 says that controls under a fieldset > legend:first-child won't + // be disabled if the fieldset is disabled. Due to implementation difficulty, + // we don't honor that edge case; we style them as disabled anyway. + &[disabled], + &[readonly], + fieldset[disabled] & { + cursor: not-allowed; + background-color: @input-bg-disabled; + } + + // Reset height for `textarea`s + textarea& { + height: auto; + } +} + + +// Form groups +// +// Designed to help with the organization and spacing of vertical forms. For +// horizontal forms, use the predefined grid classes. + +.form-group { + margin-bottom: 15px; +} + + +// Checkboxes and radios +// +// Indent the labels to position radios/checkboxes as hanging controls. + +.radio, +.checkbox { + display: block; + min-height: @line-height-computed; // clear the floating input if there is no label text + margin-top: 10px; + margin-bottom: 10px; + padding-left: 20px; + vertical-align: middle; + label { + display: inline; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; + } +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing +} + +// Radios and checkboxes on same line +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; // space out consecutive inline controls +} + +// Apply same disabled cursor tweak as for inputs +// +// Note: Neither radios nor checkboxes can be readonly. +input[type="radio"], +input[type="checkbox"], +.radio, +.radio-inline, +.checkbox, +.checkbox-inline { + &[disabled], + fieldset[disabled] & { + cursor: not-allowed; + } +} + +// Form control sizing +.input-sm { + .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); +} + +.input-lg { + .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large); +} + + +// Form control feedback states +// +// Apply contextual and semantic states to individual form controls. + +// Warning +.has-warning { + .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg); +} +// Error +.has-error { + .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg); +} +// Success +.has-success { + .form-control-validation(@state-success-text; @state-success-text; @state-success-bg); +} + + +// Static form control text +// +// Apply class to a `p` element to make any string of text align with labels in +// a horizontal form layout. + +.form-control-static { + margin-bottom: 0; // Remove default margin from `p` +} + + +// Help text +// +// Apply to any element you wish to create light text for placement immediately +// below a form control. Use for general help, formatting, or instructional text. + +.help-block { + display: block; // account for any element using help-block + margin-top: 5px; + margin-bottom: 10px; + color: lighten(@text-color, 25%); // lighten the text some for contrast +} + + + +// Inline forms +// +// Make forms appear inline(-block) by adding the `.form-inline` class. Inline +// forms begin stacked on extra small (mobile) devices and then go inline when +// viewports reach <768px. +// +// Requires wrapping inputs and labels with `.form-group` for proper display of +// default HTML form controls and our custom form controls (e.g., input groups). +// +// Heads up! This is mixin-ed into `.navbar-form` in navbars.less. + +.form-inline { + + // Kick in the inline + @media (min-width: @screen-sm) { + // Inline-block all the things for "inline" + .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + + // In navbar-form, allow folks to *not* use `.form-group` + .form-control { + display: inline-block; + } + + // Remove default margin on radios/checkboxes that were used for stacking, and + // then undo the floating of radios and checkboxes to match (which also avoids + // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969). + .radio, + .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + } + .radio input[type="radio"], + .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } + } +} + + +// Horizontal forms +// +// Horizontal forms are built on grid classes and allow you to create forms with +// labels on the left and inputs on the right. + +.form-horizontal { + + // Consistent vertical alignment of labels, radios, and checkboxes + .control-label, + .radio, + .checkbox, + .radio-inline, + .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: (@padding-base-vertical + 1); // Default padding plus a border + } + + // Make form groups behave like rows + .form-group { + .make-row(); + } + + .form-control-static { + padding-top: (@padding-base-vertical + 1); + } + + // Only right align form labels here when the columns stop stacking + @media (min-width: @screen-sm-min) { + .control-label { + text-align: right; + } + } +} diff --git a/styles/bootstrap/grid.less b/styles/bootstrap/grid.less new file mode 100644 index 0000000..67e78f7 --- /dev/null +++ b/styles/bootstrap/grid.less @@ -0,0 +1,93 @@ +// +// Grid system +// -------------------------------------------------- + +// Set the container width, and override it for fixed navbars in media queries +.container { + .container-fixed(); +} + +// mobile first defaults +.row { + .make-row(); +} + +// Common styles for small and large grid columns +.make-grid-columns(); + + +// Extra small grid +// +// Grid classes for extra small devices like smartphones. No offset, push, or +// pull classes are present here due to the size of the target. +// +// Note that `.col-xs-12` doesn't get floated on purpose--there's no need since +// it's full-width. + +.make-grid-columns-float(xs); +.make-grid(@grid-columns, xs, width); +.make-grid(@grid-columns, xs, pull); +.make-grid(@grid-columns, xs, push); +.make-grid(@grid-columns, xs, offset); + + +// Small grid +// +// Columns, offsets, pushes, and pulls for the small device range, from phones +// to tablets. +// +// Note that `.col-sm-12` doesn't get floated on purpose--there's no need since +// it's full-width. + +@media (min-width: @screen-sm-min) { + .container { + width: @container-sm; + } + + .make-grid-columns-float(sm); + .make-grid(@grid-columns, sm, width); + .make-grid(@grid-columns, sm, pull); + .make-grid(@grid-columns, sm, push); + .make-grid(@grid-columns, sm, offset); +} + + +// Medium grid +// +// Columns, offsets, pushes, and pulls for the desktop device range. +// +// Note that `.col-md-12` doesn't get floated on purpose--there's no need since +// it's full-width. + +@media (min-width: @screen-md-min) { + .container { + width: @container-md; + } + + .make-grid-columns-float(md); + .make-grid(@grid-columns, md, width); + .make-grid(@grid-columns, md, pull); + .make-grid(@grid-columns, md, push); + .make-grid(@grid-columns, md, offset); +} + + +// Large grid +// +// Columns, offsets, pushes, and pulls for the large desktop device range. +// +// Note that `.col-lg-12` doesn't get floated on purpose--there's no need since +// it's full-width. + +@media (min-width: @screen-lg-min) { + .container { + width: @container-lg; + } + + .make-grid-columns-float(lg); + .make-grid(@grid-columns, lg, width); + .make-grid(@grid-columns, lg, pull); + .make-grid(@grid-columns, lg, push); + .make-grid(@grid-columns, lg, offset); +} + diff --git a/styles/bootstrap/input-groups.less b/styles/bootstrap/input-groups.less new file mode 100644 index 0000000..8516a79 --- /dev/null +++ b/styles/bootstrap/input-groups.less @@ -0,0 +1,136 @@ +// +// Input groups +// -------------------------------------------------- + +// Base styles +// ------------------------- +.input-group { + position: relative; // For dropdowns + display: table; + border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table + + // Undo padding and float of grid classes + &.col { + float: none; + padding-left: 0; + padding-right: 0; + } + + .form-control { + width: 100%; + margin-bottom: 0; + } +} + +// Sizing options +// +// Remix the default form control sizing classes into new ones for easier +// manipulation. + +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { .input-lg(); } +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { .input-sm(); } + + +// Display as table-cell +// ------------------------- +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; + + &:not(:first-child):not(:last-child) { + border-radius: 0; + } +} +// Addon and addon wrapper for buttons +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; // Match the inputs +} + +// Text input groups +// ------------------------- +.input-group-addon { + padding: @padding-base-vertical @padding-base-horizontal; + font-size: @font-size-base; + font-weight: normal; + line-height: 1; + color: @input-color; + text-align: center; + background-color: @input-group-addon-bg; + border: 1px solid @input-group-addon-border-color; + border-radius: @border-radius-base; + + // Sizing + &.input-sm { + padding: @padding-small-vertical @padding-small-horizontal; + font-size: @font-size-small; + border-radius: @border-radius-small; + } + &.input-lg { + padding: @padding-large-vertical @padding-large-horizontal; + font-size: @font-size-large; + border-radius: @border-radius-large; + } + + // Nuke default margins from checkboxes and radios to vertically center within. + input[type="radio"], + input[type="checkbox"] { + margin-top: 0; + } +} + +// Reset rounded corners +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { + .border-right-radius(0); +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child) { + .border-left-radius(0); +} +.input-group-addon:last-child { + border-left: 0; +} + +// Button input groups +// ------------------------- +.input-group-btn { + position: relative; + white-space: nowrap; + + // Negative margin to only have a 1px border between the two + &:first-child > .btn { + margin-right: -1px; + } + &:last-child > .btn { + margin-left: -1px; + } +} +.input-group-btn > .btn { + position: relative; + // Jankily prevent input button groups from wrapping + + .btn { + margin-left: -4px; + } + // Bring the "active" button to the front + &:hover, + &:active { + z-index: 2; + } +} diff --git a/styles/bootstrap/ionicons.less b/styles/bootstrap/ionicons.less new file mode 100644 index 0000000..2eae659 --- /dev/null +++ b/styles/bootstrap/ionicons.less @@ -0,0 +1,1480 @@ +@charset "UTF-8"; +/*! + Ionicons, v2.0.1 + Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ + https://twitter.com/benjsperry https://twitter.com/ionicframework + MIT License: https://github.com/driftyco/ionicons + + Android-style icons originally built by Google’s + Material Design Icons: https://github.com/google/material-design-icons + used under CC BY http://creativecommons.org/licenses/by/4.0/ + Modified icons to fit ionicon’s grid from original. +*/ +@font-face { font-family: "Ionicons"; src: url("@{icon-font-path}/@{icon-font-name}.eot?v=2.0.1"); src: url("@{icon-font-path}/@{icon-font-name}.eot?v=2.0.1#iefix") format("embedded-opentype"), url("@{icon-font-path}/@{icon-font-name}.ttf?v=2.0.1") format("truetype"), url("@{icon-font-path}/@{icon-font-name}.woff?v=2.0.1") format("woff"), url("@{icon-font-path}/@{icon-font-name}.svg?v=2.0.1#Ionicons") format("svg"); font-weight: normal; font-style: normal; } +.ion, .ionicons, .ion-alert:before, .ion-alert-circled:before, .ion-android-add:before, .ion-android-add-circle:before, .ion-android-alarm-clock:before, .ion-android-alert:before, .ion-android-apps:before, .ion-android-archive:before, .ion-android-arrow-back:before, .ion-android-arrow-down:before, .ion-android-arrow-dropdown:before, .ion-android-arrow-dropdown-circle:before, .ion-android-arrow-dropleft:before, .ion-android-arrow-dropleft-circle:before, .ion-android-arrow-dropright:before, .ion-android-arrow-dropright-circle:before, .ion-android-arrow-dropup:before, .ion-android-arrow-dropup-circle:before, .ion-android-arrow-forward:before, .ion-android-arrow-up:before, .ion-android-attach:before, .ion-android-bar:before, .ion-android-bicycle:before, .ion-android-boat:before, .ion-android-bookmark:before, .ion-android-bulb:before, .ion-android-bus:before, .ion-android-calendar:before, .ion-android-call:before, .ion-android-camera:before, .ion-android-cancel:before, .ion-android-car:before, .ion-android-cart:before, .ion-android-chat:before, .ion-android-checkbox:before, .ion-android-checkbox-blank:before, .ion-android-checkbox-outline:before, .ion-android-checkbox-outline-blank:before, .ion-android-checkmark-circle:before, .ion-android-clipboard:before, .ion-android-close:before, .ion-android-cloud:before, .ion-android-cloud-circle:before, .ion-android-cloud-done:before, .ion-android-cloud-outline:before, .ion-android-color-palette:before, .ion-android-compass:before, .ion-android-contact:before, .ion-android-contacts:before, .ion-android-contract:before, .ion-android-create:before, .ion-android-delete:before, .ion-android-desktop:before, .ion-android-document:before, .ion-android-done:before, .ion-android-done-all:before, .ion-android-download:before, .ion-android-drafts:before, .ion-android-exit:before, .ion-android-expand:before, .ion-android-favorite:before, .ion-android-favorite-outline:before, .ion-android-film:before, .ion-android-folder:before, .ion-android-folder-open:before, .ion-android-funnel:before, .ion-android-globe:before, .ion-android-hand:before, .ion-android-hangout:before, .ion-android-happy:before, .ion-android-home:before, .ion-android-image:before, .ion-android-laptop:before, .ion-android-list:before, .ion-android-locate:before, .ion-android-lock:before, .ion-android-mail:before, .ion-android-map:before, .ion-android-menu:before, .ion-android-microphone:before, .ion-android-microphone-off:before, .ion-android-more-horizontal:before, .ion-android-more-vertical:before, .ion-android-navigate:before, .ion-android-notifications:before, .ion-android-notifications-none:before, .ion-android-notifications-off:before, .ion-android-open:before, .ion-android-options:before, .ion-android-people:before, .ion-android-person:before, .ion-android-person-add:before, .ion-android-phone-landscape:before, .ion-android-phone-portrait:before, .ion-android-pin:before, .ion-android-plane:before, .ion-android-playstore:before, .ion-android-print:before, .ion-android-radio-button-off:before, .ion-android-radio-button-on:before, .ion-android-refresh:before, .ion-android-remove:before, .ion-android-remove-circle:before, .ion-android-restaurant:before, .ion-android-sad:before, .ion-android-search:before, .ion-android-send:before, .ion-android-settings:before, .ion-android-share:before, .ion-android-share-alt:before, .ion-android-star:before, .ion-android-star-half:before, .ion-android-star-outline:before, .ion-android-stopwatch:before, .ion-android-subway:before, .ion-android-sunny:before, .ion-android-sync:before, .ion-android-textsms:before, .ion-android-time:before, .ion-android-train:before, .ion-android-unlock:before, .ion-android-upload:before, .ion-android-volume-down:before, .ion-android-volume-mute:before, .ion-android-volume-off:before, .ion-android-volume-up:before, .ion-android-walk:before, .ion-android-warning:before, .ion-android-watch:before, .ion-android-wifi:before, .ion-aperture:before, .ion-archive:before, .ion-arrow-down-a:before, .ion-arrow-down-b:before, .ion-arrow-down-c:before, .ion-arrow-expand:before, .ion-arrow-graph-down-left:before, .ion-arrow-graph-down-right:before, .ion-arrow-graph-up-left:before, .ion-arrow-graph-up-right:before, .ion-arrow-left-a:before, .ion-arrow-left-b:before, .ion-arrow-left-c:before, .ion-arrow-move:before, .ion-arrow-resize:before, .ion-arrow-return-left:before, .ion-arrow-return-right:before, .ion-arrow-right-a:before, .ion-arrow-right-b:before, .ion-arrow-right-c:before, .ion-arrow-shrink:before, .ion-arrow-swap:before, .ion-arrow-up-a:before, .ion-arrow-up-b:before, .ion-arrow-up-c:before, .ion-asterisk:before, .ion-at:before, .ion-backspace:before, .ion-backspace-outline:before, .ion-bag:before, .ion-battery-charging:before, .ion-battery-empty:before, .ion-battery-full:before, .ion-battery-half:before, .ion-battery-low:before, .ion-beaker:before, .ion-beer:before, .ion-bluetooth:before, .ion-bonfire:before, .ion-bookmark:before, .ion-bowtie:before, .ion-briefcase:before, .ion-bug:before, .ion-calculator:before, .ion-calendar:before, .ion-camera:before, .ion-card:before, .ion-cash:before, .ion-chatbox:before, .ion-chatbox-working:before, .ion-chatboxes:before, .ion-chatbubble:before, .ion-chatbubble-working:before, .ion-chatbubbles:before, .ion-checkmark:before, .ion-checkmark-circled:before, .ion-checkmark-round:before, .ion-chevron-down:before, .ion-chevron-left:before, .ion-chevron-right:before, .ion-chevron-up:before, .ion-clipboard:before, .ion-clock:before, .ion-close:before, .ion-close-circled:before, .ion-close-round:before, .ion-closed-captioning:before, .ion-cloud:before, .ion-code:before, .ion-code-download:before, .ion-code-working:before, .ion-coffee:before, .ion-compass:before, .ion-compose:before, .ion-connection-bars:before, .ion-contrast:before, .ion-crop:before, .ion-cube:before, .ion-disc:before, .ion-document:before, .ion-document-text:before, .ion-drag:before, .ion-earth:before, .ion-easel:before, .ion-edit:before, .ion-egg:before, .ion-eject:before, .ion-email:before, .ion-email-unread:before, .ion-erlenmeyer-flask:before, .ion-erlenmeyer-flask-bubbles:before, .ion-eye:before, .ion-eye-disabled:before, .ion-female:before, .ion-filing:before, .ion-film-marker:before, .ion-fireball:before, .ion-flag:before, .ion-flame:before, .ion-flash:before, .ion-flash-off:before, .ion-folder:before, .ion-fork:before, .ion-fork-repo:before, .ion-forward:before, .ion-funnel:before, .ion-gear-a:before, .ion-gear-b:before, .ion-grid:before, .ion-hammer:before, .ion-happy:before, .ion-happy-outline:before, .ion-headphone:before, .ion-heart:before, .ion-heart-broken:before, .ion-help:before, .ion-help-buoy:before, .ion-help-circled:before, .ion-home:before, .ion-icecream:before, .ion-image:before, .ion-images:before, .ion-information:before, .ion-information-circled:before, .ion-ionic:before, .ion-ios-alarm:before, .ion-ios-alarm-outline:before, .ion-ios-albums:before, .ion-ios-albums-outline:before, .ion-ios-americanfootball:before, .ion-ios-americanfootball-outline:before, .ion-ios-analytics:before, .ion-ios-analytics-outline:before, .ion-ios-arrow-back:before, .ion-ios-arrow-down:before, .ion-ios-arrow-forward:before, .ion-ios-arrow-left:before, .ion-ios-arrow-right:before, .ion-ios-arrow-thin-down:before, .ion-ios-arrow-thin-left:before, .ion-ios-arrow-thin-right:before, .ion-ios-arrow-thin-up:before, .ion-ios-arrow-up:before, .ion-ios-at:before, .ion-ios-at-outline:before, .ion-ios-barcode:before, .ion-ios-barcode-outline:before, .ion-ios-baseball:before, .ion-ios-baseball-outline:before, .ion-ios-basketball:before, .ion-ios-basketball-outline:before, .ion-ios-bell:before, .ion-ios-bell-outline:before, .ion-ios-body:before, .ion-ios-body-outline:before, .ion-ios-bolt:before, .ion-ios-bolt-outline:before, .ion-ios-book:before, .ion-ios-book-outline:before, .ion-ios-bookmarks:before, .ion-ios-bookmarks-outline:before, .ion-ios-box:before, .ion-ios-box-outline:before, .ion-ios-briefcase:before, .ion-ios-briefcase-outline:before, .ion-ios-browsers:before, .ion-ios-browsers-outline:before, .ion-ios-calculator:before, .ion-ios-calculator-outline:before, .ion-ios-calendar:before, .ion-ios-calendar-outline:before, .ion-ios-camera:before, .ion-ios-camera-outline:before, .ion-ios-cart:before, .ion-ios-cart-outline:before, .ion-ios-chatboxes:before, .ion-ios-chatboxes-outline:before, .ion-ios-chatbubble:before, .ion-ios-chatbubble-outline:before, .ion-ios-checkmark:before, .ion-ios-checkmark-empty:before, .ion-ios-checkmark-outline:before, .ion-ios-circle-filled:before, .ion-ios-circle-outline:before, .ion-ios-clock:before, .ion-ios-clock-outline:before, .ion-ios-close:before, .ion-ios-close-empty:before, .ion-ios-close-outline:before, .ion-ios-cloud:before, .ion-ios-cloud-download:before, .ion-ios-cloud-download-outline:before, .ion-ios-cloud-outline:before, .ion-ios-cloud-upload:before, .ion-ios-cloud-upload-outline:before, .ion-ios-cloudy:before, .ion-ios-cloudy-night:before, .ion-ios-cloudy-night-outline:before, .ion-ios-cloudy-outline:before, .ion-ios-cog:before, .ion-ios-cog-outline:before, .ion-ios-color-filter:before, .ion-ios-color-filter-outline:before, .ion-ios-color-wand:before, .ion-ios-color-wand-outline:before, .ion-ios-compose:before, .ion-ios-compose-outline:before, .ion-ios-contact:before, .ion-ios-contact-outline:before, .ion-ios-copy:before, .ion-ios-copy-outline:before, .ion-ios-crop:before, .ion-ios-crop-strong:before, .ion-ios-download:before, .ion-ios-download-outline:before, .ion-ios-drag:before, .ion-ios-email:before, .ion-ios-email-outline:before, .ion-ios-eye:before, .ion-ios-eye-outline:before, .ion-ios-fastforward:before, .ion-ios-fastforward-outline:before, .ion-ios-filing:before, .ion-ios-filing-outline:before, .ion-ios-film:before, .ion-ios-film-outline:before, .ion-ios-flag:before, .ion-ios-flag-outline:before, .ion-ios-flame:before, .ion-ios-flame-outline:before, .ion-ios-flask:before, .ion-ios-flask-outline:before, .ion-ios-flower:before, .ion-ios-flower-outline:before, .ion-ios-folder:before, .ion-ios-folder-outline:before, .ion-ios-football:before, .ion-ios-football-outline:before, .ion-ios-game-controller-a:before, .ion-ios-game-controller-a-outline:before, .ion-ios-game-controller-b:before, .ion-ios-game-controller-b-outline:before, .ion-ios-gear:before, .ion-ios-gear-outline:before, .ion-ios-glasses:before, .ion-ios-glasses-outline:before, .ion-ios-grid-view:before, .ion-ios-grid-view-outline:before, .ion-ios-heart:before, .ion-ios-heart-outline:before, .ion-ios-help:before, .ion-ios-help-empty:before, .ion-ios-help-outline:before, .ion-ios-home:before, .ion-ios-home-outline:before, .ion-ios-infinite:before, .ion-ios-infinite-outline:before, .ion-ios-information:before, .ion-ios-information-empty:before, .ion-ios-information-outline:before, .ion-ios-ionic-outline:before, .ion-ios-keypad:before, .ion-ios-keypad-outline:before, .ion-ios-lightbulb:before, .ion-ios-lightbulb-outline:before, .ion-ios-list:before, .ion-ios-list-outline:before, .ion-ios-location:before, .ion-ios-location-outline:before, .ion-ios-locked:before, .ion-ios-locked-outline:before, .ion-ios-loop:before, .ion-ios-loop-strong:before, .ion-ios-medical:before, .ion-ios-medical-outline:before, .ion-ios-medkit:before, .ion-ios-medkit-outline:before, .ion-ios-mic:before, .ion-ios-mic-off:before, .ion-ios-mic-outline:before, .ion-ios-minus:before, .ion-ios-minus-empty:before, .ion-ios-minus-outline:before, .ion-ios-monitor:before, .ion-ios-monitor-outline:before, .ion-ios-moon:before, .ion-ios-moon-outline:before, .ion-ios-more:before, .ion-ios-more-outline:before, .ion-ios-musical-note:before, .ion-ios-musical-notes:before, .ion-ios-navigate:before, .ion-ios-navigate-outline:before, .ion-ios-nutrition:before, .ion-ios-nutrition-outline:before, .ion-ios-paper:before, .ion-ios-paper-outline:before, .ion-ios-paperplane:before, .ion-ios-paperplane-outline:before, .ion-ios-partlysunny:before, .ion-ios-partlysunny-outline:before, .ion-ios-pause:before, .ion-ios-pause-outline:before, .ion-ios-paw:before, .ion-ios-paw-outline:before, .ion-ios-people:before, .ion-ios-people-outline:before, .ion-ios-person:before, .ion-ios-person-outline:before, .ion-ios-personadd:before, .ion-ios-personadd-outline:before, .ion-ios-photos:before, .ion-ios-photos-outline:before, .ion-ios-pie:before, .ion-ios-pie-outline:before, .ion-ios-pint:before, .ion-ios-pint-outline:before, .ion-ios-play:before, .ion-ios-play-outline:before, .ion-ios-plus:before, .ion-ios-plus-empty:before, .ion-ios-plus-outline:before, .ion-ios-pricetag:before, .ion-ios-pricetag-outline:before, .ion-ios-pricetags:before, .ion-ios-pricetags-outline:before, .ion-ios-printer:before, .ion-ios-printer-outline:before, .ion-ios-pulse:before, .ion-ios-pulse-strong:before, .ion-ios-rainy:before, .ion-ios-rainy-outline:before, .ion-ios-recording:before, .ion-ios-recording-outline:before, .ion-ios-redo:before, .ion-ios-redo-outline:before, .ion-ios-refresh:before, .ion-ios-refresh-empty:before, .ion-ios-refresh-outline:before, .ion-ios-reload:before, .ion-ios-reverse-camera:before, .ion-ios-reverse-camera-outline:before, .ion-ios-rewind:before, .ion-ios-rewind-outline:before, .ion-ios-rose:before, .ion-ios-rose-outline:before, .ion-ios-search:before, .ion-ios-search-strong:before, .ion-ios-settings:before, .ion-ios-settings-strong:before, .ion-ios-shuffle:before, .ion-ios-shuffle-strong:before, .ion-ios-skipbackward:before, .ion-ios-skipbackward-outline:before, .ion-ios-skipforward:before, .ion-ios-skipforward-outline:before, .ion-ios-snowy:before, .ion-ios-speedometer:before, .ion-ios-speedometer-outline:before, .ion-ios-star:before, .ion-ios-star-half:before, .ion-ios-star-outline:before, .ion-ios-stopwatch:before, .ion-ios-stopwatch-outline:before, .ion-ios-sunny:before, .ion-ios-sunny-outline:before, .ion-ios-telephone:before, .ion-ios-telephone-outline:before, .ion-ios-tennisball:before, .ion-ios-tennisball-outline:before, .ion-ios-thunderstorm:before, .ion-ios-thunderstorm-outline:before, .ion-ios-time:before, .ion-ios-time-outline:before, .ion-ios-timer:before, .ion-ios-timer-outline:before, .ion-ios-toggle:before, .ion-ios-toggle-outline:before, .ion-ios-trash:before, .ion-ios-trash-outline:before, .ion-ios-undo:before, .ion-ios-undo-outline:before, .ion-ios-unlocked:before, .ion-ios-unlocked-outline:before, .ion-ios-upload:before, .ion-ios-upload-outline:before, .ion-ios-videocam:before, .ion-ios-videocam-outline:before, .ion-ios-volume-high:before, .ion-ios-volume-low:before, .ion-ios-wineglass:before, .ion-ios-wineglass-outline:before, .ion-ios-world:before, .ion-ios-world-outline:before, .ion-ipad:before, .ion-iphone:before, .ion-ipod:before, .ion-jet:before, .ion-key:before, .ion-knife:before, .ion-laptop:before, .ion-leaf:before, .ion-levels:before, .ion-lightbulb:before, .ion-link:before, .ion-load-a:before, .ion-load-b:before, .ion-load-c:before, .ion-load-d:before, .ion-location:before, .ion-lock-combination:before, .ion-locked:before, .ion-log-in:before, .ion-log-out:before, .ion-loop:before, .ion-magnet:before, .ion-male:before, .ion-man:before, .ion-map:before, .ion-medkit:before, .ion-merge:before, .ion-mic-a:before, .ion-mic-b:before, .ion-mic-c:before, .ion-minus:before, .ion-minus-circled:before, .ion-minus-round:before, .ion-model-s:before, .ion-monitor:before, .ion-more:before, .ion-mouse:before, .ion-music-note:before, .ion-navicon:before, .ion-navicon-round:before, .ion-navigate:before, .ion-network:before, .ion-no-smoking:before, .ion-nuclear:before, .ion-outlet:before, .ion-paintbrush:before, .ion-paintbucket:before, .ion-paper-airplane:before, .ion-paperclip:before, .ion-pause:before, .ion-person:before, .ion-person-add:before, .ion-person-stalker:before, .ion-pie-graph:before, .ion-pin:before, .ion-pinpoint:before, .ion-pizza:before, .ion-plane:before, .ion-planet:before, .ion-play:before, .ion-playstation:before, .ion-plus:before, .ion-plus-circled:before, .ion-plus-round:before, .ion-podium:before, .ion-pound:before, .ion-power:before, .ion-pricetag:before, .ion-pricetags:before, .ion-printer:before, .ion-pull-request:before, .ion-qr-scanner:before, .ion-quote:before, .ion-radio-waves:before, .ion-record:before, .ion-refresh:before, .ion-reply:before, .ion-reply-all:before, .ion-ribbon-a:before, .ion-ribbon-b:before, .ion-sad:before, .ion-sad-outline:before, .ion-scissors:before, .ion-search:before, .ion-settings:before, .ion-share:before, .ion-shuffle:before, .ion-skip-backward:before, .ion-skip-forward:before, .ion-social-android:before, .ion-social-android-outline:before, .ion-social-angular:before, .ion-social-angular-outline:before, .ion-social-apple:before, .ion-social-apple-outline:before, .ion-social-bitcoin:before, .ion-social-bitcoin-outline:before, .ion-social-buffer:before, .ion-social-buffer-outline:before, .ion-social-chrome:before, .ion-social-chrome-outline:before, .ion-social-codepen:before, .ion-social-codepen-outline:before, .ion-social-css3:before, .ion-social-css3-outline:before, .ion-social-designernews:before, .ion-social-designernews-outline:before, .ion-social-dribbble:before, .ion-social-dribbble-outline:before, .ion-social-dropbox:before, .ion-social-dropbox-outline:before, .ion-social-euro:before, .ion-social-euro-outline:before, .ion-social-facebook:before, .ion-social-facebook-outline:before, .ion-social-foursquare:before, .ion-social-foursquare-outline:before, .ion-social-freebsd-devil:before, .ion-social-github:before, .ion-social-github-outline:before, .ion-social-google:before, .ion-social-google-outline:before, .ion-social-googleplus:before, .ion-social-googleplus-outline:before, .ion-social-hackernews:before, .ion-social-hackernews-outline:before, .ion-social-html5:before, .ion-social-html5-outline:before, .ion-social-instagram:before, .ion-social-instagram-outline:before, .ion-social-javascript:before, .ion-social-javascript-outline:before, .ion-social-linkedin:before, .ion-social-linkedin-outline:before, .ion-social-markdown:before, .ion-social-nodejs:before, .ion-social-octocat:before, .ion-social-pinterest:before, .ion-social-pinterest-outline:before, .ion-social-python:before, .ion-social-reddit:before, .ion-social-reddit-outline:before, .ion-social-rss:before, .ion-social-rss-outline:before, .ion-social-sass:before, .ion-social-skype:before, .ion-social-skype-outline:before, .ion-social-snapchat:before, .ion-social-snapchat-outline:before, .ion-social-tumblr:before, .ion-social-tumblr-outline:before, .ion-social-tux:before, .ion-social-twitch:before, .ion-social-twitch-outline:before, .ion-social-twitter:before, .ion-social-twitter-outline:before, .ion-social-usd:before, .ion-social-usd-outline:before, .ion-social-vimeo:before, .ion-social-vimeo-outline:before, .ion-social-whatsapp:before, .ion-social-whatsapp-outline:before, .ion-social-windows:before, .ion-social-windows-outline:before, .ion-social-wordpress:before, .ion-social-wordpress-outline:before, .ion-social-yahoo:before, .ion-social-yahoo-outline:before, .ion-social-yen:before, .ion-social-yen-outline:before, .ion-social-youtube:before, .ion-social-youtube-outline:before, .ion-soup-can:before, .ion-soup-can-outline:before, .ion-speakerphone:before, .ion-speedometer:before, .ion-spoon:before, .ion-star:before, .ion-stats-bars:before, .ion-steam:before, .ion-stop:before, .ion-thermometer:before, .ion-thumbsdown:before, .ion-thumbsup:before, .ion-toggle:before, .ion-toggle-filled:before, .ion-transgender:before, .ion-trash-a:before, .ion-trash-b:before, .ion-trophy:before, .ion-tshirt:before, .ion-tshirt-outline:before, .ion-umbrella:before, .ion-university:before, .ion-unlocked:before, .ion-upload:before, .ion-usb:before, .ion-videocamera:before, .ion-volume-high:before, .ion-volume-low:before, .ion-volume-medium:before, .ion-volume-mute:before, .ion-wand:before, .ion-waterdrop:before, .ion-wifi:before, .ion-wineglass:before, .ion-woman:before, .ion-wrench:before, .ion-xbox:before { display: inline-block; font-family: "Ionicons"; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; text-rendering: auto; line-height: 1; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } + +.ion-alert:before { content: "\f101"; } + +.ion-alert-circled:before { content: "\f100"; } + +.ion-android-add:before { content: "\f2c7"; } + +.ion-android-add-circle:before { content: "\f359"; } + +.ion-android-alarm-clock:before { content: "\f35a"; } + +.ion-android-alert:before { content: "\f35b"; } + +.ion-android-apps:before { content: "\f35c"; } + +.ion-android-archive:before { content: "\f2c9"; } + +.ion-android-arrow-back:before { content: "\f2ca"; } + +.ion-android-arrow-down:before { content: "\f35d"; } + +.ion-android-arrow-dropdown:before { content: "\f35f"; } + +.ion-android-arrow-dropdown-circle:before { content: "\f35e"; } + +.ion-android-arrow-dropleft:before { content: "\f361"; } + +.ion-android-arrow-dropleft-circle:before { content: "\f360"; } + +.ion-android-arrow-dropright:before { content: "\f363"; } + +.ion-android-arrow-dropright-circle:before { content: "\f362"; } + +.ion-android-arrow-dropup:before { content: "\f365"; } + +.ion-android-arrow-dropup-circle:before { content: "\f364"; } + +.ion-android-arrow-forward:before { content: "\f30f"; } + +.ion-android-arrow-up:before { content: "\f366"; } + +.ion-android-attach:before { content: "\f367"; } + +.ion-android-bar:before { content: "\f368"; } + +.ion-android-bicycle:before { content: "\f369"; } + +.ion-android-boat:before { content: "\f36a"; } + +.ion-android-bookmark:before { content: "\f36b"; } + +.ion-android-bulb:before { content: "\f36c"; } + +.ion-android-bus:before { content: "\f36d"; } + +.ion-android-calendar:before { content: "\f2d1"; } + +.ion-android-call:before { content: "\f2d2"; } + +.ion-android-camera:before { content: "\f2d3"; } + +.ion-android-cancel:before { content: "\f36e"; } + +.ion-android-car:before { content: "\f36f"; } + +.ion-android-cart:before { content: "\f370"; } + +.ion-android-chat:before { content: "\f2d4"; } + +.ion-android-checkbox:before { content: "\f374"; } + +.ion-android-checkbox-blank:before { content: "\f371"; } + +.ion-android-checkbox-outline:before { content: "\f373"; } + +.ion-android-checkbox-outline-blank:before { content: "\f372"; } + +.ion-android-checkmark-circle:before { content: "\f375"; } + +.ion-android-clipboard:before { content: "\f376"; } + +.ion-android-close:before { content: "\f2d7"; } + +.ion-android-cloud:before { content: "\f37a"; } + +.ion-android-cloud-circle:before { content: "\f377"; } + +.ion-android-cloud-done:before { content: "\f378"; } + +.ion-android-cloud-outline:before { content: "\f379"; } + +.ion-android-color-palette:before { content: "\f37b"; } + +.ion-android-compass:before { content: "\f37c"; } + +.ion-android-contact:before { content: "\f2d8"; } + +.ion-android-contacts:before { content: "\f2d9"; } + +.ion-android-contract:before { content: "\f37d"; } + +.ion-android-create:before { content: "\f37e"; } + +.ion-android-delete:before { content: "\f37f"; } + +.ion-android-desktop:before { content: "\f380"; } + +.ion-android-document:before { content: "\f381"; } + +.ion-android-done:before { content: "\f383"; } + +.ion-android-done-all:before { content: "\f382"; } + +.ion-android-download:before { content: "\f2dd"; } + +.ion-android-drafts:before { content: "\f384"; } + +.ion-android-exit:before { content: "\f385"; } + +.ion-android-expand:before { content: "\f386"; } + +.ion-android-favorite:before { content: "\f388"; } + +.ion-android-favorite-outline:before { content: "\f387"; } + +.ion-android-film:before { content: "\f389"; } + +.ion-android-folder:before { content: "\f2e0"; } + +.ion-android-folder-open:before { content: "\f38a"; } + +.ion-android-funnel:before { content: "\f38b"; } + +.ion-android-globe:before { content: "\f38c"; } + +.ion-android-hand:before { content: "\f2e3"; } + +.ion-android-hangout:before { content: "\f38d"; } + +.ion-android-happy:before { content: "\f38e"; } + +.ion-android-home:before { content: "\f38f"; } + +.ion-android-image:before { content: "\f2e4"; } + +.ion-android-laptop:before { content: "\f390"; } + +.ion-android-list:before { content: "\f391"; } + +.ion-android-locate:before { content: "\f2e9"; } + +.ion-android-lock:before { content: "\f392"; } + +.ion-android-mail:before { content: "\f2eb"; } + +.ion-android-map:before { content: "\f393"; } + +.ion-android-menu:before { content: "\f394"; } + +.ion-android-microphone:before { content: "\f2ec"; } + +.ion-android-microphone-off:before { content: "\f395"; } + +.ion-android-more-horizontal:before { content: "\f396"; } + +.ion-android-more-vertical:before { content: "\f397"; } + +.ion-android-navigate:before { content: "\f398"; } + +.ion-android-notifications:before { content: "\f39b"; } + +.ion-android-notifications-none:before { content: "\f399"; } + +.ion-android-notifications-off:before { content: "\f39a"; } + +.ion-android-open:before { content: "\f39c"; } + +.ion-android-options:before { content: "\f39d"; } + +.ion-android-people:before { content: "\f39e"; } + +.ion-android-person:before { content: "\f3a0"; } + +.ion-android-person-add:before { content: "\f39f"; } + +.ion-android-phone-landscape:before { content: "\f3a1"; } + +.ion-android-phone-portrait:before { content: "\f3a2"; } + +.ion-android-pin:before { content: "\f3a3"; } + +.ion-android-plane:before { content: "\f3a4"; } + +.ion-android-playstore:before { content: "\f2f0"; } + +.ion-android-print:before { content: "\f3a5"; } + +.ion-android-radio-button-off:before { content: "\f3a6"; } + +.ion-android-radio-button-on:before { content: "\f3a7"; } + +.ion-android-refresh:before { content: "\f3a8"; } + +.ion-android-remove:before { content: "\f2f4"; } + +.ion-android-remove-circle:before { content: "\f3a9"; } + +.ion-android-restaurant:before { content: "\f3aa"; } + +.ion-android-sad:before { content: "\f3ab"; } + +.ion-android-search:before { content: "\f2f5"; } + +.ion-android-send:before { content: "\f2f6"; } + +.ion-android-settings:before { content: "\f2f7"; } + +.ion-android-share:before { content: "\f2f8"; } + +.ion-android-share-alt:before { content: "\f3ac"; } + +.ion-android-star:before { content: "\f2fc"; } + +.ion-android-star-half:before { content: "\f3ad"; } + +.ion-android-star-outline:before { content: "\f3ae"; } + +.ion-android-stopwatch:before { content: "\f2fd"; } + +.ion-android-subway:before { content: "\f3af"; } + +.ion-android-sunny:before { content: "\f3b0"; } + +.ion-android-sync:before { content: "\f3b1"; } + +.ion-android-textsms:before { content: "\f3b2"; } + +.ion-android-time:before { content: "\f3b3"; } + +.ion-android-train:before { content: "\f3b4"; } + +.ion-android-unlock:before { content: "\f3b5"; } + +.ion-android-upload:before { content: "\f3b6"; } + +.ion-android-volume-down:before { content: "\f3b7"; } + +.ion-android-volume-mute:before { content: "\f3b8"; } + +.ion-android-volume-off:before { content: "\f3b9"; } + +.ion-android-volume-up:before { content: "\f3ba"; } + +.ion-android-walk:before { content: "\f3bb"; } + +.ion-android-warning:before { content: "\f3bc"; } + +.ion-android-watch:before { content: "\f3bd"; } + +.ion-android-wifi:before { content: "\f305"; } + +.ion-aperture:before { content: "\f313"; } + +.ion-archive:before { content: "\f102"; } + +.ion-arrow-down-a:before { content: "\f103"; } + +.ion-arrow-down-b:before { content: "\f104"; } + +.ion-arrow-down-c:before { content: "\f105"; } + +.ion-arrow-expand:before { content: "\f25e"; } + +.ion-arrow-graph-down-left:before { content: "\f25f"; } + +.ion-arrow-graph-down-right:before { content: "\f260"; } + +.ion-arrow-graph-up-left:before { content: "\f261"; } + +.ion-arrow-graph-up-right:before { content: "\f262"; } + +.ion-arrow-left-a:before { content: "\f106"; } + +.ion-arrow-left-b:before { content: "\f107"; } + +.ion-arrow-left-c:before { content: "\f108"; } + +.ion-arrow-move:before { content: "\f263"; } + +.ion-arrow-resize:before { content: "\f264"; } + +.ion-arrow-return-left:before { content: "\f265"; } + +.ion-arrow-return-right:before { content: "\f266"; } + +.ion-arrow-right-a:before { content: "\f109"; } + +.ion-arrow-right-b:before { content: "\f10a"; } + +.ion-arrow-right-c:before { content: "\f10b"; } + +.ion-arrow-shrink:before { content: "\f267"; } + +.ion-arrow-swap:before { content: "\f268"; } + +.ion-arrow-up-a:before { content: "\f10c"; } + +.ion-arrow-up-b:before { content: "\f10d"; } + +.ion-arrow-up-c:before { content: "\f10e"; } + +.ion-asterisk:before { content: "\f314"; } + +.ion-at:before { content: "\f10f"; } + +.ion-backspace:before { content: "\f3bf"; } + +.ion-backspace-outline:before { content: "\f3be"; } + +.ion-bag:before { content: "\f110"; } + +.ion-battery-charging:before { content: "\f111"; } + +.ion-battery-empty:before { content: "\f112"; } + +.ion-battery-full:before { content: "\f113"; } + +.ion-battery-half:before { content: "\f114"; } + +.ion-battery-low:before { content: "\f115"; } + +.ion-beaker:before { content: "\f269"; } + +.ion-beer:before { content: "\f26a"; } + +.ion-bluetooth:before { content: "\f116"; } + +.ion-bonfire:before { content: "\f315"; } + +.ion-bookmark:before { content: "\f26b"; } + +.ion-bowtie:before { content: "\f3c0"; } + +.ion-briefcase:before { content: "\f26c"; } + +.ion-bug:before { content: "\f2be"; } + +.ion-calculator:before { content: "\f26d"; } + +.ion-calendar:before { content: "\f117"; } + +.ion-camera:before { content: "\f118"; } + +.ion-card:before { content: "\f119"; } + +.ion-cash:before { content: "\f316"; } + +.ion-chatbox:before { content: "\f11b"; } + +.ion-chatbox-working:before { content: "\f11a"; } + +.ion-chatboxes:before { content: "\f11c"; } + +.ion-chatbubble:before { content: "\f11e"; } + +.ion-chatbubble-working:before { content: "\f11d"; } + +.ion-chatbubbles:before { content: "\f11f"; } + +.ion-checkmark:before { content: "\f122"; } + +.ion-checkmark-circled:before { content: "\f120"; } + +.ion-checkmark-round:before { content: "\f121"; } + +.ion-chevron-down:before { content: "\f123"; } + +.ion-chevron-left:before { content: "\f124"; } + +.ion-chevron-right:before { content: "\f125"; } + +.ion-chevron-up:before { content: "\f126"; } + +.ion-clipboard:before { content: "\f127"; } + +.ion-clock:before { content: "\f26e"; } + +.ion-close:before { content: "\f12a"; } + +.ion-close-circled:before { content: "\f128"; } + +.ion-close-round:before { content: "\f129"; } + +.ion-closed-captioning:before { content: "\f317"; } + +.ion-cloud:before { content: "\f12b"; } + +.ion-code:before { content: "\f271"; } + +.ion-code-download:before { content: "\f26f"; } + +.ion-code-working:before { content: "\f270"; } + +.ion-coffee:before { content: "\f272"; } + +.ion-compass:before { content: "\f273"; } + +.ion-compose:before { content: "\f12c"; } + +.ion-connection-bars:before { content: "\f274"; } + +.ion-contrast:before { content: "\f275"; } + +.ion-crop:before { content: "\f3c1"; } + +.ion-cube:before { content: "\f318"; } + +.ion-disc:before { content: "\f12d"; } + +.ion-document:before { content: "\f12f"; } + +.ion-document-text:before { content: "\f12e"; } + +.ion-drag:before { content: "\f130"; } + +.ion-earth:before { content: "\f276"; } + +.ion-easel:before { content: "\f3c2"; } + +.ion-edit:before { content: "\f2bf"; } + +.ion-egg:before { content: "\f277"; } + +.ion-eject:before { content: "\f131"; } + +.ion-email:before { content: "\f132"; } + +.ion-email-unread:before { content: "\f3c3"; } + +.ion-erlenmeyer-flask:before { content: "\f3c5"; } + +.ion-erlenmeyer-flask-bubbles:before { content: "\f3c4"; } + +.ion-eye:before { content: "\f133"; } + +.ion-eye-disabled:before { content: "\f306"; } + +.ion-female:before { content: "\f278"; } + +.ion-filing:before { content: "\f134"; } + +.ion-film-marker:before { content: "\f135"; } + +.ion-fireball:before { content: "\f319"; } + +.ion-flag:before { content: "\f279"; } + +.ion-flame:before { content: "\f31a"; } + +.ion-flash:before { content: "\f137"; } + +.ion-flash-off:before { content: "\f136"; } + +.ion-folder:before { content: "\f139"; } + +.ion-fork:before { content: "\f27a"; } + +.ion-fork-repo:before { content: "\f2c0"; } + +.ion-forward:before { content: "\f13a"; } + +.ion-funnel:before { content: "\f31b"; } + +.ion-gear-a:before { content: "\f13d"; } + +.ion-gear-b:before { content: "\f13e"; } + +.ion-grid:before { content: "\f13f"; } + +.ion-hammer:before { content: "\f27b"; } + +.ion-happy:before { content: "\f31c"; } + +.ion-happy-outline:before { content: "\f3c6"; } + +.ion-headphone:before { content: "\f140"; } + +.ion-heart:before { content: "\f141"; } + +.ion-heart-broken:before { content: "\f31d"; } + +.ion-help:before { content: "\f143"; } + +.ion-help-buoy:before { content: "\f27c"; } + +.ion-help-circled:before { content: "\f142"; } + +.ion-home:before { content: "\f144"; } + +.ion-icecream:before { content: "\f27d"; } + +.ion-image:before { content: "\f147"; } + +.ion-images:before { content: "\f148"; } + +.ion-information:before { content: "\f14a"; } + +.ion-information-circled:before { content: "\f149"; } + +.ion-ionic:before { content: "\f14b"; } + +.ion-ios-alarm:before { content: "\f3c8"; } + +.ion-ios-alarm-outline:before { content: "\f3c7"; } + +.ion-ios-albums:before { content: "\f3ca"; } + +.ion-ios-albums-outline:before { content: "\f3c9"; } + +.ion-ios-americanfootball:before { content: "\f3cc"; } + +.ion-ios-americanfootball-outline:before { content: "\f3cb"; } + +.ion-ios-analytics:before { content: "\f3ce"; } + +.ion-ios-analytics-outline:before { content: "\f3cd"; } + +.ion-ios-arrow-back:before { content: "\f3cf"; } + +.ion-ios-arrow-down:before { content: "\f3d0"; } + +.ion-ios-arrow-forward:before { content: "\f3d1"; } + +.ion-ios-arrow-left:before { content: "\f3d2"; } + +.ion-ios-arrow-right:before { content: "\f3d3"; } + +.ion-ios-arrow-thin-down:before { content: "\f3d4"; } + +.ion-ios-arrow-thin-left:before { content: "\f3d5"; } + +.ion-ios-arrow-thin-right:before { content: "\f3d6"; } + +.ion-ios-arrow-thin-up:before { content: "\f3d7"; } + +.ion-ios-arrow-up:before { content: "\f3d8"; } + +.ion-ios-at:before { content: "\f3da"; } + +.ion-ios-at-outline:before { content: "\f3d9"; } + +.ion-ios-barcode:before { content: "\f3dc"; } + +.ion-ios-barcode-outline:before { content: "\f3db"; } + +.ion-ios-baseball:before { content: "\f3de"; } + +.ion-ios-baseball-outline:before { content: "\f3dd"; } + +.ion-ios-basketball:before { content: "\f3e0"; } + +.ion-ios-basketball-outline:before { content: "\f3df"; } + +.ion-ios-bell:before { content: "\f3e2"; } + +.ion-ios-bell-outline:before { content: "\f3e1"; } + +.ion-ios-body:before { content: "\f3e4"; } + +.ion-ios-body-outline:before { content: "\f3e3"; } + +.ion-ios-bolt:before { content: "\f3e6"; } + +.ion-ios-bolt-outline:before { content: "\f3e5"; } + +.ion-ios-book:before { content: "\f3e8"; } + +.ion-ios-book-outline:before { content: "\f3e7"; } + +.ion-ios-bookmarks:before { content: "\f3ea"; } + +.ion-ios-bookmarks-outline:before { content: "\f3e9"; } + +.ion-ios-box:before { content: "\f3ec"; } + +.ion-ios-box-outline:before { content: "\f3eb"; } + +.ion-ios-briefcase:before { content: "\f3ee"; } + +.ion-ios-briefcase-outline:before { content: "\f3ed"; } + +.ion-ios-browsers:before { content: "\f3f0"; } + +.ion-ios-browsers-outline:before { content: "\f3ef"; } + +.ion-ios-calculator:before { content: "\f3f2"; } + +.ion-ios-calculator-outline:before { content: "\f3f1"; } + +.ion-ios-calendar:before { content: "\f3f4"; } + +.ion-ios-calendar-outline:before { content: "\f3f3"; } + +.ion-ios-camera:before { content: "\f3f6"; } + +.ion-ios-camera-outline:before { content: "\f3f5"; } + +.ion-ios-cart:before { content: "\f3f8"; } + +.ion-ios-cart-outline:before { content: "\f3f7"; } + +.ion-ios-chatboxes:before { content: "\f3fa"; } + +.ion-ios-chatboxes-outline:before { content: "\f3f9"; } + +.ion-ios-chatbubble:before { content: "\f3fc"; } + +.ion-ios-chatbubble-outline:before { content: "\f3fb"; } + +.ion-ios-checkmark:before { content: "\f3ff"; } + +.ion-ios-checkmark-empty:before { content: "\f3fd"; } + +.ion-ios-checkmark-outline:before { content: "\f3fe"; } + +.ion-ios-circle-filled:before { content: "\f400"; } + +.ion-ios-circle-outline:before { content: "\f401"; } + +.ion-ios-clock:before { content: "\f403"; } + +.ion-ios-clock-outline:before { content: "\f402"; } + +.ion-ios-close:before { content: "\f406"; } + +.ion-ios-close-empty:before { content: "\f404"; } + +.ion-ios-close-outline:before { content: "\f405"; } + +.ion-ios-cloud:before { content: "\f40c"; } + +.ion-ios-cloud-download:before { content: "\f408"; } + +.ion-ios-cloud-download-outline:before { content: "\f407"; } + +.ion-ios-cloud-outline:before { content: "\f409"; } + +.ion-ios-cloud-upload:before { content: "\f40b"; } + +.ion-ios-cloud-upload-outline:before { content: "\f40a"; } + +.ion-ios-cloudy:before { content: "\f410"; } + +.ion-ios-cloudy-night:before { content: "\f40e"; } + +.ion-ios-cloudy-night-outline:before { content: "\f40d"; } + +.ion-ios-cloudy-outline:before { content: "\f40f"; } + +.ion-ios-cog:before { content: "\f412"; } + +.ion-ios-cog-outline:before { content: "\f411"; } + +.ion-ios-color-filter:before { content: "\f414"; } + +.ion-ios-color-filter-outline:before { content: "\f413"; } + +.ion-ios-color-wand:before { content: "\f416"; } + +.ion-ios-color-wand-outline:before { content: "\f415"; } + +.ion-ios-compose:before { content: "\f418"; } + +.ion-ios-compose-outline:before { content: "\f417"; } + +.ion-ios-contact:before { content: "\f41a"; } + +.ion-ios-contact-outline:before { content: "\f419"; } + +.ion-ios-copy:before { content: "\f41c"; } + +.ion-ios-copy-outline:before { content: "\f41b"; } + +.ion-ios-crop:before { content: "\f41e"; } + +.ion-ios-crop-strong:before { content: "\f41d"; } + +.ion-ios-download:before { content: "\f420"; } + +.ion-ios-download-outline:before { content: "\f41f"; } + +.ion-ios-drag:before { content: "\f421"; } + +.ion-ios-email:before { content: "\f423"; } + +.ion-ios-email-outline:before { content: "\f422"; } + +.ion-ios-eye:before { content: "\f425"; } + +.ion-ios-eye-outline:before { content: "\f424"; } + +.ion-ios-fastforward:before { content: "\f427"; } + +.ion-ios-fastforward-outline:before { content: "\f426"; } + +.ion-ios-filing:before { content: "\f429"; } + +.ion-ios-filing-outline:before { content: "\f428"; } + +.ion-ios-film:before { content: "\f42b"; } + +.ion-ios-film-outline:before { content: "\f42a"; } + +.ion-ios-flag:before { content: "\f42d"; } + +.ion-ios-flag-outline:before { content: "\f42c"; } + +.ion-ios-flame:before { content: "\f42f"; } + +.ion-ios-flame-outline:before { content: "\f42e"; } + +.ion-ios-flask:before { content: "\f431"; } + +.ion-ios-flask-outline:before { content: "\f430"; } + +.ion-ios-flower:before { content: "\f433"; } + +.ion-ios-flower-outline:before { content: "\f432"; } + +.ion-ios-folder:before { content: "\f435"; } + +.ion-ios-folder-outline:before { content: "\f434"; } + +.ion-ios-football:before { content: "\f437"; } + +.ion-ios-football-outline:before { content: "\f436"; } + +.ion-ios-game-controller-a:before { content: "\f439"; } + +.ion-ios-game-controller-a-outline:before { content: "\f438"; } + +.ion-ios-game-controller-b:before { content: "\f43b"; } + +.ion-ios-game-controller-b-outline:before { content: "\f43a"; } + +.ion-ios-gear:before { content: "\f43d"; } + +.ion-ios-gear-outline:before { content: "\f43c"; } + +.ion-ios-glasses:before { content: "\f43f"; } + +.ion-ios-glasses-outline:before { content: "\f43e"; } + +.ion-ios-grid-view:before { content: "\f441"; } + +.ion-ios-grid-view-outline:before { content: "\f440"; } + +.ion-ios-heart:before { content: "\f443"; } + +.ion-ios-heart-outline:before { content: "\f442"; } + +.ion-ios-help:before { content: "\f446"; } + +.ion-ios-help-empty:before { content: "\f444"; } + +.ion-ios-help-outline:before { content: "\f445"; } + +.ion-ios-home:before { content: "\f448"; } + +.ion-ios-home-outline:before { content: "\f447"; } + +.ion-ios-infinite:before { content: "\f44a"; } + +.ion-ios-infinite-outline:before { content: "\f449"; } + +.ion-ios-information:before { content: "\f44d"; } + +.ion-ios-information-empty:before { content: "\f44b"; } + +.ion-ios-information-outline:before { content: "\f44c"; } + +.ion-ios-ionic-outline:before { content: "\f44e"; } + +.ion-ios-keypad:before { content: "\f450"; } + +.ion-ios-keypad-outline:before { content: "\f44f"; } + +.ion-ios-lightbulb:before { content: "\f452"; } + +.ion-ios-lightbulb-outline:before { content: "\f451"; } + +.ion-ios-list:before { content: "\f454"; } + +.ion-ios-list-outline:before { content: "\f453"; } + +.ion-ios-location:before { content: "\f456"; } + +.ion-ios-location-outline:before { content: "\f455"; } + +.ion-ios-locked:before { content: "\f458"; } + +.ion-ios-locked-outline:before { content: "\f457"; } + +.ion-ios-loop:before { content: "\f45a"; } + +.ion-ios-loop-strong:before { content: "\f459"; } + +.ion-ios-medical:before { content: "\f45c"; } + +.ion-ios-medical-outline:before { content: "\f45b"; } + +.ion-ios-medkit:before { content: "\f45e"; } + +.ion-ios-medkit-outline:before { content: "\f45d"; } + +.ion-ios-mic:before { content: "\f461"; } + +.ion-ios-mic-off:before { content: "\f45f"; } + +.ion-ios-mic-outline:before { content: "\f460"; } + +.ion-ios-minus:before { content: "\f464"; } + +.ion-ios-minus-empty:before { content: "\f462"; } + +.ion-ios-minus-outline:before { content: "\f463"; } + +.ion-ios-monitor:before { content: "\f466"; } + +.ion-ios-monitor-outline:before { content: "\f465"; } + +.ion-ios-moon:before { content: "\f468"; } + +.ion-ios-moon-outline:before { content: "\f467"; } + +.ion-ios-more:before { content: "\f46a"; } + +.ion-ios-more-outline:before { content: "\f469"; } + +.ion-ios-musical-note:before { content: "\f46b"; } + +.ion-ios-musical-notes:before { content: "\f46c"; } + +.ion-ios-navigate:before { content: "\f46e"; } + +.ion-ios-navigate-outline:before { content: "\f46d"; } + +.ion-ios-nutrition:before { content: "\f470"; } + +.ion-ios-nutrition-outline:before { content: "\f46f"; } + +.ion-ios-paper:before { content: "\f472"; } + +.ion-ios-paper-outline:before { content: "\f471"; } + +.ion-ios-paperplane:before { content: "\f474"; } + +.ion-ios-paperplane-outline:before { content: "\f473"; } + +.ion-ios-partlysunny:before { content: "\f476"; } + +.ion-ios-partlysunny-outline:before { content: "\f475"; } + +.ion-ios-pause:before { content: "\f478"; } + +.ion-ios-pause-outline:before { content: "\f477"; } + +.ion-ios-paw:before { content: "\f47a"; } + +.ion-ios-paw-outline:before { content: "\f479"; } + +.ion-ios-people:before { content: "\f47c"; } + +.ion-ios-people-outline:before { content: "\f47b"; } + +.ion-ios-person:before { content: "\f47e"; } + +.ion-ios-person-outline:before { content: "\f47d"; } + +.ion-ios-personadd:before { content: "\f480"; } + +.ion-ios-personadd-outline:before { content: "\f47f"; } + +.ion-ios-photos:before { content: "\f482"; } + +.ion-ios-photos-outline:before { content: "\f481"; } + +.ion-ios-pie:before { content: "\f484"; } + +.ion-ios-pie-outline:before { content: "\f483"; } + +.ion-ios-pint:before { content: "\f486"; } + +.ion-ios-pint-outline:before { content: "\f485"; } + +.ion-ios-play:before { content: "\f488"; } + +.ion-ios-play-outline:before { content: "\f487"; } + +.ion-ios-plus:before { content: "\f48b"; } + +.ion-ios-plus-empty:before { content: "\f489"; } + +.ion-ios-plus-outline:before { content: "\f48a"; } + +.ion-ios-pricetag:before { content: "\f48d"; } + +.ion-ios-pricetag-outline:before { content: "\f48c"; } + +.ion-ios-pricetags:before { content: "\f48f"; } + +.ion-ios-pricetags-outline:before { content: "\f48e"; } + +.ion-ios-printer:before { content: "\f491"; } + +.ion-ios-printer-outline:before { content: "\f490"; } + +.ion-ios-pulse:before { content: "\f493"; } + +.ion-ios-pulse-strong:before { content: "\f492"; } + +.ion-ios-rainy:before { content: "\f495"; } + +.ion-ios-rainy-outline:before { content: "\f494"; } + +.ion-ios-recording:before { content: "\f497"; } + +.ion-ios-recording-outline:before { content: "\f496"; } + +.ion-ios-redo:before { content: "\f499"; } + +.ion-ios-redo-outline:before { content: "\f498"; } + +.ion-ios-refresh:before { content: "\f49c"; } + +.ion-ios-refresh-empty:before { content: "\f49a"; } + +.ion-ios-refresh-outline:before { content: "\f49b"; } + +.ion-ios-reload:before { content: "\f49d"; } + +.ion-ios-reverse-camera:before { content: "\f49f"; } + +.ion-ios-reverse-camera-outline:before { content: "\f49e"; } + +.ion-ios-rewind:before { content: "\f4a1"; } + +.ion-ios-rewind-outline:before { content: "\f4a0"; } + +.ion-ios-rose:before { content: "\f4a3"; } + +.ion-ios-rose-outline:before { content: "\f4a2"; } + +.ion-ios-search:before { content: "\f4a5"; } + +.ion-ios-search-strong:before { content: "\f4a4"; } + +.ion-ios-settings:before { content: "\f4a7"; } + +.ion-ios-settings-strong:before { content: "\f4a6"; } + +.ion-ios-shuffle:before { content: "\f4a9"; } + +.ion-ios-shuffle-strong:before { content: "\f4a8"; } + +.ion-ios-skipbackward:before { content: "\f4ab"; } + +.ion-ios-skipbackward-outline:before { content: "\f4aa"; } + +.ion-ios-skipforward:before { content: "\f4ad"; } + +.ion-ios-skipforward-outline:before { content: "\f4ac"; } + +.ion-ios-snowy:before { content: "\f4ae"; } + +.ion-ios-speedometer:before { content: "\f4b0"; } + +.ion-ios-speedometer-outline:before { content: "\f4af"; } + +.ion-ios-star:before { content: "\f4b3"; } + +.ion-ios-star-half:before { content: "\f4b1"; } + +.ion-ios-star-outline:before { content: "\f4b2"; } + +.ion-ios-stopwatch:before { content: "\f4b5"; } + +.ion-ios-stopwatch-outline:before { content: "\f4b4"; } + +.ion-ios-sunny:before { content: "\f4b7"; } + +.ion-ios-sunny-outline:before { content: "\f4b6"; } + +.ion-ios-telephone:before { content: "\f4b9"; } + +.ion-ios-telephone-outline:before { content: "\f4b8"; } + +.ion-ios-tennisball:before { content: "\f4bb"; } + +.ion-ios-tennisball-outline:before { content: "\f4ba"; } + +.ion-ios-thunderstorm:before { content: "\f4bd"; } + +.ion-ios-thunderstorm-outline:before { content: "\f4bc"; } + +.ion-ios-time:before { content: "\f4bf"; } + +.ion-ios-time-outline:before { content: "\f4be"; } + +.ion-ios-timer:before { content: "\f4c1"; } + +.ion-ios-timer-outline:before { content: "\f4c0"; } + +.ion-ios-toggle:before { content: "\f4c3"; } + +.ion-ios-toggle-outline:before { content: "\f4c2"; } + +.ion-ios-trash:before { content: "\f4c5"; } + +.ion-ios-trash-outline:before { content: "\f4c4"; } + +.ion-ios-undo:before { content: "\f4c7"; } + +.ion-ios-undo-outline:before { content: "\f4c6"; } + +.ion-ios-unlocked:before { content: "\f4c9"; } + +.ion-ios-unlocked-outline:before { content: "\f4c8"; } + +.ion-ios-upload:before { content: "\f4cb"; } + +.ion-ios-upload-outline:before { content: "\f4ca"; } + +.ion-ios-videocam:before { content: "\f4cd"; } + +.ion-ios-videocam-outline:before { content: "\f4cc"; } + +.ion-ios-volume-high:before { content: "\f4ce"; } + +.ion-ios-volume-low:before { content: "\f4cf"; } + +.ion-ios-wineglass:before { content: "\f4d1"; } + +.ion-ios-wineglass-outline:before { content: "\f4d0"; } + +.ion-ios-world:before { content: "\f4d3"; } + +.ion-ios-world-outline:before { content: "\f4d2"; } + +.ion-ipad:before { content: "\f1f9"; } + +.ion-iphone:before { content: "\f1fa"; } + +.ion-ipod:before { content: "\f1fb"; } + +.ion-jet:before { content: "\f295"; } + +.ion-key:before { content: "\f296"; } + +.ion-knife:before { content: "\f297"; } + +.ion-laptop:before { content: "\f1fc"; } + +.ion-leaf:before { content: "\f1fd"; } + +.ion-levels:before { content: "\f298"; } + +.ion-lightbulb:before { content: "\f299"; } + +.ion-link:before { content: "\f1fe"; } + +.ion-load-a:before { content: "\f29a"; } + +.ion-load-b:before { content: "\f29b"; } + +.ion-load-c:before { content: "\f29c"; } + +.ion-load-d:before { content: "\f29d"; } + +.ion-location:before { content: "\f1ff"; } + +.ion-lock-combination:before { content: "\f4d4"; } + +.ion-locked:before { content: "\f200"; } + +.ion-log-in:before { content: "\f29e"; } + +.ion-log-out:before { content: "\f29f"; } + +.ion-loop:before { content: "\f201"; } + +.ion-magnet:before { content: "\f2a0"; } + +.ion-male:before { content: "\f2a1"; } + +.ion-man:before { content: "\f202"; } + +.ion-map:before { content: "\f203"; } + +.ion-medkit:before { content: "\f2a2"; } + +.ion-merge:before { content: "\f33f"; } + +.ion-mic-a:before { content: "\f204"; } + +.ion-mic-b:before { content: "\f205"; } + +.ion-mic-c:before { content: "\f206"; } + +.ion-minus:before { content: "\f209"; } + +.ion-minus-circled:before { content: "\f207"; } + +.ion-minus-round:before { content: "\f208"; } + +.ion-model-s:before { content: "\f2c1"; } + +.ion-monitor:before { content: "\f20a"; } + +.ion-more:before { content: "\f20b"; } + +.ion-mouse:before { content: "\f340"; } + +.ion-music-note:before { content: "\f20c"; } + +.ion-navicon:before { content: "\f20e"; } + +.ion-navicon-round:before { content: "\f20d"; } + +.ion-navigate:before { content: "\f2a3"; } + +.ion-network:before { content: "\f341"; } + +.ion-no-smoking:before { content: "\f2c2"; } + +.ion-nuclear:before { content: "\f2a4"; } + +.ion-outlet:before { content: "\f342"; } + +.ion-paintbrush:before { content: "\f4d5"; } + +.ion-paintbucket:before { content: "\f4d6"; } + +.ion-paper-airplane:before { content: "\f2c3"; } + +.ion-paperclip:before { content: "\f20f"; } + +.ion-pause:before { content: "\f210"; } + +.ion-person:before { content: "\f213"; } + +.ion-person-add:before { content: "\f211"; } + +.ion-person-stalker:before { content: "\f212"; } + +.ion-pie-graph:before { content: "\f2a5"; } + +.ion-pin:before { content: "\f2a6"; } + +.ion-pinpoint:before { content: "\f2a7"; } + +.ion-pizza:before { content: "\f2a8"; } + +.ion-plane:before { content: "\f214"; } + +.ion-planet:before { content: "\f343"; } + +.ion-play:before { content: "\f215"; } + +.ion-playstation:before { content: "\f30a"; } + +.ion-plus:before { content: "\f218"; } + +.ion-plus-circled:before { content: "\f216"; } + +.ion-plus-round:before { content: "\f217"; } + +.ion-podium:before { content: "\f344"; } + +.ion-pound:before { content: "\f219"; } + +.ion-power:before { content: "\f2a9"; } + +.ion-pricetag:before { content: "\f2aa"; } + +.ion-pricetags:before { content: "\f2ab"; } + +.ion-printer:before { content: "\f21a"; } + +.ion-pull-request:before { content: "\f345"; } + +.ion-qr-scanner:before { content: "\f346"; } + +.ion-quote:before { content: "\f347"; } + +.ion-radio-waves:before { content: "\f2ac"; } + +.ion-record:before { content: "\f21b"; } + +.ion-refresh:before { content: "\f21c"; } + +.ion-reply:before { content: "\f21e"; } + +.ion-reply-all:before { content: "\f21d"; } + +.ion-ribbon-a:before { content: "\f348"; } + +.ion-ribbon-b:before { content: "\f349"; } + +.ion-sad:before { content: "\f34a"; } + +.ion-sad-outline:before { content: "\f4d7"; } + +.ion-scissors:before { content: "\f34b"; } + +.ion-search:before { content: "\f21f"; } + +.ion-settings:before { content: "\f2ad"; } + +.ion-share:before { content: "\f220"; } + +.ion-shuffle:before { content: "\f221"; } + +.ion-skip-backward:before { content: "\f222"; } + +.ion-skip-forward:before { content: "\f223"; } + +.ion-social-android:before { content: "\f225"; } + +.ion-social-android-outline:before { content: "\f224"; } + +.ion-social-angular:before { content: "\f4d9"; } + +.ion-social-angular-outline:before { content: "\f4d8"; } + +.ion-social-apple:before { content: "\f227"; } + +.ion-social-apple-outline:before { content: "\f226"; } + +.ion-social-bitcoin:before { content: "\f2af"; } + +.ion-social-bitcoin-outline:before { content: "\f2ae"; } + +.ion-social-buffer:before { content: "\f229"; } + +.ion-social-buffer-outline:before { content: "\f228"; } + +.ion-social-chrome:before { content: "\f4db"; } + +.ion-social-chrome-outline:before { content: "\f4da"; } + +.ion-social-codepen:before { content: "\f4dd"; } + +.ion-social-codepen-outline:before { content: "\f4dc"; } + +.ion-social-css3:before { content: "\f4df"; } + +.ion-social-css3-outline:before { content: "\f4de"; } + +.ion-social-designernews:before { content: "\f22b"; } + +.ion-social-designernews-outline:before { content: "\f22a"; } + +.ion-social-dribbble:before { content: "\f22d"; } + +.ion-social-dribbble-outline:before { content: "\f22c"; } + +.ion-social-dropbox:before { content: "\f22f"; } + +.ion-social-dropbox-outline:before { content: "\f22e"; } + +.ion-social-euro:before { content: "\f4e1"; } + +.ion-social-euro-outline:before { content: "\f4e0"; } + +.ion-social-facebook:before { content: "\f231"; } + +.ion-social-facebook-outline:before { content: "\f230"; } + +.ion-social-foursquare:before { content: "\f34d"; } + +.ion-social-foursquare-outline:before { content: "\f34c"; } + +.ion-social-freebsd-devil:before { content: "\f2c4"; } + +.ion-social-github:before { content: "\f233"; } + +.ion-social-github-outline:before { content: "\f232"; } + +.ion-social-google:before { content: "\f34f"; } + +.ion-social-google-outline:before { content: "\f34e"; } + +.ion-social-googleplus:before { content: "\f235"; } + +.ion-social-googleplus-outline:before { content: "\f234"; } + +.ion-social-hackernews:before { content: "\f237"; } + +.ion-social-hackernews-outline:before { content: "\f236"; } + +.ion-social-html5:before { content: "\f4e3"; } + +.ion-social-html5-outline:before { content: "\f4e2"; } + +.ion-social-instagram:before { content: "\f351"; } + +.ion-social-instagram-outline:before { content: "\f350"; } + +.ion-social-javascript:before { content: "\f4e5"; } + +.ion-social-javascript-outline:before { content: "\f4e4"; } + +.ion-social-linkedin:before { content: "\f239"; } + +.ion-social-linkedin-outline:before { content: "\f238"; } + +.ion-social-markdown:before { content: "\f4e6"; } + +.ion-social-nodejs:before { content: "\f4e7"; } + +.ion-social-octocat:before { content: "\f4e8"; } + +.ion-social-pinterest:before { content: "\f2b1"; } + +.ion-social-pinterest-outline:before { content: "\f2b0"; } + +.ion-social-python:before { content: "\f4e9"; } + +.ion-social-reddit:before { content: "\f23b"; } + +.ion-social-reddit-outline:before { content: "\f23a"; } + +.ion-social-rss:before { content: "\f23d"; } + +.ion-social-rss-outline:before { content: "\f23c"; } + +.ion-social-sass:before { content: "\f4ea"; } + +.ion-social-skype:before { content: "\f23f"; } + +.ion-social-skype-outline:before { content: "\f23e"; } + +.ion-social-snapchat:before { content: "\f4ec"; } + +.ion-social-snapchat-outline:before { content: "\f4eb"; } + +.ion-social-tumblr:before { content: "\f241"; } + +.ion-social-tumblr-outline:before { content: "\f240"; } + +.ion-social-tux:before { content: "\f2c5"; } + +.ion-social-twitch:before { content: "\f4ee"; } + +.ion-social-twitch-outline:before { content: "\f4ed"; } + +.ion-social-twitter:before { content: "\f243"; } + +.ion-social-twitter-outline:before { content: "\f242"; } + +.ion-social-usd:before { content: "\f353"; } + +.ion-social-usd-outline:before { content: "\f352"; } + +.ion-social-vimeo:before { content: "\f245"; } + +.ion-social-vimeo-outline:before { content: "\f244"; } + +.ion-social-whatsapp:before { content: "\f4f0"; } + +.ion-social-whatsapp-outline:before { content: "\f4ef"; } + +.ion-social-windows:before { content: "\f247"; } + +.ion-social-windows-outline:before { content: "\f246"; } + +.ion-social-wordpress:before { content: "\f249"; } + +.ion-social-wordpress-outline:before { content: "\f248"; } + +.ion-social-yahoo:before { content: "\f24b"; } + +.ion-social-yahoo-outline:before { content: "\f24a"; } + +.ion-social-yen:before { content: "\f4f2"; } + +.ion-social-yen-outline:before { content: "\f4f1"; } + +.ion-social-youtube:before { content: "\f24d"; } + +.ion-social-youtube-outline:before { content: "\f24c"; } + +.ion-soup-can:before { content: "\f4f4"; } + +.ion-soup-can-outline:before { content: "\f4f3"; } + +.ion-speakerphone:before { content: "\f2b2"; } + +.ion-speedometer:before { content: "\f2b3"; } + +.ion-spoon:before { content: "\f2b4"; } + +.ion-star:before { content: "\f24e"; } + +.ion-stats-bars:before { content: "\f2b5"; } + +.ion-steam:before { content: "\f30b"; } + +.ion-stop:before { content: "\f24f"; } + +.ion-thermometer:before { content: "\f2b6"; } + +.ion-thumbsdown:before { content: "\f250"; } + +.ion-thumbsup:before { content: "\f251"; } + +.ion-toggle:before { content: "\f355"; } + +.ion-toggle-filled:before { content: "\f354"; } + +.ion-transgender:before { content: "\f4f5"; } + +.ion-trash-a:before { content: "\f252"; } + +.ion-trash-b:before { content: "\f253"; } + +.ion-trophy:before { content: "\f356"; } + +.ion-tshirt:before { content: "\f4f7"; } + +.ion-tshirt-outline:before { content: "\f4f6"; } + +.ion-umbrella:before { content: "\f2b7"; } + +.ion-university:before { content: "\f357"; } + +.ion-unlocked:before { content: "\f254"; } + +.ion-upload:before { content: "\f255"; } + +.ion-usb:before { content: "\f2b8"; } + +.ion-videocamera:before { content: "\f256"; } + +.ion-volume-high:before { content: "\f257"; } + +.ion-volume-low:before { content: "\f258"; } + +.ion-volume-medium:before { content: "\f259"; } + +.ion-volume-mute:before { content: "\f25a"; } + +.ion-wand:before { content: "\f358"; } + +.ion-waterdrop:before { content: "\f25b"; } + +.ion-wifi:before { content: "\f25c"; } + +.ion-wineglass:before { content: "\f2b9"; } + +.ion-woman:before { content: "\f25d"; } + +.ion-wrench:before { content: "\f2ba"; } + +.ion-xbox:before { content: "\f30c"; } diff --git a/styles/bootstrap/jumbotron.less b/styles/bootstrap/jumbotron.less new file mode 100644 index 0000000..22c2978 --- /dev/null +++ b/styles/bootstrap/jumbotron.less @@ -0,0 +1,40 @@ +// +// Jumbotron +// -------------------------------------------------- + + +.jumbotron { + padding: @jumbotron-padding; + margin-bottom: @jumbotron-padding; + font-size: @jumbotron-font-size; + font-weight: 200; + line-height: (@line-height-base * 1.5); + color: @jumbotron-color; + background-color: @jumbotron-bg; + + h1 { + line-height: 1; + color: @jumbotron-heading-color; + } + p { + line-height: 1.4; + } + + .container & { + border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container + } + + @media screen and (min-width: @screen-sm-min) { + padding-top: (@jumbotron-padding * 1.6); + padding-bottom: (@jumbotron-padding * 1.6); + + .container & { + padding-left: (@jumbotron-padding * 2); + padding-right: (@jumbotron-padding * 2); + } + + h1 { + font-size: (@font-size-base * 4.5); + } + } +} diff --git a/styles/bootstrap/labels.less b/styles/bootstrap/labels.less new file mode 100644 index 0000000..cad5ce5 --- /dev/null +++ b/styles/bootstrap/labels.less @@ -0,0 +1,58 @@ +// +// Labels +// -------------------------------------------------- + +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: @label-color; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; + + // Add hover effects, but only for links + &[href] { + &:hover, + &:focus { + color: @label-link-hover-color; + text-decoration: none; + cursor: pointer; + } + } + + // Empty labels collapse automatically (not available in IE8) + &:empty { + display: none; + } +} + +// Colors +// Contextual variations (linked labels get darker on :hover) + +.label-default { + .label-variant(@label-default-bg); +} + +.label-primary { + .label-variant(@label-primary-bg); +} + +.label-success { + .label-variant(@label-success-bg); +} + +.label-info { + .label-variant(@label-info-bg); +} + +.label-warning { + .label-variant(@label-warning-bg); +} + +.label-danger { + .label-variant(@label-danger-bg); +} diff --git a/styles/bootstrap/list-group.less b/styles/bootstrap/list-group.less new file mode 100644 index 0000000..2cee529 --- /dev/null +++ b/styles/bootstrap/list-group.less @@ -0,0 +1,88 @@ +// +// List groups +// -------------------------------------------------- + +// Base class +// +// Easily usable on