├── .swift-version ├── .dockerignore ├── Procfile ├── Public ├── favicon.ico ├── img │ ├── preview.png │ ├── ci-architecture.png │ ├── gi.svg │ └── gitignoreio.svg ├── components │ ├── bootstrap │ │ └── dist │ │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ └── js │ │ │ └── npm.js │ ├── select2 │ │ └── dist │ │ │ ├── js │ │ │ └── i18n │ │ │ │ ├── zh-TW.js │ │ │ │ ├── az.js │ │ │ │ ├── zh-CN.js │ │ │ │ ├── fi.js │ │ │ │ ├── ja.js │ │ │ │ ├── hu.js │ │ │ │ ├── th.js │ │ │ │ ├── tr.js │ │ │ │ ├── ko.js │ │ │ │ ├── id.js │ │ │ │ ├── vi.js │ │ │ │ ├── is.js │ │ │ │ ├── ar.js │ │ │ │ ├── de.js │ │ │ │ ├── et.js │ │ │ │ ├── km.js │ │ │ │ ├── nb.js │ │ │ │ ├── sv.js │ │ │ │ ├── bg.js │ │ │ │ ├── ms.js │ │ │ │ ├── gl.js │ │ │ │ ├── da.js │ │ │ │ ├── en.js │ │ │ │ ├── he.js │ │ │ │ ├── hi.js │ │ │ │ ├── fa.js │ │ │ │ ├── hr.js │ │ │ │ ├── eu.js │ │ │ │ ├── mk.js │ │ │ │ ├── pt-BR.js │ │ │ │ ├── lv.js │ │ │ │ ├── pt.js │ │ │ │ ├── ca.js │ │ │ │ ├── es.js │ │ │ │ ├── it.js │ │ │ │ ├── fr.js │ │ │ │ ├── nl.js │ │ │ │ ├── ro.js │ │ │ │ ├── lt.js │ │ │ │ ├── pl.js │ │ │ │ ├── el.js │ │ │ │ ├── sr.js │ │ │ │ ├── sr-Cyrl.js │ │ │ │ ├── uk.js │ │ │ │ ├── ru.js │ │ │ │ ├── sk.js │ │ │ │ └── cs.js │ │ │ └── css │ │ │ └── select2.min.css │ └── flatdoc │ │ └── v │ │ └── 0.9.0 │ │ ├── templates │ │ ├── blank.html │ │ └── template.html │ │ ├── theme-white │ │ └── script.js │ │ └── legacy.js ├── css │ ├── carbonv.css │ ├── carbonh.css │ ├── theme-gitignore-style.less │ ├── app.css │ └── app.less ├── js │ ├── app.js │ └── theme-gitignore-script.js └── README.md ├── .gitmodules ├── Sources ├── Run │ └── main.swift └── App │ ├── Models │ ├── Flags.swift │ ├── Dropdown.swift │ ├── IgnoreTemplateModeling.swift │ └── IgnoreTemplateModel.swift │ ├── Extensions │ ├── Sequence+Extensions.swift │ ├── FileManager+Extensions.swift │ ├── URL+Extensions.swift │ ├── String+Extensions.swift │ ├── Router+Extensions.swift │ └── Dictionary+Extensions.swift │ ├── Controllers │ ├── ReadOnlyTemplateManagerProtocol.swift │ └── TemplateController.swift │ ├── Enum │ └── TemplateSuffix.swift │ ├── Server.swift │ └── RouteHandlers │ ├── SiteRouteHandlers.swift │ └── APIRouteHandlers.swift ├── Dockerfile ├── docker-compose.yml ├── app.json ├── .travis ├── update-submodule.sh └── ci.sh ├── Tests ├── LinuxMain.swift └── AppTests │ ├── Controllers │ └── TemplateControllerTests.swift │ ├── Models │ └── IgnoreTemplateModelTests.swift │ ├── Extensions │ ├── URL+ExtensionsTests.swift │ ├── Sequence+ExtensionsTest.swift │ └── String+ExtensionsTests.swift │ └── RouteHandlers │ ├── SiteHandlersTests.swift │ └── APIHandlersTests.swift ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── CODE_OF_CONDUCT.md ├── Localizations ├── ar.json ├── en.json ├── pt_BR.json ├── fr_FR.json └── de_DE.json ├── LICENSE.md ├── Package.swift ├── .travis.yml ├── .gitignore ├── .swiftlint.yml ├── Resources └── Views │ ├── base.leaf │ ├── docs.leaf │ └── index.leaf ├── Package.pins ├── Package.resolved └── README.md /.swift-version: -------------------------------------------------------------------------------- 1 | 4.1 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | Packages 2 | .build 3 | 4 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: Run serve --env production --port $PORT --hostname 0.0.0.0 2 | -------------------------------------------------------------------------------- /Public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/gitignore.io/master/Public/favicon.ico -------------------------------------------------------------------------------- /Public/img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/gitignore.io/master/Public/img/preview.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gitignore"] 2 | path = gitignore 3 | url = https://github.com/dvcs/gitignore.git 4 | -------------------------------------------------------------------------------- /Sources/Run/main.swift: -------------------------------------------------------------------------------- 1 | import App 2 | 3 | let gitignore = Gitignore() 4 | try gitignore.app(.detect()).run() 5 | -------------------------------------------------------------------------------- /Public/img/ci-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/gitignore.io/master/Public/img/ci-architecture.png -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM vapor/vapor:1.0.9-xenial 2 | 3 | WORKDIR /app 4 | 5 | COPY ./ ./ 6 | 7 | RUN vapor build 8 | 9 | EXPOSE 8080 10 | 11 | # CMD vapor run 12 | 13 | -------------------------------------------------------------------------------- /Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/gitignore.io/master/Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/gitignore.io/master/Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/gitignore.io/master/Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/gitignore.io/master/Public/components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /Sources/App/Models/Flags.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Flags.swift 3 | // App 4 | // 5 | // Created by Joe Blau on 6/21/18. 6 | // 7 | 8 | import Vapor 9 | 10 | struct Flags: Content { 11 | var term: String? 12 | var format: String? 13 | } 14 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | app: 5 | image: gitignore-io:latest 6 | build: 7 | context: ./ 8 | dockerfile: Dockerfile 9 | ports: 10 | - "8080:8080" 11 | command: vapor run 12 | -------------------------------------------------------------------------------- /Sources/App/Models/Dropdown.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dropdown.swift 3 | // App 4 | // 5 | // Created by Joe Blau on 6/9/18. 6 | // 7 | 8 | import Vapor 9 | 10 | internal struct Dropdown: Content { 11 | var id: String 12 | var text: String 13 | } 14 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GitignoreIO", 3 | "scripts": {}, 4 | "env": {}, 5 | "formation": {}, 6 | "addons": [], 7 | "buildpacks": [ 8 | { 9 | "url": "https://github.com/kylef/heroku-buildpack-swift" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.travis/update-submodule.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd gitignore 4 | git pull origin master 5 | cd .. 6 | 7 | pwd 8 | if [[ `git status --porcelain` ]]; then 9 | echo "status: Updating templates" 10 | git add . 11 | git commit -m "Upading templates from https://github.com/dvcs/gitignore" 12 | git push origin master 13 | else 14 | echo "status: No updates" 15 | fi 16 | -------------------------------------------------------------------------------- /Sources/App/Extensions/Sequence+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sequence+Extensions.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joseph Blau on 1/29/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Sequence where Iterator.Element: Hashable { 12 | var uniqueElements: [Iterator.Element] { 13 | return Array( Set(self) ) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/App/Controllers/ReadOnlyTemplateManagerProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReadOnlyTemplateManagerProtocol.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joseph Blau on 1/29/17. 6 | // 7 | // 8 | 9 | internal protocol ReadOnlyTemplateManagerProtocol { 10 | var order: [String: Int] { get } 11 | var count: Int { get } 12 | var templates: [String: IgnoreTemplateModel] { get } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/App/Models/IgnoreTemplateModeling.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IgnoreTemplateModeling.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joseph Blau on 1/29/17. 6 | // 7 | // 8 | 9 | internal protocol IgnoreTemplateModeling: Codable { 10 | var key: String { get set } 11 | var name: String { get set } 12 | var fileName: String { get set } 13 | var contents: String { get set } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | #if os(Linux) 2 | 3 | import XCTest 4 | @testable import AppTests 5 | 6 | XCTMain([ 7 | testCase(TemplateControllerTests.allTests), 8 | testCase(IgnoreTemplateModelTests.allTests), 9 | testCase(String_ExtensionsTests.allTests), 10 | testCase(URL_ExtensionsTests.allTests), 11 | testCase(APIHandlersTests.allTests), 12 | testCase(SiteHandlersTests.allTests), 13 | ]) 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /Sources/App/Extensions/FileManager+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FileManager+Extensions.swift 3 | // App 4 | // 5 | // Created by Joe Blau on 6/23/18. 6 | // 7 | 8 | import Foundation 9 | 10 | extension FileManager { 11 | func templatePathsFor(_ dataDirectory: URL) -> [URL]? { 12 | return self.enumerator(at: dataDirectory, includingPropertiesForKeys: nil)? 13 | .allObjects 14 | .compactMap { (templatePath: Any) -> URL? in 15 | templatePath as? URL 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Public/components/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /Sources/App/Models/IgnoreTemplateModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IgnoreTemplateModel.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/18/16. 6 | // 7 | // 8 | 9 | import Vapor 10 | 11 | internal struct IgnoreTemplateModel: IgnoreTemplateModeling { 12 | var key: String 13 | var name: String 14 | var fileName: String 15 | var contents: String 16 | } 17 | 18 | extension IgnoreTemplateModel: CustomStringConvertible { 19 | var description: String { 20 | return "KEY: \(key)\nNAME: \(name)FILE NAME: \(fileName)\nCONTENTS: \(contents)\n" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/zh-TW.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Vision 2 | 3 | Gitignore.io's vision is to become the authoritative source for `.gitignore` templates. Gitignore provides templates for Operating Systems, IDEs and Programming Languages, but can eventually grow to encompass other creative spaces as well. 4 | 5 | ## Ways You Can Help 6 | 7 | 1. **Add Templates** - Add templates for Programming Languages, Operating Systems and IDEs at [@dvcs/gitignore](https://github.com/dvcs/gitignore) 8 | 2. **Explore** - Create better ways for users to interact with gitignore.io. 9 | 3. **Donate** - [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5J2MWBD73BQAS) to help cover server costs. 10 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/az.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/az",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return t+" simvol silin"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(e){return"Sadəcə "+e.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/fi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/ja.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" 文字を削除してください";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="少なくとも "+t+" 文字を入力してください";return n},loadingMore:function(){return"読み込み中…"},maximumSelected:function(e){var t=e.maximum+" 件しか選択できません";return t},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/hu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Sources/App/Extensions/URL+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Extensions.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joseph Blau on 1/29/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | internal extension URL { 12 | 13 | /// Name of file without extension 14 | internal var name: String { 15 | return self.deletingPathExtension().lastPathComponent 16 | } 17 | 18 | /// Name of file first component 19 | internal var stackName: String? { 20 | return self.deletingPathExtension().lastPathComponent.components(separatedBy: ".").first 21 | } 22 | 23 | /// Name of file with extension 24 | internal var fileName: String { 25 | return self.lastPathComponent 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/th.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/tr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/ko.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/id.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/vi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+' ký tự"';return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Sources/App/Extensions/String+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Extensions.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/18/16. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | internal extension String { 12 | /// Remove duplicate lines, except blank strings or comment strings 13 | /// 14 | /// - Returns: String with duplicate lines removed 15 | internal func removeDuplicateLines() -> String { 16 | return self.components(separatedBy: "\n") 17 | .reduce([String]()) { 18 | if !$1.isEmpty && !$1.hasPrefix("#") && $0.contains($1) { 19 | return $0 20 | } 21 | return $0 + [$1] 22 | } 23 | .joined(separator: "\n") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/is.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Sources/App/Enum/TemplateSuffix.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TemplateSuffix.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joseph Blau on 1/29/17. 6 | // 7 | // 8 | 9 | /// Template Suffix Enum 10 | internal enum TemplateSuffix { 11 | case template, patch, stack 12 | 13 | internal var `extension`: String { 14 | switch self { 15 | case .template: return "gitignore" 16 | case .patch: return "patch" 17 | case .stack: return "stack" 18 | } 19 | } 20 | 21 | internal func header(name: String) -> String { 22 | switch self { 23 | case .template: return "\n### \(name) ###\n" 24 | case .patch: return "\n### \(name) Patch ###\n" 25 | case .stack: return "\n### \(name) Stack ###\n" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/ar.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="الرجاء حذف "+t+" عناصر";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="الرجاء إضافة "+t+" عناصر";return n},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(e){var t="تستطيع إختيار "+e.maximum+" بنود فقط";return t},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/de.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/et.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/css/carbonv.css: -------------------------------------------------------------------------------- 1 | #carbonads { 2 | display: block; 3 | overflow: hidden; 4 | padding: 1em; 5 | background-color: #ffffff; 6 | border: solid 1px #cccccc; 7 | border-radius: 3px; 8 | font-size: 13px; 9 | line-height: 1.5; 10 | max-width: 360px; 11 | } 12 | 13 | #carbonads a {} 14 | 15 | #carbonads a:hover { 16 | color: inherit; 17 | } 18 | 19 | #carbonads span { 20 | display: block; 21 | overflow: hidden; 22 | } 23 | 24 | .carbon-img { 25 | display: block; 26 | margin: 0 auto 1em; 27 | text-align: center; 28 | } 29 | 30 | .carbon-text { 31 | display: block; 32 | margin-bottom: 1em; 33 | text-align: left; 34 | } 35 | 36 | .carbon-poweredby { 37 | position: absolute; 38 | right: 0; 39 | bottom: 0; 40 | display: block; 41 | font-size: 12px; 42 | } 43 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/km.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="សូមលុបចេញ "+t+" អក្សរ";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="សូមបញ្ចូល"+t+" អក្សរ រឺ ច្រើនជាងនេះ";return n},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(e){var t="អ្នកអាចជ្រើសរើសបានតែ "+e.maximum+" ជម្រើសប៉ុណ្ណោះ";return t},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/nb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn ";return t>1?n+=" flere tegn":n+=" tegn til",n},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/sv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Tests/AppTests/Controllers/TemplateControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TemplateControllerTests.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/22/16. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Vapor 11 | 12 | import Foundation 13 | 14 | @testable import App 15 | 16 | class TemplateControllerTests: XCTestCase { 17 | 18 | static let allTests = [ 19 | ("testIncorrectDataDirectory", testIncorrectDataDirectory), 20 | ] 21 | 22 | func testIncorrectDataDirectory() { 23 | let rootDirectory = URL(fileURLWithPath: "") 24 | let noFile = URL(fileURLWithPath: "") 25 | let templateController = TemplateController(dataDirectory: rootDirectory, orderFile: noFile) 26 | XCTAssertEqual(templateController.order.count , 0) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/bg.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bg",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Моля въведете с "+t+" по-малко символ";return t>1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/ms.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Sila hapuskan "+t+" aksara"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Sila masukkan "+t+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(e){return"Anda hanya boleh memilih "+e.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/gl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Elimine ";return t===1?n+="un carácter":n+=t+" caracteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Engada ";return t===1?n+="un carácter":n+=t+" caracteres",n},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){var t="Só pode ";return e.maximum===1?t+="un elemento":t+=e.maximum+" elementos",t},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/flatdoc/v/0.9.0/templates/blank.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/da.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Angiv venligst "+t+" tegn mindre";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Angiv venligst "+t+" tegn mere";return n},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/en.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Sources/App/Extensions/Router+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Router+Extensions.swift 3 | // App 4 | // 5 | // Created by Joe Blau on 7/2/18. 6 | // 7 | 8 | import Vapor 9 | 10 | extension Request { 11 | var acceptLanguage: String { 12 | get { 13 | guard let accpetLanguage = self.http 14 | .headers 15 | .firstValue(name: .acceptLanguage)? 16 | .split(separator: ",") 17 | .first else { 18 | return "en" 19 | } 20 | switch accpetLanguage { 21 | case "en-US", "en-us": return "en" 22 | case "de-DE", "de-de": return "de_DE" 23 | case "pt-BR", "pt-br": return "pt_BR" 24 | case "ar": return "ar" 25 | default: return "en" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/he.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק ";return t===1?n+="תו אחד":n+=t+" תווים",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס ";return t===1?n+="תו אחד":n+=t+" תווים",n+=" או יותר",n},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור עד ";return e.maximum===1?t+="פריט אחד":t+=e.maximum+" פריטים",t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/hi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/fa.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها می‌توانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجه‌ای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/hr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/eu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/mk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/pt-BR.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/lv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/pt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"carácter",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/ca.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/es.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"La carga falló"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/css/carbonh.css: -------------------------------------------------------------------------------- 1 | #carbonads { 2 | display: block; 3 | overflow: hidden; 4 | padding: 1em; 5 | background-color: #ffffff; 6 | border: solid 1px #cccccc; 7 | border-radius: 3px; 8 | font-size: 13px; 9 | line-height: 1.5; 10 | max-width: 360px; 11 | } 12 | 13 | #carbonads a {} 14 | 15 | #carbonads a:hover { 16 | color: inherit; 17 | } 18 | 19 | #carbonads span { 20 | position: relative; 21 | display: block; 22 | overflow: hidden; 23 | } 24 | 25 | .carbon-img { 26 | float: left; 27 | margin-right: 1em; 28 | } 29 | 30 | .carbon-img img { 31 | display: block; 32 | } 33 | 34 | .carbon-text { 35 | display: block; 36 | float: left; 37 | max-width: calc(100% - 130px - 1em); 38 | text-align: left; 39 | } 40 | 41 | .carbon-poweredby { 42 | position: absolute; 43 | right: 0; 44 | bottom: 0; 45 | display: block; 46 | font-size: 12px; 47 | } 48 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/it.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/fr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/nl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t=e.maximum==1?"kan":"kunnen",n="Er "+t+" maar "+e.maximum+" item";return e.maximum!=1&&(n+="s"),n+=" worden geselecteerd",n},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/ro.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return t!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți "+t+"sau mai multe caractere";return n},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",e.maximum!==1&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/lt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%10===1&&(e%100<11||e%100>19)?t:e%10>=2&&e%10<=9&&(e%100<11||e%100>19)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"į","ius","ių"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"į","ius","ių"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ą","us","ų"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Tests/AppTests/Models/IgnoreTemplateModelTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IgnoreTemplateModelTests.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/21/16. 6 | // 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import App 12 | 13 | class IgnoreTemplateModelTests: XCTestCase { 14 | static let allTests = [ 15 | ("testDescription", testDescription), 16 | ("testJSON", testJSON), 17 | ] 18 | 19 | func testDescription() { 20 | let item = IgnoreTemplateModel(key: "a", name: "b", fileName: "c", contents: "d") 21 | XCTAssertEqual("\(item)", "KEY: a\nNAME: bFILE NAME: c\nCONTENTS: d\n") 22 | } 23 | 24 | func testJSON() { 25 | let item = IgnoreTemplateModel(key: "a", name: "b", fileName: "c", contents: "d") 26 | XCTAssertEqual(item.name, "b") 27 | XCTAssertEqual(item.fileName, "c") 28 | XCTAssertEqual(item.contents, "d") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/pl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maximum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Localizations/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "إنشاء ملفات .gitignore مفيدة لمشروعك - gitignore.io", 3 | "description": "Create useful .gitignore files for your project by selecting from %{templateCount} Operating System, IDE, and Programming Language .gitignore templates", 4 | "subtitle": "إنشاء ملفات .gitignore مفيدة لمشروعك", 5 | "searchPlaceholder": "ابحث عن أنظمة تشغيل، IDEs، أو لغات برمجة", 6 | "searchGo": "إنشاء", 7 | "searchDownload": "تحميل ملف", 8 | "footer": "قوالب نظام تشغيل، IDE، ولغة برمجة لملف .gitignore %{templateCount}", 9 | "commandLineTitle": "توثيق سطر اﻷوامر", 10 | "commandLineDescription": "تعلم كيفية تشغيل .gitignore.io من سطر اﻷوامر", 11 | "videoTitle": "مشاهدة مقطع فيديو تعليمي", 12 | "videoDescription": "مشاهدة فيديو تعليمي حول كيفية عمل .gitignore.io", 13 | "sourceCodeTitle": "شفرة مصدرية", 14 | "sourceCodeDescription": "الشفرة المصدرية لـ.gitignore.io مستضافة على GitHub" 15 | } 16 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/el.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Παρακαλώ διαγράψτε "+t+" χαρακτήρ";return t==1&&(n+="α"),t!=1&&(n+="ες"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Παρακαλώ συμπληρώστε "+t+" ή περισσότερους χαρακτήρες";return n},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(e){var t="Μπορείτε να επιλέξετε μόνο "+e.maximum+" επιλογ";return e.maximum==1&&(t+="ή"),e.maximum!=1&&(t+="ές"),t},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/sr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/sr-Cyrl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr-Cyrl",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Обришите "+n+" симбол";return r+=e(n,"","а","а"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Укуцајте бар још "+n+" симбол";return r+=e(n,"","а","а"),r},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(t){var n="Можете изабрати само "+t.maximum+" ставк";return n+=e(t.maximum,"у","е","и"),n},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/uk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/ru.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Localizations/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "gitignore.io - Create Useful .gitignore Files For Your Project", 3 | "description": "Create useful .gitignore files for your project by selecting from %{templateCount} Operating System, IDE, and Programming Language .gitignore templates", 4 | "subtitle": "Create useful .gitignore files for your project", 5 | "searchPlaceholder": "Search Operating Systems, IDEs, or Programming Languages", 6 | "searchGo": "Create", 7 | "searchDownload": "Download File", 8 | "footer": "%{templateCount} Operating System, IDE, and Programming Language .gitignore templates", 9 | "commandLineTitle": "Command Line Docs", 10 | "commandLineDescription": "Learn how to run .gitignore.io from the command line", 11 | "videoTitle": "Watch Video Tutorial", 12 | "videoDescription": "Watch a video to learn how .gitignore.io works", 13 | "sourceCodeTitle": "Source Code", 14 | "sourceCodeDescription": "GitHub hosted source code for .gitignore.io" 15 | } 16 | -------------------------------------------------------------------------------- /Localizations/pt_BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "gitignore.io - Crie Arquivos .gitignore Úteis Para Seu Projeto.", 3 | "description": "Crie arquivos .gitignore úteis para o seu projeto selecionando os %{templateCount} templates de Sistemas Operacionais, IDEs e linguagens de Programação.", 4 | "subtitle": "Crie arquivos .gitignore úteis para o seu projeto.", 5 | "searchPlaceholder": "Pesquise Sistemas Operacionais, IDEs ou Linguagens de Programação.", 6 | "searchGo": "Criar", 7 | "searchDownload": "Baixar Arquivo", 8 | "footer": "%{templateCount} Templates de .gitignore de Sistemas Operacionais, IDEs e Linguagens de Programação.", 9 | "commandLineTitle": "Documentação", 10 | "commandLineDescription": "Saiba como executar o .gitignore.io a partir da Linha de Comando", 11 | "videoTitle": "Assista ao Vídeo Tutorial", 12 | "videoDescription": "Assista a um vídeo para aprender como funciona o .gitignore.io", 13 | "sourceCodeTitle": "Código-fonte", 14 | "sourceCodeDescription": "Código-fonte hospedado no GitHub" 15 | } 16 | -------------------------------------------------------------------------------- /Localizations/fr_FR.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "gitignore.io - Créez des fichiers .gitignore utiles à votre Projet", 3 | "description": "Créez des fichiers .gitignore utiles à votre projet en choisissant l'un des %{templateCount} templates .gitignore.io de Système d'exploitation, IDE et Langage de Programmation", 4 | "subtitle": "Créez des fichiers .gitignore utiles à votre projet", 5 | "searchPlaceholder": "Recherchez des Systèmes d'Exploitation, IDEs ou Langages de Programmation", 6 | "searchGo": "Créer", 7 | "searchDownload": "Téléchargement du fichier", 8 | "footer": "%{templateCount} templates .gitignore.io de Système d'exploitation, IDE et Langage de Programmation", 9 | "commandLineTitle": "Documentation", 10 | "commandLineDescription": "Apprenez comment utiliser .gitignore.io en ligne de commande", 11 | "videoTitle": "Regardez une Vidéo Didacticielle", 12 | "videoDescription": "Regardez une vidéo pour apprendre comment fonctionne .gitignore.io", 13 | "sourceCodeTitle": "Code Source", 14 | "sourceCodeDescription": "Le code source de .gitignore.io est hébergé par GitHub" 15 | } 16 | -------------------------------------------------------------------------------- /Localizations/de_DE.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "gitignore.io - Erstelle nützliche .gitignore Dateien Für Dein Projekt", 3 | "description": "Erstelle nützliche .gitignore Dateien für dein Projekt in dem du eines von {templateCount} Betriebssystem, Entwicklungsumgebung und Programmiersprache .gitignore Templates wählst", 4 | "subtitle": "Erstelle nützliche .gitignore Dateien für dein Projekt", 5 | "searchPlaceholder": "Suche nach Betriebssystemen, Entwicklungsumgebungen oder Programmiersprachen", 6 | "searchGo": "Create", 7 | "searchDownload": "Datei herunterladen", 8 | "footer": "%{templateCount} Betriebssystem, Entwicklungsumgebung und Programmiersprache .gitignore Templates", 9 | "commandLineTitle": "Kommandozeilen Dokumentation", 10 | "commandLineDescription": "Lerne wie man .gitignore.io von der Kommandozeile ausführt", 11 | "videoTitle": "Schau das Video Tutorial", 12 | "videoDescription": "Schau ein Video um zu lernen wie .gitignore.io funktioniert", 13 | "sourceCodeTitle": "Quellcode", 14 | "sourceCodeDescription": "Der Quellcode für .gitignore.io ist bei Github gehosted" 15 | } 16 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "GitignoreIO", 6 | dependencies: [ 7 | .package( 8 | url: "https://github.com/vapor/vapor.git", 9 | from: "3.1.0" 10 | ), 11 | .package( 12 | url: "https://github.com/vapor/leaf.git", 13 | from: "3.0.0" 14 | ), 15 | .package( 16 | url: "https://github.com/vapor-community/lingo-vapor.git", 17 | from: "3.0.0" 18 | ) 19 | ], 20 | targets: [ 21 | .target( 22 | name: "App", 23 | dependencies: ["Vapor", "Leaf", "LingoVapor"], 24 | exclude: ["Config", "Localization", "Public", "Resources", "data", "wiki"] 25 | ), 26 | .target( 27 | name: "Run", 28 | dependencies: ["App"], 29 | exclude: ["Config", "Localization", "Public", "Resources", "data", "wiki"] 30 | ), 31 | .testTarget( 32 | name: "AppTests", 33 | dependencies: ["App"] 34 | ) 35 | ] 36 | ) 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/sk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Public/components/select2/dist/js/i18n/cs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím zadejte o jeden znak méně":n<=4?"Prosím zadejte o "+e(n,!0)+" znaky méně":"Prosím zadejte o "+n+" znaků méně"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím zadejte ještě jeden znak":n<=4?"Prosím zadejte ještě další "+e(n,!0)+" znaky":"Prosím zadejte ještě dalších "+n+" znaků"},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky":"Můžete zvolit maximálně "+n+" položek"},noResults:function(){return"Nenalezeny žádné položky"},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /Tests/AppTests/Extensions/URL+ExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+ExtensionsTests.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joseph Blau on 2/12/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Vapor 11 | 12 | @testable import App 13 | 14 | class URL_ExtensionsTests: XCTestCase { 15 | 16 | static let allTests = [ 17 | ("testName", testName), 18 | ("testStackName", testStackName), 19 | ("testFileName", testFileName) 20 | ] 21 | 22 | 23 | func testName() { 24 | guard let mockURL = URL(string: "file://this/is/a/test/file.txt") else { 25 | XCTFail() 26 | return 27 | } 28 | XCTAssertEqual(mockURL.name, "file") 29 | } 30 | 31 | func testStackName() { 32 | guard let mockURL = URL(string: "file://this/is/a/test/file.txt") else { 33 | XCTFail() 34 | return 35 | } 36 | XCTAssertEqual(mockURL.stackName, "file") 37 | } 38 | 39 | func testFileName() { 40 | guard let mockURL = URL(string: "file://this/is/a/test/file.txt") else { 41 | XCTFail() 42 | return 43 | } 44 | XCTAssertEqual(mockURL.fileName, "file.txt") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Tests/AppTests/Extensions/Sequence+ExtensionsTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sequence+ExtensionsTest.swift 3 | // AppTests 4 | // 5 | // Created by Joe Blau on 6/22/18. 6 | // 7 | 8 | import XCTest 9 | 10 | @testable import App 11 | 12 | class Sequence_ExtensionsTest: XCTestCase { 13 | 14 | static let allTests = [ 15 | ("testUniqueElements_numbers", testUniqueElements_numbers), 16 | ("testUniqueElements_strings", testUniqueElements_strings), 17 | ("testUniqueElements_emoji", testUniqueElements_emoji) 18 | ] 19 | 20 | func testUniqueElements_numbers() { 21 | let sequenceOfDuplciates = [1,2,3,3,4,5,6,1] 22 | let sequenceOfUniques = sequenceOfDuplciates.uniqueElements 23 | XCTAssertEqual(sequenceOfUniques.count, 6) 24 | } 25 | 26 | func testUniqueElements_strings() { 27 | let sequenceOfDuplciates = ["abc","def","hij","abc","abc","xyz","abc","def"] 28 | let sequenceOfUniques = sequenceOfDuplciates.uniqueElements 29 | XCTAssertEqual(sequenceOfUniques.count, 4) 30 | } 31 | 32 | func testUniqueElements_emoji() { 33 | let sequenceOfDuplciates = ["😂","😃","☺️","😂","😅","😘","😅"] 34 | let sequenceOfUniques = sequenceOfDuplciates.uniqueElements 35 | XCTAssertEqual(sequenceOfUniques.count, 5) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: osx 2 | language: generic 3 | sudo: required 4 | osx_image: xcode9.4 5 | before_script: 6 | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-darwin-amd64 > ./cc-test-reporter 7 | - chmod +x ./cc-test-reporter 8 | - ./cc-test-reporter before-build 9 | before_install: 10 | - git config credential.helper "store --file=.git/credentials" 11 | - echo "https://${GH_TOKEN}:@github.com" > .git/credentials 12 | - .travis/update-submodule.sh 13 | install: 14 | - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" 15 | script: 16 | - brew install vapor/tap/vapor 17 | - swift build 18 | - swift test 19 | after_script: 20 | - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT 21 | notifications: 22 | email: 23 | recipients: 24 | - josephblau@gmail.com 25 | deploy: 26 | provider: heroku 27 | strategy: git 28 | app: gitignoreio-stage-swift 29 | on: master 30 | api_key: 31 | secure: In+pMxDoWCe5h2oCi20pCpLGLdiqvP1SuWqTkFm1G1LPtZ7LIcIbxlCgiWGlWqaPnwC5n0VkpOEkOSnFZz2E7ffKQuzonvEBUPl5EFLzfJxeHUDWaaMGWfadx2kR21cx/wTyEZseSqeBm77wbKJKU7D6RqRbCS+MxaavQhaJnKk= 32 | env: 33 | global: 34 | - CC_TEST_REPORTER_ID=6133dfb857104f811740c22973bcb412866eba231509f7f8f60a8ad95005ee2b 35 | - secure: ZubW/TIAZCjYPJYI1mwUtWhY9iAabIQzyeexKGEbcbUuYhdCzZ2Dj7mIjPyOQ0KPwQm3nwWPRXq8V7YnGJMU3ytofu/PTb0gYDGPguVpLj0k7hN3xlxuODQeP2BtiS4uzuXspMfOb14kEkszFqU0qlF/eKnKBtqvva//Iwi2L3I= 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Issue Template 2 | 3 | ## Frequently Asked Questions 4 | 5 | 6 | **Q:** How do I submit a new .gitignore templates? 7 | **A:** Please submit all new templates to [@dvcs/gitignore](https://github.com/dvcs/gitignore). 8 | 9 | **Q:** How do I suggest modifications to existing `.gitignore` templates? 10 | **A:** Modifictions should come in the form of pull requests at [@dvcs/gitignore](https://github.com/dvcs/gitignore). 11 | 12 | **Q:** Why don't Gitignore.io's templates don't look exactly like the templates on [@github/gitignore](https://github.com/github/gitignore)? 13 | **A:** Gitignore.io tried to maintain parity with [@github/gitignore](https://github.com/github/gitignore), but GitHub's template list doesn't include many languages, operating systems, and IDE's that developers use. Gitignore.io's template list has over 100 more templates than GitHub's. 14 | 15 | **Q:** Why is my local site empty? 16 | **A:** When the repository is cloned, the `--recursive` flag is necessary. gitignore.io uses @dvcs/gitignore as it's data source. If the repo isn't cloned recursively, templates will be missing. 17 | 18 | ## Issue 19 | 20 | ### Development Environment: 21 | 22 | - [ ] Machine (Local, Container, Virtual): 23 | - [ ] Operating System (Name/Version): 24 | - [ ] Web Browser (Name/Version): 25 | - [ ] Vapor Version: 26 | - [ ] Swift Version: 27 | 28 | ### Expected Behavior: 29 | 30 | ### Actual Behavior: 31 | 32 | ### Reproduction Steps: 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/macos,linux,windows,vapor 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | 28 | # Thumbnails 29 | ._* 30 | 31 | # Files that might appear in the root of a volume 32 | .DocumentRevisions-V100 33 | .fseventsd 34 | .Spotlight-V100 35 | .TemporaryItems 36 | .Trashes 37 | .VolumeIcon.icns 38 | .com.apple.timemachine.donotpresent 39 | 40 | # Directories potentially created on remote AFP share 41 | .AppleDB 42 | .AppleDesktop 43 | Network Trash Folder 44 | Temporary Items 45 | .apdisk 46 | 47 | ### Vapor ### 48 | Config/secrets 49 | 50 | ### Vapor Patch ### 51 | Packages 52 | .build 53 | xcuserdata 54 | *.xcodeproj 55 | 56 | ### Windows ### 57 | # Windows thumbnail cache files 58 | Thumbs.db 59 | ehthumbs.db 60 | ehthumbs_vista.db 61 | 62 | # Folder config file 63 | Desktop.ini 64 | 65 | # Recycle Bin used on file shares 66 | $RECYCLE.BIN/ 67 | 68 | # Windows Installer files 69 | *.cab 70 | *.msi 71 | *.msm 72 | *.msp 73 | 74 | # Windows shortcuts 75 | *.lnk 76 | 77 | .git/credentials 78 | 79 | cobertura.xml 80 | # End of https://www.gitignore.io/api/macos,linux,windows,vapor 81 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: # rule identifiers to exclude from running 2 | - colon 3 | - comma 4 | - control_statement 5 | - line_length 6 | opt_in_rules: # some rules are only opt-in 7 | - empty_count 8 | # Find all the available rules by running: 9 | # swiftlint rules 10 | included: # paths to include during linting. `--path` is ignored if present. 11 | - Sources/App 12 | - Sources/GitignoreIOServer 13 | excluded: # paths to ignore during linting. Takes precedence over `included`. 14 | 15 | # configurable rules can be customized from this configuration file 16 | # binary rules can set their severity level 17 | force_cast: warning # implicitly 18 | force_try: 19 | severity: warning # explicitly 20 | # rules that have both warning and error levels, can set just the warning level 21 | # implicitly 22 | # line_length: 110 23 | # they can set both implicitly with an array 24 | type_body_length: 25 | - 300 # warning 26 | - 400 # error 27 | # or they can set both explicitly 28 | file_length: 29 | warning: 500 30 | error: 1200 31 | # naming rules can set warnings/errors for min_length and max_length 32 | # additionally they can set excluded names 33 | type_name: 34 | min_length: 4 # only warning 35 | max_length: # warning and error 36 | warning: 40 37 | error: 50 38 | excluded: iPhone # excluded via string 39 | identifier_name: 40 | min_length: # only min_length 41 | error: 3 # only error 42 | excluded: # excluded via string array 43 | - id 44 | - URL 45 | - GlobalAPIKey 46 | reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit) 47 | cyclomatic_complexity: 48 | warning: 30 49 | error: 50 50 | function_parameter_count: 51 | warning: 7 52 | error: 11 53 | -------------------------------------------------------------------------------- /.travis/ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | VERSION="4.1" 4 | echo "Swift $VERSION Continuous Integration"; 5 | 6 | # Determine OS 7 | UNAME=`uname`; 8 | if [[ $UNAME == "Darwin" ]]; 9 | then 10 | OS="macos"; 11 | else 12 | if [[ $UNAME == "Linux" ]]; 13 | then 14 | UBUNTU_RELEASE=`lsb_release -a 2>/dev/null`; 15 | if [[ $UBUNTU_RELEASE == *"16.04"* ]]; 16 | then 17 | OS="ubuntu1604"; 18 | else 19 | OS="ubuntu1404"; 20 | fi 21 | else 22 | echo "Unsupported Operating System: $UNAME"; 23 | fi 24 | fi 25 | echo "🖥 Operating System: $OS"; 26 | 27 | if [[ $OS != "macos" ]]; 28 | then 29 | echo "📚 Installing Dependencies" 30 | sudo apt-get install -y clang libicu-dev uuid-dev 31 | 32 | echo "🐦 Installing Swift"; 33 | if [[ $OS == "ubuntu1604" ]]; 34 | then 35 | SWIFTFILE="swift-$VERSION-RELEASE-ubuntu16.04"; 36 | else 37 | SWIFTFILE="swift-$VERSION-RELEASE-ubuntu14.04"; 38 | fi 39 | wget https://swift.org/builds/swift-$VERSION-release/$OS/swift-$VERSION-RELEASE/$SWIFTFILE.tar.gz 40 | tar -zxf $SWIFTFILE.tar.gz 41 | export PATH=$PWD/$SWIFTFILE/usr/bin:"${PATH}" 42 | fi 43 | 44 | echo "📅 Version: `swift --version`"; 45 | 46 | echo "🚀 Building"; 47 | swift build 48 | if [[ $? != 0 ]]; 49 | then 50 | echo "❌ Build failed"; 51 | exit 1; 52 | fi 53 | 54 | echo "💼 Building Release"; 55 | swift build -c release 56 | if [[ $? != 0 ]]; 57 | then 58 | echo "❌ Build for release failed"; 59 | exit 1; 60 | fi 61 | 62 | echo "🔎 Testing"; 63 | 64 | swift test 65 | if [[ $? != 0 ]]; 66 | then 67 | echo "❌ Tests failed"; 68 | exit 1; 69 | fi 70 | 71 | echo "✅ Done" 72 | -------------------------------------------------------------------------------- /Public/img/gi.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gi 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Resources/Views/base.leaf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #get(title) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | #get(description) 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | #get(headerScripts) 34 | 35 | #get(bodyType) 36 | #get(body) 37 | 38 | #get(footerScripts) 39 | 40 | 41 | -------------------------------------------------------------------------------- /Tests/AppTests/Extensions/String+ExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+ExtensionsTests.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/21/16. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Foundation 11 | 12 | @testable import App 13 | 14 | class String_ExtensionsTests: XCTestCase { 15 | static let allTests = [ 16 | ("testStringName_valid", testStringName_valid), 17 | ("testStringName_empty", testStringName_empty), 18 | ("testStringFileName_valid", testStringFileName_valid), 19 | ("testStringFileName_empty", testStringFileName_empty), 20 | ("testRemoveDuplicateLines", testRemoveDuplicateLines), 21 | ] 22 | 23 | func testStringName_valid() { 24 | let path = URL(fileURLWithPath: "/User/ElonMusk/Developer/GitIgnoreIO/data/custom/tesla.gitignore") 25 | XCTAssertEqual(path.name, "tesla") 26 | } 27 | 28 | func testStringName_empty() { 29 | let path = URL(fileURLWithPath: "") 30 | XCTAssertFalse(path.name.isEmpty) 31 | } 32 | 33 | func testStringFileName_valid() { 34 | let path = URL(fileURLWithPath: "/User/ElonMusk/Developer/GitIgnoreIO/data/custom/tesla.gitignore") 35 | XCTAssertEqual(path.fileName, "tesla.gitignore") 36 | } 37 | 38 | func testStringFileName_empty() { 39 | let path = URL(fileURLWithPath: "") 40 | XCTAssertFalse(path.fileName.isEmpty) 41 | } 42 | 43 | 44 | func testRemoveDuplicateLines() { 45 | let string = "abc\n" 46 | .appending("#comment\n") 47 | .appending("\n") 48 | .appending("dup\n") 49 | .appending("\n") 50 | .appending("dup\n") 51 | .appending("xyz\n") 52 | 53 | let answer = "abc\n" 54 | .appending("#comment\n") 55 | .appending("\n") 56 | .appending("dup\n") 57 | .appending("\n") 58 | .appending("xyz\n") 59 | XCTAssertEqual(string.removeDuplicateLines(), answer) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/App/Extensions/Dictionary+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dictionary+Extensions.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joseph Blau on 1/29/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | internal extension Dictionary where Key: ExpressibleByStringLiteral, Value: IgnoreTemplateModeling { 12 | 13 | /// Append template patches to template contents 14 | /// 15 | /// - Parameter dataDirectory: The path to the data directory 16 | internal mutating func patchTemplates(dataDirectory: URL) throws { 17 | try FileManager().templatePathsFor(dataDirectory)? 18 | .filter({ (templatePath: URL) -> Bool in 19 | templatePath.pathExtension == TemplateSuffix.patch.extension 20 | }) 21 | .forEach({ (templatePath: URL) in 22 | let fileContents = try String(contentsOf: templatePath, encoding: String.Encoding.utf8) 23 | if let path = templatePath.name.lowercased() as? Key { 24 | self[path]? 25 | .contents 26 | .append(TemplateSuffix.patch.header(name: templatePath.name) + fileContents) 27 | } 28 | }) 29 | } 30 | 31 | /// Append stacks to template contents 32 | /// 33 | /// - Parameter dataDictionary: The path to the data dictionary 34 | internal mutating func stackTempaltes(dataDirectory: URL) throws { 35 | try FileManager().templatePathsFor(dataDirectory)? 36 | .filter({ (templatePath: URL) -> Bool in 37 | templatePath.pathExtension == TemplateSuffix.stack.extension 38 | }) 39 | .forEach({ (templatePath: URL) in 40 | let fileContents = try String(contentsOf: templatePath, encoding: String.Encoding.utf8) 41 | if let path = templatePath.stackName?.lowercased() as? Key { 42 | self[path]? 43 | .contents 44 | .append(TemplateSuffix.stack.header(name: templatePath.name) + fileContents) 45 | } 46 | }) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Public/components/flatdoc/v/0.9.0/templates/template.html: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Your Project 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 42 | 43 | 44 | 45 |
46 |
47 |

Your Project

48 | 52 |
53 |
54 | 55 | 56 |
57 |
58 | 59 |
60 | 63 |
64 |
65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Public/js/app.js: -------------------------------------------------------------------------------- 1 | $.ajax('/dropdown/templates.json').success(data => { 2 | $(".ignore-search").select2({ 3 | sorter(results) { 4 | const query = $('.select2-search__field').val().toLowerCase(); 5 | return results.sort((a, b) => a.text.toLowerCase().indexOf(query) - 6 | b.text.toLowerCase().indexOf(query)); 7 | }, 8 | minimumInputLength: 1, 9 | theme: "bootstrap", 10 | multiple: true, 11 | data 12 | }); 13 | 14 | const urlParams = new URLSearchParams(window.location.search); 15 | const preFilledSearchTerms = urlParams.get("templates").replace(/\s/g, "+").toLowerCase().split(","); 16 | const validIDs = new Set(data.map(datum => datum.id)); 17 | const validPreFilledSearchTerms = preFilledSearchTerms.filter(term => validIDs.has(term)); 18 | $(".ignore-search").val(validPreFilledSearchTerms).trigger('change.select2'); 19 | }); 20 | 21 | 22 | // Delete selecitons by tag instead of individual letter 23 | $.fn.select2.amd.require(['select2/selection/search'], function (Search) { 24 | Search.prototype.searchRemoveChoice = function (decorated, item) { 25 | this.trigger('unselect', { 26 | data: item 27 | }); 28 | 29 | this.$search.val(''); 30 | this.handleSearch(); 31 | }; 32 | }); 33 | 34 | // Highlight input on site load 35 | setTimeout(() => { 36 | $(".select2-search__field").focus(); 37 | }, 100); 38 | 39 | // All users to press ctrl+enter to create template 40 | $(".ignore-search").on("select2:selecting", e => { 41 | setTimeout(() => { 42 | $(".select2-search__field").keydown(e => { 43 | if (e.keyCode == 13 && (e.metaKey || e.ctrlKey)) { 44 | generateGitIgnore(); 45 | } 46 | }); 47 | }, 100); 48 | }); 49 | 50 | // Generate gitignore template 51 | function generateGitIgnore() { 52 | const searchString = $(".ignore-search").map(function() {return $(this).val();}).get().join(','); 53 | const searchLength = searchString.length; 54 | if (searchLength > 0) { 55 | const files = searchString.replace(/^,/, ''); 56 | window.location = `/api/${files}`; 57 | $(".ignore-search").val(""); 58 | } 59 | } 60 | 61 | // Generate gitignore file template 62 | function generateGitIgnoreFile() { 63 | const searchString = $(".ignore-search").map(function() {return $(this).val();}).get().join(','); 64 | const searchLength = searchString.length; 65 | if (searchLength > 0) { 66 | const files = searchString.replace(/^,/, ''); 67 | window.location = `/api/f/${files}`; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Resources/Views/docs.leaf: -------------------------------------------------------------------------------- 1 | #set("title") { 2 | #(titleString) 3 | } 4 | 5 | #set("description") { 6 | 7 | } 8 | 9 | #set("headerScripts") { 10 | 11 | 12 | #if(enableCarbon) { 13 | 14 | } 15 | } 16 | 17 | #set("bodyType") { 18 | 19 | } 20 | 21 | #set("body") { 22 |
23 |
24 |

25 | 30 |
31 |
32 | 33 | 34 | 35 |
36 |
37 |
38 | 44 |
45 |
46 | } 47 | 48 | #set("footerScripts") { 49 | 50 | 51 | 52 | 53 | 54 | 57 | } 58 | 59 | #embed("base") 60 | -------------------------------------------------------------------------------- /Sources/App/Server.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Server.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/22/16. 6 | // 7 | // 8 | 9 | import Vapor 10 | import Leaf 11 | import LingoVapor 12 | 13 | public class Gitignore { 14 | fileprivate let config: Config 15 | fileprivate var services: Services 16 | fileprivate let lingoProvider: LingoProvider 17 | fileprivate var middlewares: MiddlewareConfig 18 | 19 | public init() { 20 | config = Config.default() 21 | services = Services.default() 22 | middlewares = MiddlewareConfig() 23 | lingoProvider = LingoProvider(defaultLocale: "en", localizationsDir: "Localizations") 24 | } 25 | 26 | public func app(_ env: Environment) throws -> Application { 27 | try configure(env: env) 28 | let app = try Application(config: config, environment: env, services: services) 29 | 30 | return app 31 | } 32 | 33 | private func configure(env: Environment) throws { 34 | let router = EngineRouter.default() 35 | try routes(router, env: env) 36 | 37 | services.register(router, as: Router.self) 38 | 39 | try services.register(LeafProvider()) 40 | try services.register(lingoProvider) 41 | 42 | middlewares.use(FileMiddleware.self) 43 | middlewares.use(ErrorMiddleware.self) 44 | services.register(middlewares) 45 | } 46 | 47 | /// Register your application's routes here. 48 | private func routes(_ router: Router, env: Environment) throws { 49 | let dataDirectory = URL(fileURLWithPath: DirectoryConfig.detect().workDir, isDirectory: true) 50 | .absoluteURL.appendingPathComponent("gitignore", isDirectory: true) 51 | .absoluteURL.appendingPathComponent("templates", isDirectory: true) 52 | let orderFile = dataDirectory.absoluteURL.appendingPathComponent("order", isDirectory: false) 53 | 54 | let templateController = TemplateController(dataDirectory: dataDirectory, orderFile: orderFile) 55 | 56 | let siteHandlers = SiteHandlers(templateController: templateController, env: env) 57 | siteHandlers.createIndexPage(router: router) 58 | siteHandlers.createDocumentsPage(router: router) 59 | siteHandlers.createDropdownTemplates(router: router) 60 | 61 | let apiHandlers = APIHandlers(templateController: templateController) 62 | apiHandlers.createIgnoreEndpoint(router: router) 63 | apiHandlers.createTemplateDownloadEndpoint(router: router) 64 | apiHandlers.createListEndpoint(router: router) 65 | apiHandlers.createOrderEndpoint(router: router) 66 | apiHandlers.createHelp(router: router) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Tests/AppTests/RouteHandlers/SiteHandlersTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SiteHandlers.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/22/16. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Vapor 11 | import HTTP 12 | 13 | @testable import App 14 | 15 | class SiteHandlersTests: XCTestCase { 16 | 17 | static let allTests = [ 18 | ("testServer_index", testServer_index), 19 | ("testServer_docs", testServer_docs), 20 | ("testServer_templatesJSON_noTerm", testServer_templatesJSON_noTerm), 21 | ("testServer_templatesJSON_term", testServer_templatesJSON_term), 22 | ("testServer_templatesJSON_term_capitalLetter", testServer_templatesJSON_term_capitalLetter), 23 | ("testServer_templatesJSON_multipleTerms", testServer_templatesJSON_multipleTerms) 24 | ] 25 | 26 | func testServer_index() throws { 27 | if let byteCount = try responseForRequest("/").http.body.count { 28 | XCTAssertGreaterThan(byteCount, 0) 29 | } else { 30 | XCTFail() 31 | } 32 | } 33 | 34 | func testServer_docs() throws { 35 | if let byteCount = try responseForRequest("/docs").http.body.count { 36 | XCTAssertGreaterThan(byteCount, 0) 37 | } else { 38 | XCTFail() 39 | } 40 | } 41 | 42 | func testServer_templatesJSON_noTerm() throws { 43 | if let byteCount = try responseForRequest("/dropdown/templates.json").http.body.count { 44 | XCTAssertGreaterThan(byteCount, 0) 45 | } else { 46 | XCTFail() 47 | } 48 | } 49 | 50 | func testServer_templatesJSON_term() throws { 51 | if let byteCount = try responseForRequest("/dropdown/templates.json?term=java").http.body.count { 52 | XCTAssertGreaterThan(byteCount, 0) 53 | } else { 54 | XCTFail() 55 | } 56 | } 57 | 58 | func testServer_templatesJSON_term_capitalLetter() throws { 59 | if let byteCount = try responseForRequest("/dropdown/templates.json?term=Java").http.body.count { 60 | XCTAssertGreaterThan(byteCount, 0) 61 | } else { 62 | XCTFail() 63 | } 64 | } 65 | 66 | func testServer_templatesJSON_multipleTerms() throws { 67 | if let byteCount = try responseForRequest("/dropdown/templates.json?term=java,ada").http.body.count { 68 | XCTAssertGreaterThan(byteCount, 0) 69 | } else { 70 | XCTFail() 71 | } 72 | } 73 | 74 | 75 | // MARK: - Private 76 | 77 | private func responseForRequest(_ url: String) throws -> Response { 78 | let application = try Gitignore().app(.detect()) 79 | let request = HTTPRequest(method: .GET, url: URL(string: url)!) 80 | let wrappedRequest = Request(http: request, using: application) 81 | 82 | let responder = try application.make(Responder.self) 83 | return try responder.respond(to: wrappedRequest).wait() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Package.pins: -------------------------------------------------------------------------------- 1 | { 2 | "autoPin": true, 3 | "pins": [ 4 | { 5 | "package": "CLibreSSL", 6 | "reason": null, 7 | "repositoryURL": "https://github.com/vapor/clibressl.git", 8 | "version": "1.0.0" 9 | }, 10 | { 11 | "package": "Console", 12 | "reason": null, 13 | "repositoryURL": "https://github.com/vapor/console.git", 14 | "version": "1.0.2" 15 | }, 16 | { 17 | "package": "Core", 18 | "reason": null, 19 | "repositoryURL": "https://github.com/vapor/core.git", 20 | "version": "1.1.1" 21 | }, 22 | { 23 | "package": "Crypto", 24 | "reason": null, 25 | "repositoryURL": "https://github.com/vapor/crypto.git", 26 | "version": "1.1.0" 27 | }, 28 | { 29 | "package": "Engine", 30 | "reason": null, 31 | "repositoryURL": "https://github.com/vapor/engine.git", 32 | "version": "1.3.12" 33 | }, 34 | { 35 | "package": "Fluent", 36 | "reason": null, 37 | "repositoryURL": "https://github.com/vapor/fluent.git", 38 | "version": "1.4.1" 39 | }, 40 | { 41 | "package": "JSON", 42 | "reason": null, 43 | "repositoryURL": "https://github.com/vapor/json.git", 44 | "version": "1.0.6" 45 | }, 46 | { 47 | "package": "Jay", 48 | "reason": null, 49 | "repositoryURL": "https://github.com/DanToml/Jay.git", 50 | "version": "1.0.1" 51 | }, 52 | { 53 | "package": "Leaf", 54 | "reason": null, 55 | "repositoryURL": "https://github.com/vapor/leaf.git", 56 | "version": "1.0.6" 57 | }, 58 | { 59 | "package": "Multipart", 60 | "reason": null, 61 | "repositoryURL": "https://github.com/vapor/multipart.git", 62 | "version": "1.0.2" 63 | }, 64 | { 65 | "package": "Node", 66 | "reason": null, 67 | "repositoryURL": "https://github.com/vapor/node.git", 68 | "version": "1.0.1" 69 | }, 70 | { 71 | "package": "PathIndexable", 72 | "reason": null, 73 | "repositoryURL": "https://github.com/vapor/path-indexable.git", 74 | "version": "1.0.0" 75 | }, 76 | { 77 | "package": "Polymorphic", 78 | "reason": null, 79 | "repositoryURL": "https://github.com/vapor/polymorphic.git", 80 | "version": "1.0.1" 81 | }, 82 | { 83 | "package": "Routing", 84 | "reason": null, 85 | "repositoryURL": "https://github.com/vapor/routing.git", 86 | "version": "1.1.0" 87 | }, 88 | { 89 | "package": "Socks", 90 | "reason": null, 91 | "repositoryURL": "https://github.com/vapor/socks.git", 92 | "version": "1.2.7" 93 | }, 94 | { 95 | "package": "TLS", 96 | "reason": null, 97 | "repositoryURL": "https://github.com/vapor/tls.git", 98 | "version": "1.1.2" 99 | }, 100 | { 101 | "package": "Turnstile", 102 | "reason": null, 103 | "repositoryURL": "https://github.com/stormpath/Turnstile.git", 104 | "version": "1.0.6" 105 | }, 106 | { 107 | "package": "Vapor", 108 | "reason": null, 109 | "repositoryURL": "https://github.com/vapor/vapor.git", 110 | "version": "1.5.13" 111 | } 112 | ], 113 | "version": 1 114 | } -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@gitignore.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /Sources/App/Controllers/TemplateController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TemplateController.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/17/16. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | internal struct TemplateController: ReadOnlyTemplateManagerProtocol { 12 | internal var order = [String: Int]() 13 | internal var count = 0 14 | internal var templates = [String: IgnoreTemplateModel]() 15 | 16 | /// Create Template Controller 17 | /// 18 | /// - Returns: Template Controller 19 | init(dataDirectory: URL, orderFile: URL) { 20 | do { 21 | order = try parseFile(orderFile: orderFile) 22 | templates = try parseTemplateDirectory(dataDirectory: dataDirectory) 23 | try templates.patchTemplates(dataDirectory: dataDirectory) 24 | try templates.stackTempaltes(dataDirectory: dataDirectory) 25 | count = templates.count 26 | } catch { 27 | print("‼️ You might not have done a recursive clone to update your submodules:\n‼️ `git submodule update --init --recursive`") 28 | } 29 | } 30 | 31 | // MARK: - Private 32 | 33 | /// Parse file which defines template order precedence 34 | /// 35 | /// - Parameter orderFile: The dependency order file 36 | /// - Returns: List of templates in order precedence 37 | private func parseFile(orderFile: URL) throws -> [String: Int] { 38 | return try String(contentsOf: orderFile, encoding: String.Encoding.utf8) 39 | .replacingOccurrences(of: "\r\n", with: "\n", options: .regularExpression) 40 | .components(separatedBy: "\n") 41 | .map({ (line) -> String in 42 | line.trimmingCharacters(in: .whitespaces).lowercased() 43 | }) 44 | .filter({ (line) -> Bool in 45 | !line.hasPrefix("#") && !line.isEmpty 46 | }) 47 | .enumerated() 48 | .reduce([String: Int](), { (orderedDict, line : (offset: Int, text: String)) -> [String: Int] in 49 | var mutableOrderedDict = orderedDict 50 | mutableOrderedDict[line.text] = line.offset 51 | return mutableOrderedDict 52 | }) 53 | } 54 | 55 | /// Parse template directory 56 | /// 57 | /// - Parameter dataDirectory: The path to the data directory 58 | /// - Returns: Ignore template model dictionary 59 | private func parseTemplateDirectory(dataDirectory: URL) throws -> [String: IgnoreTemplateModel] { 60 | return try FileManager().enumerator(at: dataDirectory, includingPropertiesForKeys: nil)! 61 | .allObjects 62 | .compactMap({ (templatePath: Any) -> URL? in 63 | templatePath as? URL 64 | }) 65 | .filter({ (templatePath: URL) -> Bool in 66 | templatePath.pathExtension == TemplateSuffix.template.extension 67 | }) 68 | .compactMap({ (templatePath: URL) -> (key: String, model: IgnoreTemplateModel) in 69 | let fileContents = try String(contentsOf: templatePath, encoding: String.Encoding.utf8) 70 | .replacingOccurrences(of: "\r\n", with: "\n", options: .regularExpression) 71 | return (key: templatePath.name.lowercased(), 72 | model: IgnoreTemplateModel(key: templatePath.name.lowercased(), 73 | name: templatePath.name, 74 | fileName: templatePath.fileName, 75 | contents: TemplateSuffix.template.header(name: templatePath.name).appending(fileContents))) 76 | }) 77 | .reduce([String: IgnoreTemplateModel]()) { (currentTemplateModels, templateData) in 78 | var mutableCurrentTemplates = currentTemplateModels 79 | mutableCurrentTemplates[templateData.key] = templateData.model 80 | return mutableCurrentTemplates 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Public/css/theme-gitignore-style.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Globals 3 | */ 4 | .lead { 5 | color: #9090AA; 6 | padding: 20px 0 0; 7 | font-size: 16px; 8 | } 9 | /* Links */ 10 | a, 11 | a:focus, 12 | a:hover { 13 | color: #E15B39; 14 | } 15 | /* Custom default button */ 16 | .btn-default, 17 | .btn-default:focus, 18 | .btn-default:hover { 19 | color: #E15B39; 20 | text-shadow: none; 21 | /* Prevent inheritence from `body` */ 22 | background-color: #FAFAFA; 23 | border: 1px solid #EEEEEE; 24 | } 25 | /* 26 | * Base structure 27 | */ 28 | body, 29 | html { 30 | height: 100%; 31 | background-color: #FAFAFA; 32 | } 33 | body { 34 | color: #222222; 35 | text-align: center; 36 | } 37 | /* Extra markup and styles for table-esque vertical and horizontal centering */ 38 | .site-wrapper { 39 | display: table; 40 | width: 100%; 41 | height: 100%; 42 | /* For at least Firefox */ 43 | min-height: 100%; 44 | } 45 | .site-wrapper-inner { 46 | display: table-cell; 47 | vertical-align: top; 48 | } 49 | .cover-container { 50 | margin-right: auto; 51 | margin-left: auto; 52 | } 53 | /* Padding for spacing */ 54 | .inner { 55 | padding: 30px; 56 | } 57 | /* 58 | * Header 59 | */ 60 | .masthead-brand { 61 | margin-top: 10px; 62 | margin-bottom: 10px; 63 | } 64 | .masthead-nav > li { 65 | display: inline-block; 66 | } 67 | .masthead-nav > li + li { 68 | margin-left: 20px; 69 | } 70 | .masthead-nav > li > a { 71 | padding-right: 0; 72 | padding-left: 0; 73 | font-size: 16px; 74 | font-weight: bold; 75 | color: #E15B39; 76 | /* IE8 proofing */ 77 | border-bottom: 2px solid transparent; 78 | } 79 | .masthead-nav > li > a:focus, 80 | .masthead-nav > li > a:hover { 81 | background-color: transparent; 82 | border-bottom-color: #C03C1F; 83 | } 84 | .masthead-nav > .active > a, 85 | .masthead-nav > .active > a:focus, 86 | .masthead-nav > .active > a:hover { 87 | color: #C03C1F; 88 | border-bottom-color: #C03C1F; 89 | } 90 | /* 91 | * Cover 92 | */ 93 | .cover { 94 | padding: 0 20px 100px; 95 | } 96 | .cover .btn-lg { 97 | padding: 10px 20px; 98 | font-weight: bold; 99 | } 100 | /* 101 | * Footer 102 | */ 103 | .mastfoot { 104 | color: #222222; 105 | /* IE8 proofing */ 106 | } 107 | /* 108 | * Affix and center 109 | */ 110 | @media (min-width: 768px) { 111 | /* Pull out the header and footer */ 112 | .masthead { 113 | position: fixed; 114 | top: 0; 115 | } 116 | .mastfoot { 117 | position: fixed; 118 | bottom: 0; 119 | } 120 | /* Start the vertical centering */ 121 | .site-wrapper-inner { 122 | vertical-align: middle; 123 | } 124 | /* Handle the widths */ 125 | .cover-container, 126 | .mastfoot, 127 | .masthead { 128 | width: 100%; 129 | /* Must be percentage or pixels for horizontal alignment */ 130 | } 131 | } 132 | @media (min-width: 992px) { 133 | .cover-container, 134 | .mastfoot, 135 | .masthead { 136 | width: 700px; 137 | } 138 | } 139 | .btn-gitignore { 140 | color: #fff; 141 | background-image: -webkit-linear-gradient(top, #ff4f27 0, #E15B39 100%); 142 | background-image: linear-gradient(to bottom, #ff4f27 0, #E15B39 100%); 143 | background-repeat: repeat-x; 144 | border: 1px solid #d23e1e; 145 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fffaa937', GradientType=0); 146 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 147 | } 148 | .btn-gitignore:active { 149 | color: #fff; 150 | background-image: -webkit-linear-gradient(top, #d84824 0, #ce4121 100%); 151 | background-image: linear-gradient(to bottom, #d84521 0, #ce4121 100%); 152 | background-repeat: repeat-x; 153 | border: 1px solid #d23e1e; 154 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fffaa937', GradientType=0); 155 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 156 | } 157 | .select2-results .select2-highlighted { 158 | background: #E15B39; 159 | color: #fff; 160 | } 161 | -------------------------------------------------------------------------------- /Public/css/app.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Globals 3 | */ 4 | .lead { 5 | color: #9090AA; 6 | padding: 0 0 20px; 7 | font-weight: 300; 8 | font-size: 18px; 9 | } 10 | /* Links */ 11 | a, 12 | a:focus, 13 | a:hover { 14 | color: #E15B39; 15 | } 16 | /* Custom default button */ 17 | .btn-default, 18 | .btn-default:focus, 19 | .btn-default:hover { 20 | color: #E15B39; 21 | text-shadow: none; 22 | /* Prevent inheritence from `body` */ 23 | background-color: #FAFAFA; 24 | border: 1px solid #EEEEEE; 25 | } 26 | /* 27 | * Base structure 28 | */ 29 | body, 30 | html { 31 | height: 100%; 32 | background-color: #FAFAFA; 33 | } 34 | body { 35 | color: #222222; 36 | text-align: center; 37 | } 38 | /* Extra markup and styles for table-esque vertical and horizontal centering */ 39 | .site-wrapper { 40 | display: table; 41 | width: 100%; 42 | height: 100%; 43 | /* For at least Firefox */ 44 | min-height: 100%; 45 | } 46 | .site-wrapper-inner { 47 | display: table-cell; 48 | vertical-align: top; 49 | } 50 | .cover-container { 51 | margin-right: auto; 52 | margin-left: auto; 53 | } 54 | /* Padding for spacing */ 55 | .inner { 56 | padding: 30px; 57 | } 58 | /* 59 | * Header 60 | */ 61 | .masthead-brand { 62 | margin-top: 10px; 63 | margin-bottom: 10px; 64 | } 65 | .masthead-nav { 66 | padding: 40px 0 0 0; 67 | } 68 | .masthead-nav > li { 69 | display: inline-block; 70 | } 71 | .masthead-nav > li + li { 72 | margin-left: 20px; 73 | } 74 | .masthead-nav > li > a { 75 | padding: 0 0 10px 0; 76 | font-size: 18px; 77 | font-weight: 300; 78 | color: #E15B39; 79 | /* IE8 proofing */ 80 | border-bottom: 1px solid transparent; 81 | } 82 | .masthead-nav > li > a:focus, 83 | .masthead-nav > li > a:hover { 84 | background-color: transparent; 85 | border-bottom-color: #C03C1F; 86 | } 87 | .masthead-nav > .active > a, 88 | .masthead-nav > .active > a:focus, 89 | .masthead-nav > .active > a:hover { 90 | color: #C03C1F; 91 | border-bottom-color: #C03C1F; 92 | } 93 | /* 94 | * Cover 95 | */ 96 | .cover { 97 | padding: 0 20px 100px; 98 | } 99 | .cover .btn-lg { 100 | padding: 10px 20px; 101 | font-weight: bold; 102 | } 103 | /* 104 | * Footer 105 | */ 106 | .mastfoot { 107 | color: #222222; 108 | /* IE8 proofing */ 109 | } 110 | /* 111 | * Affix and center 112 | */ 113 | @media (min-width: 768px) { 114 | /* Pull out the header and footer */ 115 | .masthead { 116 | position: fixed; 117 | top: 0; 118 | } 119 | .mastfoot { 120 | position: fixed; 121 | bottom: 0; 122 | } 123 | /* Start the vertical centering */ 124 | .site-wrapper-inner { 125 | vertical-align: middle; 126 | } 127 | /* Handle the widths */ 128 | .cover-container, 129 | .mastfoot, 130 | .masthead { 131 | width: 100%; 132 | /* Must be percentage or pixels for horizontal alignment */ 133 | } 134 | } 135 | @media (min-width: 992px) { 136 | .cover-container, 137 | .mastfoot, 138 | .masthead { 139 | width: 700px; 140 | } 141 | } 142 | .btn-gitignore { 143 | color: #fff; 144 | background-image: -webkit-linear-gradient(top, #ff4f27 0, #E15B39 100%); 145 | background-image: linear-gradient(to bottom, #ff4f27 0, #E15B39 100%); 146 | background-repeat: repeat-x; 147 | border: 1px solid #d23e1e; 148 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fffaa937', GradientType=0); 149 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 150 | } 151 | .btn-gitignore:active { 152 | color: #fff; 153 | background-image: -webkit-linear-gradient(top, #d84824 0, #ce4121 100%); 154 | background-image: linear-gradient(to bottom, #d84521 0, #ce4121 100%); 155 | background-repeat: repeat-x; 156 | border: 1px solid #d23e1e; 157 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fffaa937', GradientType=0); 158 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 159 | } 160 | .select2-results .select2-highlighted { 161 | background: #E15B39; 162 | color: #fff; 163 | } 164 | -------------------------------------------------------------------------------- /Resources/Views/index.leaf: -------------------------------------------------------------------------------- 1 | #set("title") { 2 | #(titleString) 3 | } 4 | 5 | #set("description") { 6 | 7 | } 8 | 9 | #set("headerScripts") { 10 | 11 | 12 | 13 | 14 | 15 | #if(enableCarbon) { 16 | 17 | } 18 | } 19 | 20 | #set("bodyType") { 21 | 22 | } 23 | 24 | #set("body") { 25 |
26 |
27 |
28 |
29 | 30 |

#(subtitleString)

31 | 32 |
33 | 34 |
35 | 36 |
37 |
38 | 39 | 46 |
47 |
48 |
49 |
50 | 51 |
52 |
53 |
54 |
55 |
56 | 57 |
58 | } 59 | 60 | #set("footerScripts") { 61 | 62 | 63 | 64 | 65 | 66 | } 67 | 68 | #embed("base") 69 | -------------------------------------------------------------------------------- /Public/css/app.less: -------------------------------------------------------------------------------- 1 | @import "variables.less"; 2 | /* 3 | * Globals 4 | */ 5 | .lead { 6 | color: @text-secondary; 7 | padding: 20px 0 0; 8 | font-size: 16px; 9 | } 10 | /* Links */ 11 | a, 12 | a:focus, 13 | a:hover { 14 | color: @link; 15 | } 16 | /* Custom default button */ 17 | .btn-default, 18 | .btn-default:focus, 19 | .btn-default:hover { 20 | color: @link; 21 | text-shadow: none; 22 | /* Prevent inheritence from `body` */ 23 | background-color: @background; 24 | border: 1px solid @border-line; 25 | } 26 | /* 27 | * Base structure 28 | */ 29 | body, 30 | html { 31 | height: 100%; 32 | background-color: @background; 33 | } 34 | body { 35 | color: @text; 36 | text-align: center; 37 | } 38 | /* Extra markup and styles for table-esque vertical and horizontal centering */ 39 | .site-wrapper { 40 | display: table; 41 | width: 100%; 42 | height: 100%; 43 | /* For at least Firefox */ 44 | min-height: 100%; 45 | } 46 | .site-wrapper-inner { 47 | display: table-cell; 48 | vertical-align: top; 49 | } 50 | .cover-container { 51 | margin-right: auto; 52 | margin-left: auto; 53 | } 54 | /* Padding for spacing */ 55 | .inner { 56 | padding: 30px; 57 | } 58 | /* 59 | * Header 60 | */ 61 | .masthead-brand { 62 | margin-top: 10px; 63 | margin-bottom: 10px; 64 | } 65 | .masthead-nav > li { 66 | display: inline-block; 67 | } 68 | .masthead-nav > li + li { 69 | margin-left: 20px; 70 | } 71 | .masthead-nav > li > a { 72 | padding-right: 0; 73 | padding-left: 0; 74 | font-size: 16px; 75 | font-weight: bold; 76 | color: @link; 77 | /* IE8 proofing */ 78 | border-bottom: 2px solid transparent; 79 | } 80 | .masthead-nav > li > a:focus, 81 | .masthead-nav > li > a:hover { 82 | background-color: transparent; 83 | border-bottom-color: @link-hover; 84 | } 85 | .masthead-nav > .active > a, 86 | .masthead-nav > .active > a:focus, 87 | .masthead-nav > .active > a:hover { 88 | color: @link-hover; 89 | border-bottom-color: @link-hover; 90 | } 91 | /* 92 | * Cover 93 | */ 94 | .cover { 95 | padding: 0 20px 100px; 96 | } 97 | .cover .btn-lg { 98 | padding: 10px 20px; 99 | font-weight: bold; 100 | } 101 | /* 102 | * Footer 103 | */ 104 | .mastfoot { 105 | color: @text; 106 | /* IE8 proofing */ 107 | } 108 | /* 109 | * Affix and center 110 | */ 111 | @media (min-width: 768px) { 112 | /* Pull out the header and footer */ 113 | .masthead { 114 | position: fixed; 115 | top: 0; 116 | } 117 | .mastfoot { 118 | position: fixed; 119 | bottom: 0; 120 | } 121 | /* Start the vertical centering */ 122 | .site-wrapper-inner { 123 | vertical-align: middle; 124 | } 125 | /* Handle the widths */ 126 | .cover-container, 127 | .mastfoot, 128 | .masthead { 129 | width: 100%; 130 | /* Must be percentage or pixels for horizontal alignment */ 131 | } 132 | } 133 | @media (min-width: 992px) { 134 | .cover-container, 135 | .mastfoot, 136 | .masthead { 137 | width: 700px; 138 | } 139 | } 140 | .btn-gitignore { 141 | color: #fff; 142 | background-image: -webkit-linear-gradient(top, #ff4f27 0, #E15B39 100%); 143 | background-image: linear-gradient(to bottom, #ff4f27 0, #E15B39 100%); 144 | background-repeat: repeat-x; 145 | border: 1px solid #d23e1e; 146 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= '#fffbb450',endColorstr='#fffaa937',GradientType=0); 147 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 148 | } 149 | .btn-gitignore:active { 150 | color: #fff; 151 | background-image: -webkit-linear-gradient(top, #d84824 0, #ce4121 100%); 152 | background-image: linear-gradient(to bottom, #d84521 0, #ce4121 100%); 153 | background-repeat: repeat-x; 154 | border: 1px solid #d23e1e; 155 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= '#fffbb450',endColorstr='#fffaa937',GradientType=0); 156 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 157 | } 158 | .select2-results .select2-highlighted { 159 | background: @link; 160 | color: #fff; 161 | } 162 | -------------------------------------------------------------------------------- /Public/img/gitignoreio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Artboard 5 | Created with Sketch. 6 | 7 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Sources/App/RouteHandlers/SiteRouteHandlers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SiteRouteHandlers.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 11/7/16. 6 | // 7 | // 8 | 9 | import Vapor 10 | import Leaf 11 | import Lingo 12 | 13 | internal class SiteHandlers { 14 | private let count: String 15 | private let templates: [String: IgnoreTemplateModel] 16 | private let env: Environment! 17 | 18 | /// Initialze the Site Handlers extension 19 | /// 20 | /// - Parameter templateController: All of the gitignore template objects 21 | init(templateController: TemplateController, env: Environment) { 22 | self.count = String(templateController.count) 23 | self.templates = templateController.templates 24 | self.env = env 25 | } 26 | 27 | /// Create Index Page 28 | /// 29 | /// - Parameter router: Vapor server side Swift Router 30 | internal func createIndexPage(router: Router) { 31 | router.get("/") { request -> Future in 32 | let leaf = try request.make(LeafRenderer.self) 33 | let lingo = try request.make(Lingo.self) 34 | let locale = request.acceptLanguage 35 | 36 | let context = ["titleString": lingo.localize("title", locale: locale), 37 | "descriptionString": lingo.localize("description", locale: locale, interpolations: ["templateCount": self.count]), 38 | "searchPlaceholderString": lingo.localize("searchPlaceholder", locale: locale), 39 | "searchGoString": lingo.localize("searchGo", locale: locale), 40 | "searchDownloadString": lingo.localize("searchDownload", locale: locale), 41 | "subtitleString": lingo.localize("subtitle", locale: locale), 42 | "sourceCodeDescriptionString": lingo.localize("sourceCodeDescription", locale: locale), 43 | "sourceCodeTitleString": lingo.localize("sourceCodeTitle", locale: locale), 44 | "commandLineDescriptionString": lingo.localize("commandLineDescription", locale: locale), 45 | "commandLineTitleString": lingo.localize("commandLineTitle", locale: locale), 46 | "videoDescriptionString": lingo.localize("videoDescription", locale: locale), 47 | "videoTitleString": lingo.localize("videoTitle", locale: locale), 48 | "footerString": lingo.localize("footer", locale: locale, interpolations: ["templateCount": self.count])] 49 | 50 | return leaf.render("index", context) 51 | } 52 | } 53 | 54 | /// Crate Documentation Page 55 | /// 56 | /// - Parameter router: Vapor server side Swift Router 57 | internal func createDocumentsPage(router: Router) { 58 | router.get("/docs") { request -> Future in 59 | let leaf = try request.make(LeafRenderer.self) 60 | let lingo = try request.make(Lingo.self) 61 | let locale = request.acceptLanguage 62 | 63 | let context = ["titleString": lingo.localize("title", locale: locale), 64 | "descriptionString": lingo.localize("description", locale: locale, interpolations: ["templateCount": self.count])] 65 | 66 | return leaf.render("docs", context) 67 | } 68 | } 69 | 70 | /// Create dropdown template JSON list 71 | /// 72 | /// - Parameter router: Vapor server side Swift Router 73 | internal func createDropdownTemplates(router: Router) { 74 | router.get("/dropdown/templates.json") { request -> [Dropdown] in 75 | guard let flags = try? request.query.decode(Flags.self), 76 | let term = flags.term else { 77 | return self.createSortedDropdownTemplates() 78 | } 79 | return self.createSortedDropdownTemplates(query: term) 80 | } 81 | } 82 | 83 | // MARK: - Private 84 | 85 | /// Create dropdown list template 86 | /// 87 | /// - Parameter templates: Template controller template dictionary 88 | /// 89 | /// - Returns: JSON array containing all templates 90 | private func createSortedDropdownTemplates(query: String? = nil) -> [Dropdown] { 91 | return templates 92 | .values 93 | .filter({ (templateModel) -> Bool in 94 | guard let query = query else { 95 | return true 96 | } 97 | return templateModel.key.contains(query) 98 | }) 99 | .sorted(by: { $0.key < $1.key }) 100 | .sorted(by: { $0.key.count < $1.key.count }) 101 | .map { (templateModel) -> Dropdown in 102 | return Dropdown(id: templateModel.key, text: templateModel.name) 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Tests/AppTests/RouteHandlers/APIHandlersTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APIHandlers.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/22/16. 6 | // 7 | // 8 | 9 | import XCTest 10 | import Vapor 11 | import HTTP 12 | 13 | @testable import App 14 | 15 | class APIHandlersTests: XCTestCase { 16 | static let allTests = [ 17 | ("testServer_api_template", testServer_api_template), 18 | ("testServer_api_no_template", testServer_api_no_template), 19 | ("testServer_api_file_template", testServer_api_file_template), 20 | ("testServer_api_list", testServer_api_list), 21 | ("testServer_api_list_lines", testServer_api_list_lines), 22 | ("testServer_api_list_json", testServer_api_list_json), 23 | ("testServer_api_list_xyz", testServer_api_list_xyz), 24 | ("testServer_api_force_sort_sortable", testServer_api_force_sort_sortable), 25 | ("testServer_api_no_sort_sortalbe", testServer_api_no_sort_sortalbe), 26 | ("testServer_api_no_sort_not_sortable", testServer_api_no_sort_not_sortable), 27 | ("testServer_api_order", testServer_api_order), 28 | ("testServer_api", testServer_api), 29 | ] 30 | 31 | func testServer_api_template() throws { 32 | if let byteCount = try responseForRequest("/api/swift").http.body.count { 33 | XCTAssertGreaterThan(byteCount, 0) 34 | } else { 35 | XCTFail() 36 | } 37 | } 38 | 39 | func testServer_api_no_template() throws { 40 | if let byteCount = try responseForRequest("/api/f/tesla").http.body.count { 41 | XCTAssertGreaterThan(byteCount, 0) 42 | } else { 43 | XCTFail() 44 | } 45 | } 46 | 47 | func testServer_api_file_template() throws { 48 | if let byteCount = try responseForRequest("/api/f/swift").http.body.count { 49 | XCTAssertGreaterThan(byteCount, 0) 50 | } else { 51 | XCTFail() 52 | } 53 | } 54 | 55 | func testServer_api_list() throws { 56 | if let byteCount = try responseForRequest("/api/list").http.body.count { 57 | XCTAssertGreaterThan(byteCount, 0) 58 | } else { 59 | XCTFail() 60 | } 61 | } 62 | 63 | func testServer_api_list_lines() throws { 64 | if let byteCount = try responseForRequest("/api/list?format=lines").http.body.count { 65 | XCTAssertGreaterThan(byteCount, 0) 66 | } else { 67 | XCTFail() 68 | } 69 | } 70 | 71 | func testServer_api_list_json() throws { 72 | if let byteCount = try responseForRequest("/api/list?format=json").http.body.count { 73 | XCTAssertGreaterThan(byteCount, 0) 74 | } else { 75 | XCTFail() 76 | } 77 | } 78 | 79 | func testServer_api_list_xyz() throws { 80 | if let byteCount = try responseForRequest("/api/list?format=xyz").http.body.count { 81 | XCTAssertGreaterThan(byteCount, 0) 82 | } else { 83 | XCTFail() 84 | } 85 | } 86 | 87 | func testServer_api_force_sort_sortable() throws { 88 | if let byteCount = try responseForRequest("/api/gradle,java").http.body.count { 89 | XCTAssertGreaterThan(byteCount, 0) 90 | } else { 91 | XCTFail() 92 | } 93 | } 94 | 95 | func testServer_api_no_sort_sortalbe() throws { 96 | if let byteCount = try responseForRequest("/api/java,gradle").http.body.count { 97 | XCTAssertGreaterThan(byteCount, 0) 98 | } else { 99 | XCTFail() 100 | } 101 | } 102 | 103 | func testServer_api_no_sort_not_sortable() throws { 104 | let body = try responseForRequest("/api/macos,swift").http.body 105 | XCTAssertFalse(body.description.contains("!! ERROR:")) 106 | XCTAssertTrue(body.description.contains("### macOS ###")) 107 | XCTAssertTrue(body.description.contains("### Swift ###")) 108 | if let byteCount = body.count { 109 | XCTAssertGreaterThan(byteCount, 0) 110 | } else { 111 | XCTFail() 112 | } 113 | } 114 | 115 | func testServer_api_url_multiple_url_encoded() throws { 116 | let body = try responseForRequest("/api/sbt%2Cscala%2Cintellij").http.body 117 | XCTAssertFalse(body.description.contains("!! ERROR:")) 118 | XCTAssertTrue(body.description.contains("### SBT ###")) 119 | XCTAssertTrue(body.description.contains("### Scala ###")) 120 | XCTAssertTrue(body.description.contains("### Intellij ###")) 121 | if let byteCount = body.count { 122 | XCTAssertGreaterThan(byteCount, 0) 123 | } else { 124 | XCTFail() 125 | } 126 | } 127 | 128 | func testServer_api_order() throws { 129 | if let byteCount = try responseForRequest("/api/order").http.body.count { 130 | XCTAssertGreaterThan(byteCount, 0) 131 | } else { 132 | XCTFail() 133 | } 134 | } 135 | 136 | func testServer_api() throws { 137 | if let byteCount = try responseForRequest("/api/").http.body.count { 138 | XCTAssertGreaterThan(byteCount, 0) 139 | } else { 140 | XCTFail() 141 | } 142 | } 143 | 144 | // MARK: - Private 145 | 146 | private func responseForRequest(_ url: String) throws -> Response { 147 | let application = try Gitignore().app(.detect()) 148 | let request = HTTPRequest(method: .GET, url: URL(string: url)!) 149 | let wrappedRequest = Request(http: request, using: application) 150 | 151 | let responder = try application.make(Responder.self) 152 | return try responder.respond(to: wrappedRequest).wait() 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Console", 6 | "repositoryURL": "https://github.com/vapor/console.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "96617dcdcbb7572cbff0645a2e3362c042bfffad", 10 | "version": "3.0.3" 11 | } 12 | }, 13 | { 14 | "package": "Core", 15 | "repositoryURL": "https://github.com/vapor/core.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "96ce86ebf9198328795c4b9cb711489460be083c", 19 | "version": "3.4.4" 20 | } 21 | }, 22 | { 23 | "package": "Crypto", 24 | "repositoryURL": "https://github.com/vapor/crypto.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "5605334590affd4785a5839806b4504407e054ac", 28 | "version": "3.3.0" 29 | } 30 | }, 31 | { 32 | "package": "DatabaseKit", 33 | "repositoryURL": "https://github.com/vapor/database-kit.git", 34 | "state": { 35 | "branch": null, 36 | "revision": "3a17dbbe9be5f8c37703e4b7982c1332ad6b00c4", 37 | "version": "1.3.1" 38 | } 39 | }, 40 | { 41 | "package": "HTTP", 42 | "repositoryURL": "https://github.com/vapor/http.git", 43 | "state": { 44 | "branch": null, 45 | "revision": "272b22be8cb3364e42a4701c2e0676e37480ec5a", 46 | "version": "3.1.5" 47 | } 48 | }, 49 | { 50 | "package": "Leaf", 51 | "repositoryURL": "https://github.com/vapor/leaf.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "d35f54cbac723e673f9bd5078361eea74049c8d7", 55 | "version": "3.0.2" 56 | } 57 | }, 58 | { 59 | "package": "Lingo", 60 | "repositoryURL": "https://github.com/miroslavkovac/Lingo.git", 61 | "state": { 62 | "branch": null, 63 | "revision": "f21f388b04239641b3e88d14f21762125faa9857", 64 | "version": "3.0.5" 65 | } 66 | }, 67 | { 68 | "package": "LingoVapor", 69 | "repositoryURL": "https://github.com/vapor-community/lingo-vapor.git", 70 | "state": { 71 | "branch": null, 72 | "revision": "56fdc7e7d531907ff97024a4aff8db90bcf0f965", 73 | "version": "3.0.0" 74 | } 75 | }, 76 | { 77 | "package": "Multipart", 78 | "repositoryURL": "https://github.com/vapor/multipart.git", 79 | "state": { 80 | "branch": null, 81 | "revision": "e57007c23a52b68e44ebdfc70cbe882a7c4f1ec3", 82 | "version": "3.0.2" 83 | } 84 | }, 85 | { 86 | "package": "Routing", 87 | "repositoryURL": "https://github.com/vapor/routing.git", 88 | "state": { 89 | "branch": null, 90 | "revision": "3219e328491b0853b8554c5a694add344d2c6cfb", 91 | "version": "3.0.1" 92 | } 93 | }, 94 | { 95 | "package": "Service", 96 | "repositoryURL": "https://github.com/vapor/service.git", 97 | "state": { 98 | "branch": null, 99 | "revision": "281a70b69783891900be31a9e70051b6fe19e146", 100 | "version": "1.0.0" 101 | } 102 | }, 103 | { 104 | "package": "swift-nio", 105 | "repositoryURL": "https://github.com/apple/swift-nio.git", 106 | "state": { 107 | "branch": null, 108 | "revision": "176dd6e8564d60e936b76f3a896d667ae3acba31", 109 | "version": "1.10.0" 110 | } 111 | }, 112 | { 113 | "package": "swift-nio-ssl", 114 | "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", 115 | "state": { 116 | "branch": null, 117 | "revision": "db16c3a90b101bb53b26a58867a344ad428072e0", 118 | "version": "1.3.2" 119 | } 120 | }, 121 | { 122 | "package": "swift-nio-ssl-support", 123 | "repositoryURL": "https://github.com/apple/swift-nio-ssl-support.git", 124 | "state": { 125 | "branch": null, 126 | "revision": "c02eec4e0e6d351cd092938cf44195a8e669f555", 127 | "version": "1.0.0" 128 | } 129 | }, 130 | { 131 | "package": "swift-nio-zlib-support", 132 | "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git", 133 | "state": { 134 | "branch": null, 135 | "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", 136 | "version": "1.0.0" 137 | } 138 | }, 139 | { 140 | "package": "TemplateKit", 141 | "repositoryURL": "https://github.com/vapor/template-kit.git", 142 | "state": { 143 | "branch": null, 144 | "revision": "db35b1c35aabd0f5db3abca0cfda7becfe9c43e2", 145 | "version": "1.1.0" 146 | } 147 | }, 148 | { 149 | "package": "URLEncodedForm", 150 | "repositoryURL": "https://github.com/vapor/url-encoded-form.git", 151 | "state": { 152 | "branch": null, 153 | "revision": "932024f363ee5ff59059cf7d67194a1c271d3d0c", 154 | "version": "1.0.5" 155 | } 156 | }, 157 | { 158 | "package": "Validation", 159 | "repositoryURL": "https://github.com/vapor/validation.git", 160 | "state": { 161 | "branch": null, 162 | "revision": "4de213cf319b694e4ce19e5339592601d4dd3ff6", 163 | "version": "2.1.1" 164 | } 165 | }, 166 | { 167 | "package": "Vapor", 168 | "repositoryURL": "https://github.com/vapor/vapor.git", 169 | "state": { 170 | "branch": null, 171 | "revision": "157d3b15336caa882662cc75024dd04b2e225246", 172 | "version": "3.1.0" 173 | } 174 | }, 175 | { 176 | "package": "WebSocket", 177 | "repositoryURL": "https://github.com/vapor/websocket.git", 178 | "state": { 179 | "branch": null, 180 | "revision": "eb4277f75f1d96a3d15c852cdd89af1799093dcd", 181 | "version": "1.1.0" 182 | } 183 | } 184 | ] 185 | }, 186 | "version": 1 187 | } 188 | -------------------------------------------------------------------------------- /Sources/App/RouteHandlers/APIRouteHandlers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APIRouteHandler.swift 3 | // GitignoreIO 4 | // 5 | // Created by Joe Blau on 12/17/16. 6 | // 7 | // 8 | 9 | import Foundation 10 | import Vapor 11 | import HTTP 12 | import Lingo 13 | 14 | //struct Encaps: Content { 15 | // var encapse = "encapse" 16 | // var sulation = "sulation" 17 | //} 18 | // 19 | //struct Test: Content { 20 | // var hello = Encaps() 21 | //} 22 | 23 | internal class APIHandlers { 24 | private let splitSize = 5 25 | private var order: [String: Int]! 26 | private var templates: [String: IgnoreTemplateModel]! 27 | 28 | /// Initialze the API Handlers extension 29 | /// 30 | /// - Parameter templateController: All of the gitignore template objects 31 | init(templateController: TemplateController) { 32 | templates = templateController.templates 33 | order = templateController.order 34 | } 35 | 36 | /// Create the API endpoint for serving ignore templates 37 | /// 38 | /// - Parameter router: Vapor server side Swift router 39 | internal func createIgnoreEndpoint(router: Router) { 40 | router.get("/api", String.parameter) { request -> Response in 41 | let response = request.response() 42 | let ignoreString = try request.parameters.next(String.self) 43 | let (template, status) = self.createTemplate(ignoreString: ignoreString) 44 | try response.content.encode(template) 45 | response.http.status = status 46 | return response 47 | } 48 | } 49 | 50 | /// Create the API endpoint for downloading ignore templates 51 | /// 52 | /// - Parameter router: Vapor server side Swift router 53 | internal func createTemplateDownloadEndpoint(router: Router) { 54 | router.get("/api/f", String.parameter) { request -> HTTPResponse in 55 | let ignoreString = try request.parameters.next(String.self) 56 | let (template, status) = self.createTemplate(ignoreString: ignoreString) 57 | return HTTPResponse(status: status, 58 | version: HTTPVersion(major: 1, minor: 0), 59 | headers: HTTPHeaders([(HTTPHeaderName.contentDisposition.description, "attachment; filename=\"gitignore\"")]), 60 | body: template) 61 | } 62 | } 63 | 64 | /// Create the API endpoint for showing the list of templates 65 | /// 66 | /// - Parameter router: Vapor server side Swift router 67 | internal func createListEndpoint(router: Router) { 68 | router.get("/api/list") { request -> Response in 69 | let response = request.response() 70 | 71 | let templateKeys = self.templates.keys.sorted() 72 | guard let flags = try? request.query.decode(Flags.self), 73 | let format = flags.format else { 74 | let groupedLines = stride(from: 0, to: templateKeys.count, by: self.splitSize) 75 | .map { 76 | templateKeys[$0.. Response in 99 | let response = request.response() 100 | try response.content.encode(json: self.order) 101 | return response 102 | } 103 | } 104 | 105 | /// Create the API endpoint for help 106 | /// 107 | /// - Parameter router: Vapor server side Swift router 108 | internal func createHelp(router: Router) { 109 | router.get("/api/") { _ in 110 | """ 111 | gitignore.io help: 112 | list - lists the operating systems, programming languages and IDE input types 113 | :types: - creates .gitignore files for types of operating systems, programming languages or IDEs 114 | """ 115 | } 116 | } 117 | 118 | // MARK: - Private 119 | 120 | /// Create final output template sorted based on `data/order` file with headers 121 | /// and footers applied to templates 122 | /// 123 | /// - Parameter ignoreString: Comma separated string of templates to generate 124 | /// 125 | /// - Peturns: Final formatted template with headers and footers 126 | private func createTemplate(ignoreString: String) -> (template: String, status: HTTPResponseStatus) { 127 | guard let urlDecoded = ignoreString.removingPercentEncoding else { 128 | return (""" 129 | 130 | #!! ERROR: url decoding \(ignoreString) !# 131 | 132 | """, .internalServerError) 133 | } 134 | var createStatus: HTTPResponseStatus = .ok 135 | let template = urlDecoded 136 | .lowercased() 137 | .components(separatedBy: ",") 138 | .uniqueElements 139 | .sorted() 140 | .sorted(by: { (left: String, right: String) -> Bool in 141 | (self.order[left] ?? 0) < (self.order[right] ?? 0) 142 | }) 143 | .map { (templateKey) -> String in 144 | guard let contents = self.templates[templateKey]?.contents else { 145 | createStatus = .notFound 146 | return """ 147 | 148 | #!! ERROR: \(templateKey) is undefined. Use list command to see defined gitignore types !!# 149 | 150 | """ 151 | } 152 | return contents 153 | } 154 | .reduce(""" 155 | 156 | # Created by https://www.gitignore.io/api/\(urlDecoded) 157 | # Edit at https://www.gitignore.io/?templates=\(urlDecoded) 158 | 159 | """) { (currentTemplate, contents) -> String in 160 | return currentTemplate.appending(contents) 161 | } 162 | .appending(""" 163 | 164 | # End of https://www.gitignore.io/api/\(urlDecoded) 165 | 166 | """) 167 | .removeDuplicateLines() 168 | 169 | return (template: template, status: createStatus) 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /Public/components/flatdoc/v/0.9.0/theme-white/script.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var $window = $(window); 3 | var $document = $(document); 4 | 5 | /* 6 | * Scrollspy. 7 | */ 8 | 9 | $document.on('flatdoc:ready', function() { 10 | $("h2, h3").scrollagent(function(cid, pid, currentElement, previousElement) { 11 | if (pid) { 12 | $("[href='#"+pid+"']").removeClass('active'); 13 | } 14 | if (cid) { 15 | $("[href='#"+cid+"']").addClass('active'); 16 | } 17 | }); 18 | }); 19 | 20 | /* 21 | * Anchor jump links. 22 | */ 23 | 24 | $document.on('flatdoc:ready', function() { 25 | $('.menu a').anchorjump(); 26 | }); 27 | 28 | /* 29 | * Title card. 30 | */ 31 | 32 | $(function() { 33 | var $card = $('.title-card'); 34 | if (!$card.length) return; 35 | 36 | var $header = $('.header'); 37 | var headerHeight = $header.length ? $header.outerHeight() : 0; 38 | 39 | $window 40 | .on('resize.title-card', function() { 41 | var windowWidth = $window.width(); 42 | 43 | if (windowWidth < 480) { 44 | $card.css('height', ''); 45 | } else { 46 | var height = $window.height(); 47 | $card.css('height', height - headerHeight); 48 | } 49 | }) 50 | .trigger('resize.title-card'); 51 | }); 52 | 53 | /* 54 | * Sidebar stick. 55 | */ 56 | 57 | $(function() { 58 | var $sidebar = $('.menubar'); 59 | var elTop; 60 | 61 | $window 62 | .on('resize.sidestick', function() { 63 | $sidebar.removeClass('fixed'); 64 | elTop = $sidebar.offset().top; 65 | $window.trigger('scroll.sidestick'); 66 | }) 67 | .on('scroll.sidestick', function() { 68 | var scrollY = $window.scrollTop(); 69 | $sidebar.toggleClass('fixed', (scrollY >= elTop)); 70 | }) 71 | .trigger('resize.sidestick'); 72 | }); 73 | 74 | })(jQuery); 75 | /*! jQuery.scrollagent (c) 2012, Rico Sta. Cruz. MIT License. 76 | * https://github.com/rstacruz/jquery-stuff/tree/master/scrollagent */ 77 | 78 | // Call $(...).scrollagent() with a callback function. 79 | // 80 | // The callback will be called everytime the focus changes. 81 | // 82 | // Example: 83 | // 84 | // $("h2").scrollagent(function(cid, pid, currentElement, previousElement) { 85 | // if (pid) { 86 | // $("[href='#"+pid+"']").removeClass('active'); 87 | // } 88 | // if (cid) { 89 | // $("[href='#"+cid+"']").addClass('active'); 90 | // } 91 | // }); 92 | 93 | (function($) { 94 | 95 | $.fn.scrollagent = function(options, callback) { 96 | // Account for $.scrollspy(function) 97 | if (typeof callback === 'undefined') { 98 | callback = options; 99 | options = {}; 100 | } 101 | 102 | var $sections = $(this); 103 | var $parent = options.parent || $(window); 104 | 105 | // Find the top offsets of each section 106 | var offsets = []; 107 | $sections.each(function(i) { 108 | var offset = $(this).attr('data-anchor-offset') ? 109 | parseInt($(this).attr('data-anchor-offset'), 10) : 110 | (options.offset || 0); 111 | 112 | offsets.push({ 113 | id: $(this).attr('id'), 114 | index: i, 115 | el: this, 116 | offset: offset 117 | }); 118 | }); 119 | 120 | // State 121 | var current = null; 122 | var height = null; 123 | var range = null; 124 | 125 | // Save the height. Do this only whenever the window is resized so we don't 126 | // recalculate often. 127 | $(window).on('resize', function() { 128 | height = $parent.height(); 129 | range = $(document).height(); 130 | }); 131 | 132 | // Find the current active section every scroll tick. 133 | $parent.on('scroll', function() { 134 | var y = $parent.scrollTop(); 135 | y += height * (0.3 + 0.7 * Math.pow(y/range, 2)); 136 | 137 | var latest = null; 138 | 139 | for (var i in offsets) { 140 | if (offsets.hasOwnProperty(i)) { 141 | var offset = offsets[i]; 142 | if ($(offset.el).offset().top + offset.offset < y) latest = offset; 143 | } 144 | } 145 | 146 | if (latest && (!current || (latest.index !== current.index))) { 147 | callback.call($sections, 148 | latest ? latest.id : null, 149 | current ? current.id : null, 150 | latest ? latest.el : null, 151 | current ? current.el : null); 152 | current = latest; 153 | } 154 | }); 155 | 156 | $(window).trigger('resize'); 157 | $parent.trigger('scroll'); 158 | 159 | return this; 160 | }; 161 | 162 | })(jQuery); 163 | /*! Anchorjump (c) 2012, Rico Sta. Cruz. MIT License. 164 | * http://github.com/rstacruz/jquery-stuff/tree/master/anchorjump */ 165 | 166 | // Makes anchor jumps happen with smooth scrolling. 167 | // 168 | // $("#menu a").anchorjump(); 169 | // $("#menu a").anchorjump({ offset: -30 }); 170 | // 171 | // // Via delegate: 172 | // $("#menu").anchorjump({ for: 'a', offset: -30 }); 173 | // 174 | // You may specify a parent. This makes it scroll down to the parent. 175 | // Great for tabbed views. 176 | // 177 | // $('#menu a').anchorjump({ parent: '.anchor' }); 178 | // 179 | // You can jump to a given area. 180 | // 181 | // $.anchorjump('#bank-deposit', options); 182 | 183 | (function($) { 184 | var defaults = { 185 | 'speed': 500, 186 | 'offset': 0, 187 | 'for': null, 188 | 'parent': null 189 | }; 190 | 191 | $.fn.anchorjump = function(options) { 192 | options = $.extend({}, defaults, options); 193 | 194 | if (options['for']) { 195 | this.on('click', options['for'], onClick); 196 | } else { 197 | this.on('click', onClick); 198 | } 199 | 200 | function onClick(e) { 201 | var $a = $(e.target).closest('a'); 202 | if (e.ctrlKey || e.metaKey || e.altKey || $a.attr('target')) return; 203 | 204 | e.preventDefault(); 205 | var href = $a.attr('href'); 206 | 207 | $.anchorjump(href, options); 208 | } 209 | }; 210 | 211 | // Jump to a given area. 212 | $.anchorjump = function(href, options) { 213 | options = $.extend({}, defaults, options); 214 | 215 | var top = 0; 216 | 217 | if (href != '#') { 218 | var $area = $(href); 219 | // Find the parent 220 | if (options.parent) { 221 | var $parent = $area.closest(options.parent); 222 | if ($parent.length) { $area = $parent; } 223 | } 224 | if (!$area.length) { return; } 225 | 226 | // Determine the pixel offset; use the default if not available 227 | var offset = 228 | $area.attr('data-anchor-offset') ? 229 | parseInt($area.attr('data-anchor-offset'), 10) : 230 | options.offset; 231 | 232 | top = Math.max(0, $area.offset().top + offset); 233 | } 234 | 235 | $('html, body').animate({ scrollTop: top }, options.speed); 236 | $('body').trigger('anchor', href); 237 | 238 | // Add the location hash via pushState. 239 | if (window.history.pushState) { 240 | window.history.pushState({ href: href }, "", href); 241 | } 242 | }; 243 | })(jQuery); 244 | -------------------------------------------------------------------------------- /Public/js/theme-gitignore-script.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var $window = $(window); 3 | var $document = $(document); 4 | 5 | /* 6 | * Scrollspy. 7 | */ 8 | 9 | $document.on('flatdoc:ready', function() { 10 | $("h2, h3").scrollagent(function(cid, pid, currentElement, previousElement) { 11 | if (pid) { 12 | $("[href='#" + pid + "']").removeClass('active'); 13 | } 14 | if (cid) { 15 | $("[href='#" + cid + "']").addClass('active'); 16 | } 17 | }); 18 | }); 19 | 20 | /* 21 | * Anchor jump links. 22 | */ 23 | 24 | $document.on('flatdoc:ready', function() { 25 | $('.menu a').anchorjump(); 26 | }); 27 | 28 | /* 29 | * Title card. 30 | */ 31 | 32 | $(function() { 33 | var $card = $('.title-card'); 34 | if (!$card.length) return; 35 | 36 | var $header = $('.header'); 37 | var headerHeight = $header.length ? $header.outerHeight() : 0; 38 | 39 | $window 40 | .on('resize.title-card', function() { 41 | var windowWidth = $window.width(); 42 | 43 | if (windowWidth < 480) { 44 | $card.css('height', ''); 45 | } else { 46 | var height = $window.height(); 47 | $card.css('height', height - headerHeight); 48 | } 49 | }) 50 | .trigger('resize.title-card'); 51 | }); 52 | 53 | /* 54 | * Sidebar stick. 55 | */ 56 | 57 | $(function() { 58 | var $sidebar = $('.menubar'); 59 | var elTop; 60 | 61 | $window 62 | .on('resize.sidestick', function() { 63 | $sidebar.removeClass('fixed'); 64 | elTop = $sidebar.offset().top; 65 | $window.trigger('scroll.sidestick'); 66 | }) 67 | .on('scroll.sidestick', function() { 68 | var scrollY = $window.scrollTop(); 69 | $sidebar.toggleClass('fixed', (scrollY >= elTop)); 70 | }) 71 | .trigger('resize.sidestick'); 72 | }); 73 | 74 | })(jQuery); 75 | /*! jQuery.scrollagent (c) 2012, Rico Sta. Cruz. MIT License. 76 | * https://github.com/rstacruz/jquery-stuff/tree/master/scrollagent */ 77 | 78 | // Call $(...).scrollagent() with a callback function. 79 | // 80 | // The callback will be called everytime the focus changes. 81 | // 82 | // Example: 83 | // 84 | // $("h2").scrollagent(function(cid, pid, currentElement, previousElement) { 85 | // if (pid) { 86 | // $("[href='#"+pid+"']").removeClass('active'); 87 | // } 88 | // if (cid) { 89 | // $("[href='#"+cid+"']").addClass('active'); 90 | // } 91 | // }); 92 | 93 | (function($) { 94 | 95 | $.fn.scrollagent = function(options, callback) { 96 | // Account for $.scrollspy(function) 97 | if (typeof callback === 'undefined') { 98 | callback = options; 99 | options = {}; 100 | } 101 | 102 | var $sections = $(this); 103 | var $parent = options.parent || $(window); 104 | 105 | // Find the top offsets of each section 106 | var offsets = []; 107 | $sections.each(function(i) { 108 | var offset = $(this).attr('data-anchor-offset') ? 109 | parseInt($(this).attr('data-anchor-offset'), 10) : 110 | (options.offset || 0); 111 | 112 | offsets.push({ 113 | top: $(this).offset().top + offset, 114 | id: $(this).attr('id'), 115 | index: i, 116 | el: this 117 | }); 118 | }); 119 | 120 | // State 121 | var current = null; 122 | var height = null; 123 | var range = null; 124 | 125 | // Save the height. Do this only whenever the window is resized so we don't 126 | // recalculate often. 127 | $(window).on('resize', function() { 128 | height = $parent.height(); 129 | range = $(document).height(); 130 | }); 131 | 132 | // Find the current active section every scroll tick. 133 | $parent.on('scroll', function() { 134 | var y = $parent.scrollTop(); 135 | y += height * (0.3 + 0.7 * Math.pow(y / range, 2)); 136 | 137 | var latest = null; 138 | 139 | for (var i in offsets) { 140 | if (offsets.hasOwnProperty(i)) { 141 | var offset = offsets[i]; 142 | if (offset.top < y) latest = offset; 143 | } 144 | } 145 | 146 | if (latest && (!current || (latest.index !== current.index))) { 147 | callback.call($sections, 148 | latest ? latest.id : null, 149 | current ? current.id : null, 150 | latest ? latest.el : null, 151 | current ? current.el : null); 152 | current = latest; 153 | } 154 | }); 155 | 156 | $(window).trigger('resize'); 157 | $parent.trigger('scroll'); 158 | 159 | return this; 160 | }; 161 | 162 | })(jQuery); 163 | /*! Anchorjump (c) 2012, Rico Sta. Cruz. MIT License. 164 | * http://github.com/rstacruz/jquery-stuff/tree/master/anchorjump */ 165 | 166 | // Makes anchor jumps happen with smooth scrolling. 167 | // 168 | // $("#menu a").anchorjump(); 169 | // $("#menu a").anchorjump({ offset: -30 }); 170 | // 171 | // // Via delegate: 172 | // $("#menu").anchorjump({ for: 'a', offset: -30 }); 173 | // 174 | // You may specify a parent. This makes it scroll down to the parent. 175 | // Great for tabbed views. 176 | // 177 | // $('#menu a').anchorjump({ parent: '.anchor' }); 178 | // 179 | // You can jump to a given area. 180 | // 181 | // $.anchorjump('#bank-deposit', options); 182 | 183 | (function($) { 184 | var defaults = { 185 | 'speed': 500, 186 | 'offset': 0, 187 | 'for': null, 188 | 'parent': null 189 | }; 190 | 191 | $.fn.anchorjump = function(options) { 192 | options = $.extend({}, defaults, options); 193 | 194 | if (options['for']) { 195 | this.on('click', options['for'], onClick); 196 | } else { 197 | this.on('click', onClick); 198 | } 199 | 200 | function onClick(e) { 201 | var $a = $(e.target).closest('a'); 202 | if (e.ctrlKey || e.metaKey || e.altKey || $a.attr('target')) return; 203 | 204 | e.preventDefault(); 205 | var href = $a.attr('href'); 206 | 207 | $.anchorjump(href, options); 208 | } 209 | }; 210 | 211 | // Jump to a given area. 212 | $.anchorjump = function(href, options) { 213 | options = $.extend({}, defaults, options); 214 | 215 | var top = 0; 216 | 217 | if (href != '#') { 218 | var $area = $(href); 219 | // Find the parent 220 | if (options.parent) { 221 | var $parent = $area.closest(options.parent); 222 | if ($parent.length) { 223 | $area = $parent; 224 | } 225 | } 226 | if (!$area.length) { 227 | return; 228 | } 229 | 230 | // Determine the pixel offset; use the default if not available 231 | var offset = 232 | $area.attr('data-anchor-offset') ? 233 | parseInt($area.attr('data-anchor-offset'), 10) : 234 | options.offset; 235 | 236 | top = Math.max(0, $area.offset().top + offset); 237 | } 238 | 239 | $('html, body').animate({ 240 | scrollTop: top 241 | }, options.speed); 242 | $('body').trigger('anchor', href); 243 | 244 | // Add the location hash via pushState. 245 | if (window.history.pushState) { 246 | window.history.pushState({ 247 | href: href 248 | }, "", href); 249 | } 250 | }; 251 | })(jQuery); 252 | -------------------------------------------------------------------------------- /Public/components/flatdoc/v/0.9.0/legacy.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | Support JS for legacy browsers. 4 | Includes: 5 | 6 | HTML5 Shiv 7 | @afarkas @jdalton @jon_neal @rem 8 | MIT/GPL2 Licensed 9 | https://github.com/aFarkas/html5shiv 10 | 11 | matchMedia() polyfill 12 | (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license 13 | 14 | Respond.js 15 | min/max-width media query polyfill 16 | (c) Scott Jehl. MIT/GPLv2 Lic. 17 | http://j.mp/respondjs 18 | 19 | */ 20 | !function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x";c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;!function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}}();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d #mq-test-1 { width: 42px; }';docElem.insertBefore(fakeBody,refNode);bool=div.offsetWidth===42;docElem.removeChild(fakeBody);return{matches:bool,media:q}}}(document);/*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 23 | !function(win){"use strict";var respond={};win.respond=respond;respond.update=function(){};respond.mediaQueriesSupported=win.matchMedia&&win.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var doc=win.document,docElem=doc.documentElement,mediastyles=[],rules=[],appendedEls=[],parsedSheets={},resizeThrottle=30,head=doc.getElementsByTagName("head")[0]||docElem,base=doc.getElementsByTagName("base")[0],links=head.getElementsByTagName("link"),requestQueue=[],ripCSS=function(){for(var i=0;i-1,minw:thisq.match(/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:thisq.match(/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}applyMedia()},lastCall,resizeDefer,getEmValue=function(){var ret,div=doc.createElement("div"),body=doc.body,fakeUsed=false;div.style.cssText="position:absolute;font-size:1em;width:1em";if(!body){body=fakeUsed=doc.createElement("body");body.style.background="none"}body.appendChild(div);docElem.insertBefore(body,docElem.firstChild);ret=div.offsetWidth;if(fakeUsed){docElem.removeChild(body)}else{body.removeChild(div)}ret=eminpx=parseFloat(ret);return ret},eminpx,applyMedia=function(fromResize){var name="clientWidth",docElemProp=docElem[name],currWidth=doc.compatMode==="CSS1Compat"&&docElemProp||doc.body[name]||docElemProp,styleBlocks={},lastLink=links[links.length-1],now=(new Date).getTime();if(fromResize&&lastCall&&now-lastCall-1?eminpx||getEmValue():1)}if(!!max){max=parseFloat(max)*(max.indexOf(em)>-1?eminpx||getEmValue():1)}if(!thisstyle.hasquery||(!minnull||!maxnull)&&(minnull||currWidth>=min)&&(maxnull||currWidth<=max)){if(!styleBlocks[thisstyle.media]){styleBlocks[thisstyle.media]=[]}styleBlocks[thisstyle.media].push(rules[thisstyle.rules])}}}for(var j in appendedEls){if(appendedEls.hasOwnProperty(j)){if(appendedEls[j]&&appendedEls[j].parentNode===head){head.removeChild(appendedEls[j])}}}for(var k in styleBlocks){if(styleBlocks.hasOwnProperty(k)){var ss=doc.createElement("style"),css=styleBlocks[k].join("\n");ss.type="text/css";ss.media=k;head.insertBefore(ss,lastLink.nextSibling);if(ss.styleSheet){ss.styleSheet.cssText=css}else{ss.appendChild(doc.createTextNode(css))}appendedEls.push(ss)}}},ajax=function(url,callback){var req=xmlHttp();if(!req){return}req.open("GET",url,true);req.onreadystatechange=function(){if(req.readyState!==4||req.status!==200&&req.status!==304){return}callback(req.responseText)};if(req.readyState===4){return}req.send(null)},xmlHttp=function(){var xmlhttpmethod=false;try{xmlhttpmethod=new win.XMLHttpRequest}catch(e){xmlhttpmethod=new win.ActiveXObject("Microsoft.XMLHTTP")}return function(){return xmlhttpmethod}}();ripCSS();respond.update=ripCSS;function callMedia(){applyMedia(true)}if(win.addEventListener){win.addEventListener("resize",callMedia,false)}else if(win.attachEvent){win.attachEvent("onresize",callMedia)}}(this); -------------------------------------------------------------------------------- /Public/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |
6 | Create useful .gitignore files for your project 7 |

8 |

9 | 10 | Travis 11 | Code Climate Test Coverage 12 | Code Climate Maintainability 13 | Platforms 14 | license 15 |

16 | 17 | ## `.gitignore` Template Source 18 | 19 | Source templates for gitignore.io can be found at https://github.com/dvcs/gitignore 20 | 21 | ## Install Command Line 22 | 23 | To run gitignore.io from your command line you need an active internet connection and an environment function. You need to add a function to your environment that lets you access the gitignore.io API. 24 | 25 | ### Git 26 | `#!/bin/bash` 27 | ```sh 28 | $ git config --global alias.ignore '!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi' 29 | ``` 30 | 31 | ### Linux 32 | `#!/bin/bash` 33 | ```sh 34 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bashrc && source ~/.bashrc 35 | ``` 36 | 37 | `#!/bin/zsh` 38 | ```sh 39 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.zshrc && source ~/.zshrc 40 | ``` 41 | 42 | `#!/bin/fish` 43 | ```sh 44 | $ printf "function gi\n\tcurl -L -s https://www.gitignore.io/api/\$argv\nend\n" > ~/.config/fish/functions/gi.fish 45 | ``` 46 | 47 | ### macOS 48 | `#!/bin/bash` 49 | ```sh 50 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bash_profile && source ~/.bash_profile 51 | ``` 52 | `#!/bin/zsh` 53 | ```sh 54 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.zshrc && source ~/.zshrc 55 | ``` 56 | 57 | `#!/bin/fish` 58 | ```sh 59 | $ printf "function gi\n\tcurl -L -s https://www.gitignore.io/api/\$argv\nend\n" > ~/.config/fish/functions/gi.fish 60 | ``` 61 | 62 | ### Windows 63 | Create a PowerShell v3 Script 64 | ```posh 65 | #For PowerShell v3 66 | Function gig { 67 | param( 68 | [Parameter(Mandatory=$true)] 69 | [string[]]$list 70 | ) 71 | $params = ($list | ForEach-Object { [uri]::EscapeDataString($_) }) -join "," 72 | Invoke-WebRequest -Uri "https://www.gitignore.io/api/$params" | select -ExpandProperty content | Out-File -FilePath $(Join-Path -path $pwd -ChildPath ".gitignore") -Encoding ascii 73 | } 74 | ``` 75 | Create a PowerShell v2 Script 76 | ```posh 77 | #For PowerShell v2 78 | Function gig { 79 | param( 80 | [Parameter(Mandatory=$true)] 81 | [string[]]$list 82 | ) 83 | $params = ($list | ForEach-Object { [uri]::EscapeDataString($_) }) -join "," 84 | $wc = New-Object System.Net.WebClient 85 | $wc.Headers["User-Agent"] = "PowerShell/" + $PSVersionTable["PSVersion"].ToString() 86 | $wc.DownloadFile("https://www.gitignore.io/api/$params", "$PWD\.gitignore") 87 | } 88 | ``` 89 | 90 | Create a Command Line Prompt Script 91 | If you have installed [msysgit](http://msysgit.github.io)), create `gi.cmd` with content below. And copy it to `C:\Program Files\Git\cmd\gi.cmd`, assuming `msysgit` was installed to `c:\Program Files\Git`. Make sure that `C:\Program Files\Git\cmd` is added to the environment variable `path`. 92 | ```bat 93 | @rem Do not use "echo off" to not affect any child calls. 94 | @setlocal 95 | 96 | @rem Get the abolute path to the parent directory, which is assumed to be the 97 | @rem Git installation root. 98 | @for /F "delims=" %%I in ("%~dp0..") do @set git_install_root=%%~fI 99 | @for /F "delims=" %%I in ("%~dp0..") do @set git_mingw_root=%%~fI\mingw 100 | @if not exist "%git_mingw_root%" @set git_mingw_root=%git_install_root%\mingw64 101 | @set PATH=%git_install_root%\bin;%git_mingw_root%\bin;%PATH% 102 | 103 | @if not exist "%HOME%" @set HOME=%HOMEDRIVE%%HOMEPATH% 104 | @if not exist "%HOME%" @set HOME=%USERPROFILE% 105 | 106 | @curl.exe -L -s https://www.gitignore.io/api/%* 107 | ``` 108 | ### Other Clients 109 | 110 | Clients maintained by third-party developers 111 | 112 | | Source Code | Language | Instructions | Maintainer | 113 | |---|---|---|---| 114 | | [gogi](https://github.com/Gnouc/gogi) | Go | [Install](https://github.com/Gnouc/gogi#installation) | [Cuong Manh Le](https://github.com/Gnouc) | 115 | | [ignr](https://github.com/Antrikshy/ignr.py) | Python | [Usage](https://github.com/Antrikshy/ignr.py#usage) | [Antriksh Yadav](https://github.com/Antrikshy) | 116 | | [add-gitignore](https://github.com/TejasQ/add-gitignore) | Node | [Usage](https://github.com/TejasQ/add-gitignore#usage) | [Tejas Kumar](https://github.com/TejasQ) | 117 | 118 | Tools or extensions maintained by third-party developers on other platforms 119 | 120 | | Source Code | Platform | Instructions | Maintainer 121 | |---|---|---|---| 122 | | [fzf-gitignore](https://github.com/fszymanski/fzf-gitignore) | Neovim | [Install](https://github.com/fszymanski/fzf-gitignore#installation) | [Filip Szymański](https://github.com/fszymanski) 123 | | [gi](https://marketplace.visualstudio.com/items?itemName=rubbersheep.gi) | Visual Studio Code | [Install](https://marketplace.visualstudio.com/items?itemName=rubbersheep.gi#install) | [Hasit Mistry](https://github.com/hasit/) 124 | | [helm-gitignore](https://github.com/jupl/helm-gitignore) | GNU Emacs | [Install](https://github.com/jupl/helm-gitignore#installation) | [Juan Placencia](https://github.com/jupl) 125 | 126 | ## Use Command Line 127 | 128 | After the function is created, the `gi` command will give you command line access to the gitignore.io API. . **Note:** Use `gig` if you are on Windows 129 | 130 | ### Preview 131 | Show output on the command line. **Note:** Use `gig` if you are on Windows 132 | ```sh 133 | $ gi linux,java 134 | # Created by https://www.gitignore.io 135 | 136 | ### Linux ### 137 | .* 138 | !.gitignore 139 | *~ 140 | 141 | ### Java ### 142 | *.class 143 | # Package Files # 144 | *.jar 145 | *.war 146 | *.ear 147 | ``` 148 | 149 | ### Global 150 | Append Operating System and IDE settings to global .gitignore. **Note:** Use `gig` if you are on Windows 151 | ```sh 152 | $ gi linux,eclipse >> ~/.gitignore_global 153 | ``` 154 | 155 | ### Project 156 | Appending Programming Language settings to your projects .gitignore. **Note:** Use `gig` if you are on Windows 157 | ```sh 158 | $ gi java,python >> .gitignore 159 | ``` 160 | 161 | ### List 162 | List displays a list of all of the currently support gitignore.io templates. **Note:** Use `gig` if you are on Windows 163 | ```sh 164 | $ gi list 165 | actionscript,ada,agda,android,appceleratortitanium,appcode,archives, 166 | archlinuxpackages,autotools,bancha,basercms,bower,bricxcc,c,c++,cakephp, 167 | cfwheels,chefcookbook,clojure,cloud9,cmake,codeigniter,codekit,commonlisp, 168 | compass,composer,concrete5,coq,cvs,dart,darteditor,delphi,django,dotsettings, 169 | dreamweaver,drupal,eagle,eclipse,elasticbeanstalk,elisp,elixir,emacs,ensime, 170 | episerver,erlang,espresso,expressionengine,fancy,finale,flexbuilder,forcedotcom, 171 | freepascal,fuelphp,gcov,go,gradle,grails,gwt,haskell,intellij,java,jboss,jekyll, 172 | jetbrains,joe,joomla,justcode,jython,kate,kdevelop4,kohana,komodoedit,laravel, 173 | latex,lazarus,leiningen,lemonstand,lilypond,linux,lithium,magento,matlab,maven, 174 | mercurial,meteor,modelsim,monodevelop,nanoc,netbeans,node,notepadpp,objective-c, 175 | ocaml,opa,opencart,openfoam,oracleforms,osx,perl,ph7cms,phpstorm,playframework, 176 | plone,prestashop,processing,pycharm,python,qooxdoo,qt,quartus2,r,rails,redcar, 177 | rhodesrhomobile,ros,ruby,rubymine,rubymotion,sass,sbt,scala,scrivener,sdcc, 178 | seamgen,senchatouch,silverstripe,sketchup,stella,sublimetext,sugarcrm,svn, 179 | symfony,symfony2,symphonycms,tags,target3001,tarmainstallmate,tasm,tex,textmate, 180 | textpattern,turbogears2,typo3,unity,vagrant,vim,virtualenv,visualstudio,vvvv, 181 | waf,wakanda,webmethods,webstorm,windows,wordpress,xamarinstudio,xcode,xilinxise, 182 | yeoman,yii,zendframework 183 | ``` 184 | 185 | ## Advanced Command Line Improvements 186 | 187 | Advanced command line suggestions are tracked on the [gitignore.io wiki](https://github.com/joeblau/gitignore.io/wiki/Advanced-Command-Line). 188 | 189 | ## Design 190 | 191 | | Asset | Description | 192 | | --- | --- | 193 | | | gitignore.io horizontal logo | 194 | | | gitignore.io square logo | 195 | 196 | ## Install Locally 197 | 198 | ### Requirements 199 | 200 | - **Vapor** - [macOS](https://vapor.github.io/documentation/getting-started/install-swift-3-macos.html) / [Linux](https://vapor.github.io/documentation/getting-started/install-swift-3-ubuntu.html) 201 | 202 | ## Instructions 203 | 204 | ```sh 205 | $ git clone --recursive git@github.com:joeblau/gitignore.io.git 206 | $ cd gitignore.io/ 207 | $ vapor build 208 | $ vapor run 209 | ``` 210 | 211 | ### Using Docker 212 | 213 | It's also possible to run the app using [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/). It can be done by running the commands below. 214 | 215 | ```sh 216 | $ git clone --recursive git@github.com:joeblau/gitignore.io.git 217 | $ cd gitignore.io/ 218 | $ docker-compose up -d 219 | ``` 220 | 221 | ## Companies 222 | 223 | Here are some companies that use gitignore.io: 224 | 225 | 226 | 227 | ## About 228 | 229 | .gitignore.io is a web service designed to help you create .gitignore files for 230 | your Git repositories. The site has a graphical and command line method of 231 | creating a .gitignore for your operating system, programming language, or IDE. 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |
6 | Create useful .gitignore files for your project 7 |

8 |

9 | 10 | Travis 11 | Code Climate Test Coverage 12 | Code Climate Maintainability 13 | Platforms 14 | license 15 |

16 | 17 | ## `.gitignore` Template Source 18 | 19 | Source templates for gitignore.io can be found at https://github.com/dvcs/gitignore 20 | 21 | ## Install Command Line 22 | 23 | To run gitignore.io from your command line you need an active internet connection and an environment function. You need to add a function to your environment that lets you access the gitignore.io API. 24 | 25 | ### Git 26 | `#!/bin/bash` 27 | ```sh 28 | $ git config --global alias.ignore '!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi' 29 | ``` 30 | 31 | ### Linux 32 | `#!/bin/bash` 33 | ```sh 34 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bashrc && source ~/.bashrc 35 | ``` 36 | 37 | `#!/bin/zsh` 38 | ```sh 39 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.zshrc && source ~/.zshrc 40 | ``` 41 | 42 | `#!/bin/fish` 43 | ```sh 44 | $ printf "function gi\n\tcurl -L -s https://www.gitignore.io/api/\$argv\nend\n" > ~/.config/fish/functions/gi.fish 45 | ``` 46 | 47 | ### macOS 48 | `#!/bin/bash` 49 | ```sh 50 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bash_profile && source ~/.bash_profile 51 | ``` 52 | `#!/bin/zsh` 53 | ```sh 54 | $ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.zshrc && source ~/.zshrc 55 | ``` 56 | 57 | `#!/bin/fish` 58 | ```sh 59 | $ printf "function gi\n\tcurl -L -s https://www.gitignore.io/api/\$argv\nend\n" > ~/.config/fish/functions/gi.fish 60 | ``` 61 | 62 | ### Windows 63 | Create a PowerShell v3 Script 64 | ```posh 65 | #For PowerShell v3 66 | Function gig { 67 | param( 68 | [Parameter(Mandatory=$true)] 69 | [string[]]$list 70 | ) 71 | $params = ($list | ForEach-Object { [uri]::EscapeDataString($_) }) -join "," 72 | Invoke-WebRequest -Uri "https://www.gitignore.io/api/$params" | select -ExpandProperty content | Out-File -FilePath $(Join-Path -path $pwd -ChildPath ".gitignore") -Encoding ascii 73 | } 74 | ``` 75 | Create a PowerShell v2 Script 76 | ```posh 77 | #For PowerShell v2 78 | Function gig { 79 | param( 80 | [Parameter(Mandatory=$true)] 81 | [string[]]$list 82 | ) 83 | $params = ($list | ForEach-Object { [uri]::EscapeDataString($_) }) -join "," 84 | $wc = New-Object System.Net.WebClient 85 | $wc.Headers["User-Agent"] = "PowerShell/" + $PSVersionTable["PSVersion"].ToString() 86 | $wc.DownloadFile("https://www.gitignore.io/api/$params", "$PWD\.gitignore") 87 | } 88 | ``` 89 | 90 | Create a Command Line Prompt Script 91 | If you have installed [msysgit](http://msysgit.github.io)), create `gi.cmd` with content below. And copy it to `C:\Program Files\Git\cmd\gi.cmd`, assuming `msysgit` was installed to `c:\Program Files\Git`. Make sure that `C:\Program Files\Git\cmd` is added to the environment variable `path`. 92 | ```bat 93 | @rem Do not use "echo off" to not affect any child calls. 94 | @setlocal 95 | 96 | @rem Get the abolute path to the parent directory, which is assumed to be the 97 | @rem Git installation root. 98 | @for /F "delims=" %%I in ("%~dp0..") do @set git_install_root=%%~fI 99 | @for /F "delims=" %%I in ("%~dp0..") do @set git_mingw_root=%%~fI\mingw 100 | @if not exist "%git_mingw_root%" @set git_mingw_root=%git_install_root%\mingw64 101 | @set PATH=%git_install_root%\bin;%git_mingw_root%\bin;%PATH% 102 | 103 | @if not exist "%HOME%" @set HOME=%HOMEDRIVE%%HOMEPATH% 104 | @if not exist "%HOME%" @set HOME=%USERPROFILE% 105 | 106 | @curl.exe -L -s https://www.gitignore.io/api/%* 107 | ``` 108 | ### Other Clients 109 | 110 | Clients maintained by third-party developers 111 | 112 | | Source Code | Language | Instructions | Maintainer | 113 | |---|---|---|---| 114 | | [gogi](https://github.com/Gnouc/gogi) | Go | [Install](https://github.com/Gnouc/gogi#installation) | [Cuong Manh Le](https://github.com/Gnouc) | 115 | | [ignr](https://github.com/Antrikshy/ignr.py) | Python | [Usage](https://github.com/Antrikshy/ignr.py#usage) | [Antriksh Yadav](https://github.com/Antrikshy) | 116 | | [add-gitignore](https://github.com/TejasQ/add-gitignore) | Node | [Usage](https://github.com/TejasQ/add-gitignore#usage) | [Tejas Kumar](https://github.com/TejasQ) | 117 | | [git-ignore](https://github.com/sondr3/git-ignore) | Rust | [Usage](https://github.com/sondr3/git-ignore#installation) | [Sondre Nilsen](https://github.com/sondr3) | 118 | 119 | Tools or extensions maintained by third-party developers on other platforms 120 | 121 | | Source Code | Platform | Instructions | Maintainer 122 | |---|---|---|---| 123 | | [fzf-gitignore](https://github.com/fszymanski/fzf-gitignore) | Neovim | [Install](https://github.com/fszymanski/fzf-gitignore#installation) | [Filip Szymański](https://github.com/fszymanski) 124 | | [gi](https://marketplace.visualstudio.com/items?itemName=rubbersheep.gi) | Visual Studio Code | [Install](https://marketplace.visualstudio.com/items?itemName=rubbersheep.gi#install) | [Hasit Mistry](https://github.com/hasit/) 125 | | [helm-gitignore](https://github.com/jupl/helm-gitignore) | GNU Emacs | [Install](https://github.com/jupl/helm-gitignore#installation) | [Juan Placencia](https://github.com/jupl) 126 | 127 | ## Use Command Line 128 | 129 | After the function is created, the `gi` command will give you command line access to the gitignore.io API. . **Note:** Use `gig` if you are on Windows 130 | 131 | ### Preview 132 | Show output on the command line. **Note:** Use `gig` if you are on Windows 133 | ```sh 134 | $ gi linux,java 135 | # Created by https://www.gitignore.io 136 | 137 | ### Linux ### 138 | .* 139 | !.gitignore 140 | *~ 141 | 142 | ### Java ### 143 | *.class 144 | # Package Files # 145 | *.jar 146 | *.war 147 | *.ear 148 | ``` 149 | 150 | ### Global 151 | Append Operating System and IDE settings to global .gitignore. **Note:** Use `gig` if you are on Windows 152 | ```sh 153 | $ gi linux,eclipse >> ~/.gitignore_global 154 | ``` 155 | 156 | ### Project 157 | Appending Programming Language settings to your projects .gitignore. **Note:** Use `gig` if you are on Windows 158 | ```sh 159 | $ gi java,python >> .gitignore 160 | ``` 161 | 162 | ### List 163 | List displays a list of all of the currently support gitignore.io templates. **Note:** Use `gig` if you are on Windows 164 | ```sh 165 | $ gi list 166 | actionscript,ada,agda,android,appceleratortitanium,appcode,archives, 167 | archlinuxpackages,autotools,bancha,basercms,bower,bricxcc,c,c++,cakephp, 168 | cfwheels,chefcookbook,clojure,cloud9,cmake,codeigniter,codekit,commonlisp, 169 | compass,composer,concrete5,coq,cvs,dart,darteditor,delphi,django,dotsettings, 170 | dreamweaver,drupal,eagle,eclipse,elasticbeanstalk,elisp,elixir,emacs,ensime, 171 | episerver,erlang,espresso,expressionengine,fancy,finale,flexbuilder,forcedotcom, 172 | freepascal,fuelphp,gcov,go,gradle,grails,gwt,haskell,intellij,java,jboss,jekyll, 173 | jetbrains,joe,joomla,justcode,jython,kate,kdevelop4,kohana,komodoedit,laravel, 174 | latex,lazarus,leiningen,lemonstand,lilypond,linux,lithium,magento,matlab,maven, 175 | mercurial,meteor,modelsim,monodevelop,nanoc,netbeans,node,notepadpp,objective-c, 176 | ocaml,opa,opencart,openfoam,oracleforms,osx,perl,ph7cms,phpstorm,playframework, 177 | plone,prestashop,processing,pycharm,python,qooxdoo,qt,quartus2,r,rails,redcar, 178 | rhodesrhomobile,ros,ruby,rubymine,rubymotion,sass,sbt,scala,scrivener,sdcc, 179 | seamgen,senchatouch,silverstripe,sketchup,stella,sublimetext,sugarcrm,svn, 180 | symfony,symfony2,symphonycms,tags,target3001,tarmainstallmate,tasm,tex,textmate, 181 | textpattern,turbogears2,typo3,unity,vagrant,vim,virtualenv,visualstudio,vvvv, 182 | waf,wakanda,webmethods,webstorm,windows,wordpress,xamarinstudio,xcode,xilinxise, 183 | yeoman,yii,zendframework 184 | ``` 185 | 186 | ## Advanced Command Line Improvements 187 | 188 | Advanced command line suggestions are tracked on the [gitignore.io wiki](https://github.com/joeblau/gitignore.io/wiki/Advanced-Command-Line). 189 | 190 | ## Design 191 | 192 | | Asset | Description | 193 | | --- | --- | 194 | | | gitignore.io horizontal logo | 195 | | | gitignore.io square logo | 196 | 197 | ## Install Locally 198 | 199 | ### Requirements 200 | 201 | - **Vapor** - [macOS](https://vapor.github.io/documentation/getting-started/install-swift-3-macos.html) / [Linux](https://vapor.github.io/documentation/getting-started/install-swift-3-ubuntu.html) 202 | 203 | ## Instructions 204 | 205 | ```sh 206 | $ git clone --recursive git@github.com:joeblau/gitignore.io.git 207 | $ cd gitignore.io/ 208 | $ vapor build 209 | $ vapor run 210 | ``` 211 | 212 | ### Using Docker 213 | 214 | It's also possible to run the app using [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/). It can be done by running the commands below. 215 | 216 | ```sh 217 | $ git clone --recursive git@github.com:joeblau/gitignore.io.git 218 | $ cd gitignore.io/ 219 | $ docker-compose up -d 220 | ``` 221 | 222 | ## Companies 223 | 224 | Here are some companies that use gitignore.io: 225 | 226 | 227 | 228 | ## About 229 | 230 | .gitignore.io is a web service designed to help you create .gitignore files for 231 | your Git repositories. The site has a graphical and command line method of 232 | creating a .gitignore for your operating system, programming language, or IDE. 233 | -------------------------------------------------------------------------------- /Public/components/select2/dist/css/select2.min.css: -------------------------------------------------------------------------------- 1 | .select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;height:1px !important;margin:-1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} 2 | --------------------------------------------------------------------------------