Repository: toptal/gitignore.io Branch: master Commit: fd3331d935ac Files: 97 Total size: 314.8 KB Directory structure: gitextract_u0sne320/ ├── .dockerignore ├── .github/ │ ├── CODEOWNERS │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE.md │ ├── dependabot.yml │ └── workflows/ │ ├── close-inactive.yaml │ └── update-templates.yml ├── .gitignore ├── .gitmodules ├── .swift-version ├── .swiftlint.yml ├── .travis/ │ ├── ci.sh │ └── update-submodule.sh ├── Dockerfile ├── LICENSE.md ├── Localizations/ │ ├── README.md │ ├── ar.json │ ├── cs.json │ ├── de.json │ ├── el.json │ ├── en.json │ ├── fa.json │ ├── fr.json │ ├── id.json │ ├── ja.json │ ├── ko.json │ ├── nl.json │ ├── pt.json │ ├── ro.json │ ├── ru.json │ ├── th.json │ ├── tr.json │ └── zh.json ├── Package.pins ├── Package.resolved ├── Package.swift ├── Procfile ├── Public/ │ ├── assets/ │ │ ├── main.css │ │ └── main.js │ ├── fonts/ │ │ ├── ProximaNova-Bold.otf │ │ ├── ProximaNova-Light.otf │ │ ├── ProximaNova-Regular.otf │ │ ├── ProximaNova-Semibold.otf │ │ └── ProximaNova-Thin.otf │ └── sitemap.xml ├── README.md ├── Resources/ │ ├── Views/ │ │ ├── index.leaf │ │ └── internal-linking.leaf │ └── links.json ├── Sources/ │ ├── App/ │ │ ├── Controllers/ │ │ │ ├── InternalLinkingController.swift │ │ │ ├── ReadOnlyTemplateManagerProtocol.swift │ │ │ └── TemplateController.swift │ │ ├── Enum/ │ │ │ └── TemplateSuffix.swift │ │ ├── Extensions/ │ │ │ ├── Dictionary+Extensions.swift │ │ │ ├── FileManager+Extensions.swift │ │ │ ├── Router+Extensions.swift │ │ │ ├── Sequence+Extensions.swift │ │ │ ├── String+Extensions.swift │ │ │ └── URL+Extensions.swift │ │ ├── Middleware/ │ │ │ └── FileMiddlewareWithBasePrefix.swift │ │ ├── Models/ │ │ │ ├── Dropdown.swift │ │ │ ├── Flags.swift │ │ │ ├── IgnoreTemplateModel.swift │ │ │ ├── IgnoreTemplateModeling.swift │ │ │ └── InternalLink.swift │ │ ├── RouteHandlers/ │ │ │ ├── APIRouteHandlers.swift │ │ │ ├── SiteRouteHandlers.swift │ │ │ └── UrlResolver.swift │ │ └── Server.swift │ └── Run/ │ └── main.swift ├── Tests/ │ ├── AppTests/ │ │ ├── Controllers/ │ │ │ └── TemplateControllerTests.swift │ │ ├── Extensions/ │ │ │ ├── Sequence+ExtensionsTest.swift │ │ │ ├── String+ExtensionsTests.swift │ │ │ └── URL+ExtensionsTests.swift │ │ ├── Models/ │ │ │ └── IgnoreTemplateModelTests.swift │ │ └── RouteHandlers/ │ │ ├── APIHandlersTests.swift │ │ └── SiteHandlersTests.swift │ └── LinuxMain.swift ├── app.json ├── docker-compose-dev.yml ├── docker-compose.yml ├── e2e-tests/ │ ├── api/ │ │ ├── index.test.js │ │ └── show.test.js │ ├── pages/ │ │ └── homepage.test.js │ └── utils/ │ └── templates.js ├── jest-puppeteer.config.js ├── jest.config.js ├── package.json ├── src/ │ ├── css/ │ │ └── bootstrap-extract.css │ ├── index.js │ ├── js/ │ │ └── app.js │ └── less/ │ ├── app.less │ ├── internal-linking.less │ ├── select2-toptal-theme.less │ └── variables.less └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ Packages .build ================================================ FILE: .github/CODEOWNERS ================================================ * @toptal/external-sites ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge 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. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities 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. 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. ## Scope 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. ## Enforcement 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. 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. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Vision 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. ## Ways You Can Help 1. **Add Templates** - Add templates for Programming Languages, Operating Systems and IDEs at [@toptal/gitignore](https://github.com/toptal/gitignore) 2. **Explore** - Create better ways for users to interact with gitignore.io. ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ # Issue Template ## Frequently Asked Questions **Q:** How do I submit a new .gitignore templates? **A:** Please submit all new templates to [@toptal/gitignore](https://github.com/toptal/gitignore). **Q:** How do I suggest modifications to existing `.gitignore` templates? **A:** Modifictions should come in the form of pull requests at [@toptal/gitignore](https://github.com/toptal/gitignore). **Q:** Why don't Gitignore.io's templates don't look exactly like the templates on [@github/gitignore](https://github.com/github/gitignore)? **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. **Q:** Why is my local site empty? **A:** When the repository is cloned, the `--recursive` flag is necessary. gitignore.io uses [@toptal/gitignore](https://github.com/toptal/gitignore) as its data source. If the repo isn't cloned recursively, templates will be missing. ## Issue ### Development Environment: - [ ] Machine (Local, Container, Virtual): - [ ] Operating System (Name/Version): - [ ] Web Browser (Name/Version): - [ ] Vapor Version: - [ ] Swift Version: ### Expected Behavior: ### Actual Behavior: ### Reproduction Steps: ================================================ FILE: .github/dependabot.yml ================================================ version: 2 registries: docker-registry-gcr-io: type: docker-registry url: https://gcr.io username: _json_key password: "${{secrets.DOCKER_REGISTRY_GCR_IO_PASSWORD}}" updates: - package-ecosystem: docker directory: "/" schedule: interval: daily time: "07:00" pull-request-branch-name: separator: "-" open-pull-requests-limit: 10 registries: - docker-registry-gcr-io ================================================ FILE: .github/workflows/close-inactive.yaml ================================================ name: Close inactive issues and PRs on: workflow_dispatch: schedule: - cron: "30 1 * * *" jobs: close-stale: runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: actions/stale@v6 with: days-before-stale: 30 days-before-close: 14 stale-issue-label: "stale" stale-pr-label: "stale" exempt-issue-labels: backlog,triage,nostale exempt-pr-labels: backlog,triage,nostale stale-pr-message: "This PR is stale because it has been open for 30 days with no activity." close-pr-message: "This PR was closed because it has been inactive for 14 days since being marked as stale." stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." repo-token: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/update-templates.yml ================================================ name: Update Templates on: workflow_dispatch: jobs: build: runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v3 - name: Sync Templates run: | git submodule update --init cd gitignore git pull origin master - name: Create Pull Request uses: peter-evans/create-pull-request@v4 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: Sync Templates Submodule title: Sync Templates Submodule branch: sync_templates base: master ================================================ FILE: .gitignore ================================================ # Created by https://www.gitignore.io/api/macos,linux,windows,vapor ### Linux ### *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* ### macOS ### *.DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ### Vapor ### Config/secrets ### Vapor Patch ### Packages .build xcuserdata *.xcodeproj ### Windows ### # Windows thumbnail cache files Thumbs.db ehthumbs.db ehthumbs_vista.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msm *.msp # Windows shortcuts *.lnk .git/credentials cobertura.xml # End of https://www.gitignore.io/api/macos,linux,windows,vapor node_modules/ *.swp yarn-error.log .yarn/cache .yarn/unplugged .yarn/build-state.yml .pnp.* .idea ================================================ FILE: .gitmodules ================================================ [submodule "gitignore"] path = gitignore url = https://github.com/toptal/gitignore.git ================================================ FILE: .swift-version ================================================ 4.1 ================================================ FILE: .swiftlint.yml ================================================ disabled_rules: # rule identifiers to exclude from running - colon - comma - control_statement - line_length opt_in_rules: # some rules are only opt-in - empty_count # Find all the available rules by running: # swiftlint rules included: # paths to include during linting. `--path` is ignored if present. - Sources/App - Sources/GitignoreIOServer excluded: # paths to ignore during linting. Takes precedence over `included`. # configurable rules can be customized from this configuration file # binary rules can set their severity level force_cast: warning # implicitly force_try: severity: warning # explicitly # rules that have both warning and error levels, can set just the warning level # implicitly # line_length: 110 # they can set both implicitly with an array type_body_length: - 300 # warning - 400 # error # or they can set both explicitly file_length: warning: 500 error: 1200 # naming rules can set warnings/errors for min_length and max_length # additionally they can set excluded names type_name: min_length: 4 # only warning max_length: # warning and error warning: 40 error: 50 excluded: iPhone # excluded via string identifier_name: min_length: # only min_length error: 3 # only error excluded: # excluded via string array - id - URL - GlobalAPIKey reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit) cyclomatic_complexity: warning: 30 error: 50 function_parameter_count: warning: 7 error: 11 ================================================ FILE: .travis/ci.sh ================================================ #!/usr/bin/env bash VERSION="4.1" echo "Swift $VERSION Continuous Integration"; # Determine OS UNAME=`uname`; if [[ $UNAME == "Darwin" ]]; then OS="macos"; else if [[ $UNAME == "Linux" ]]; then UBUNTU_RELEASE=`lsb_release -a 2>/dev/null`; if [[ $UBUNTU_RELEASE == *"16.04"* ]]; then OS="ubuntu1604"; else OS="ubuntu1404"; fi else echo "Unsupported Operating System: $UNAME"; fi fi echo "🖥 Operating System: $OS"; if [[ $OS != "macos" ]]; then echo "📚 Installing Dependencies" sudo apt-get install -y clang libicu-dev uuid-dev echo "🐦 Installing Swift"; if [[ $OS == "ubuntu1604" ]]; then SWIFTFILE="swift-$VERSION-RELEASE-ubuntu16.04"; else SWIFTFILE="swift-$VERSION-RELEASE-ubuntu14.04"; fi wget https://swift.org/builds/swift-$VERSION-release/$OS/swift-$VERSION-RELEASE/$SWIFTFILE.tar.gz tar -zxf $SWIFTFILE.tar.gz export PATH=$PWD/$SWIFTFILE/usr/bin:"${PATH}" fi echo "📅 Version: `swift --version`"; echo "🚀 Building"; swift build if [[ $? != 0 ]]; then echo "❌ Build failed"; exit 1; fi echo "💼 Building Release"; swift build -c release if [[ $? != 0 ]]; then echo "❌ Build for release failed"; exit 1; fi echo "🔎 Testing"; swift test if [[ $? != 0 ]]; then echo "❌ Tests failed"; exit 1; fi echo "✅ Done" ================================================ FILE: .travis/update-submodule.sh ================================================ #!/bin/bash cd gitignore git pull origin master cd .. pwd if [[ `git status --porcelain` ]]; then echo "status: Updating templates" git add . git commit -m "Upading templates from https://github.com/toptal/gitignore" else echo "status: No updates" fi ================================================ FILE: Dockerfile ================================================ ############################################################################################################################## ## ## ## We recommend building with buildx: ## ## ## ## // Note: you can use the standard `docker build` command, but there is no multi-CPU architecture support ## ## ## ## // Create buildx instance ## ## docker buildx create --driver docker-container --name builder --bootstrap --use ## ## ## ## // Login to Rregistry ## ## docker login [REGSITRY_ADDRESS] ## ## ## ## // Build the docker image (both x86 and amd64 are supported) ## ## docker buildx build --platform=linux/amd64,linux/arm64 --push -t [REGSITRY_ADDRESS]/REGSITRY_USERNAME/gitignore.io . ## ## ## ############################################################################################################################## # Build swift backend FROM swift:5.6-focal AS swift-builder COPY . /gitignore.io WORKDIR /gitignore.io RUN set -ex \ && apt update \ && apt install libssl-dev -y \ && swift package clean \ && swift package update \ && swift build -Xswiftc -static-stdlib -j $(nproc) -c release \ && mv $(swift build -Xswiftc -static-stdlib -c release --show-bin-path)/Run /tmp/Run # Build node frontend FROM node:lts AS node-builder COPY . /gitignore.io WORKDIR /gitignore.io RUN set -ex \ && yarn install \ && yarn build \ && rm -rf node_modules # Build final image FROM debian:stable-slim AS dest WORKDIR /app # The environment variable is set to empty(use the default value) ARG HOST_ORIGIN ARG BASE_PREFIX ARG GOOGLE_ANALYTICS_UID # Copy the project and remove the node frontend COPY . ./ COPY .git ./ # Install some necessary dependencies RUN set -ex \ && apt update \ && apt install git ca-certificates libcurl4 dumb-init --no-install-recommends -y \ && git submodule update --init --recursive \ && rm -rf /app/Public /app/Resources \ && apt autoremove -y \ && apt autoclean -y # Copy all newly compiled files to the final image COPY --from=swift-builder /tmp/Run /app/Run COPY --from=node-builder /gitignore.io/Public /app/Public COPY --from=node-builder /gitignore.io/Resources /app/Resources EXPOSE 8080/tcp # Add dump-init to ensure container can respond to exit signals ENTRYPOINT ["/usr/bin/dumb-init", "--"] # System signals are taken over by dump-init, we can use `exec` to execute # commands without worrying about signal forwarding and zombie processes # See Also: https://docs.docker.com/engine/reference/builder/#cmd CMD ["/app/Run", "serve", "-e", "prod", "-b", "0.0.0.0"] ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2013-2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Localizations/README.md ================================================ # Localizations 1. Copy the `en.json` file and rename it _use the base version of the language (en) instead of a country specific version (en_US)_ 2. Replace the strings with the language you're translating 3. Add the language to `Sources/App/Extensions/Router+Extensions.swift` under `supportedLanguages` 4. Create a pull request to get your translation approved and merged Thank you for help with localizing gitignore ================================================ FILE: Localizations/ar.json ================================================ { "title": "إنشاء ملفات .gitignore مفيدة لمشروعك - gitignore.io", "description": "Create useful .gitignore files for your project by selecting from %{templateCount} Operating System, IDE, and Programming Language .gitignore templates", "subtitle": "إنشاء ملفات .gitignore مفيدة لمشروعك", "searchPlaceholder": "ابحث عن أنظمة تشغيل، IDEs، أو لغات برمجة", "searchGo": "إنشاء", "searchDownload": "تحميل ملف", "footer": "قوالب نظام تشغيل، IDE، ولغة برمجة لملف .gitignore %{templateCount}", "commandLineTitle": "توثيق سطر اﻷوامر", "commandLineDescription": "تعلم كيفية تشغيل .gitignore.io من سطر اﻷوامر", "videoTitle": "مشاهدة مقطع فيديو تعليمي", "videoDescription": "مشاهدة فيديو تعليمي حول كيفية عمل .gitignore.io", "sourceCodeTitle": "شفرة مصدرية", "sourceCodeDescription": "الشفرة المصدرية لـ.gitignore.io مستضافة على GitHub" } ================================================ FILE: Localizations/cs.json ================================================ { "title": "gitignore.io - Vytvořte užitečný soubory .gitignore pro váš projekt", "description": "Vytvořte užitečné soubory .gitignore pro svůj projekt výběrem z %{templateCount}. Šablony .gitignore pro operační systém, IDE a programovací jazyk.", "subtitle": "Vytvořte užitečné soubory .gitignore pro svůj projekt", "searchPlaceholder": "Hledání operačních systémů, IDE nebo programovacích jazyků", "searchGo": "Vytvořit", "searchDownload": "Soubor ke stažení", "footer": "%{templateCount} šablon .gitignore pro operační systémy, IDE a programovací jazyky", "commandLineTitle": "Dokumentace příkazového řádku", "commandLineDescription": "Naučte se spouštět soubor .gitignore.io z příkazového řádku", "videoTitle": "Podívejte se na video tutoriál", "videoDescription": "Podívejte se na video, ve kterém se dozvíte, jak .gitignore.io funguje.", "sourceCodeTitle": "Zdrojový kód", "sourceCodeDescription": "Zdrojový kód pro .gitignore.io hostovaný na GitHub" } ================================================ FILE: Localizations/de.json ================================================ { "title": "gitignore.io - Erstelle nützliche .gitignore Dateien Für Dein Projekt", "description": "Erstelle nützliche .gitignore Dateien für dein Projekt in dem du eines von {templateCount} Betriebssystem, Entwicklungsumgebung und Programmiersprache .gitignore Templates wählst", "subtitle": "Erstelle nützliche .gitignore Dateien für dein Projekt", "searchPlaceholder": "Suche nach Betriebssystemen, Entwicklungsumgebungen oder Programmiersprachen", "searchGo": "Create", "searchDownload": "Datei herunterladen", "footer": "%{templateCount} Betriebssystem, Entwicklungsumgebung und Programmiersprache .gitignore Templates", "commandLineTitle": "Kommandozeilen Dokumentation", "commandLineDescription": "Lerne wie man .gitignore.io von der Kommandozeile ausführt", "videoTitle": "Schau das Video Tutorial", "videoDescription": "Schau ein Video um zu lernen wie .gitignore.io funktioniert", "sourceCodeTitle": "Quellcode", "sourceCodeDescription": "Der Quellcode für .gitignore.io ist bei Github gehosted" } ================================================ FILE: Localizations/el.json ================================================ { "title": "gitignore.io - Δημιουργήστε χρήσιμα αρχεία .gitignore για το έργο σας", "description": "Δημιουργήστε χρήσιμα αρχεία .gitignore για το έργο σας επιλέγοντας από το %{templateCount} πρότυπα .gitignore για λειτουργικό σύστημα, IDE και γλώσσα προγραμματισμού", "subtitle": "Δημιουργήστε χρήσιμα αρχεία .gitignore για το έργο σας", "searchPlaceholder": "Αναζήτηση λειτουργικών συστημάτων, IDEs ή γλωσσών προγραμματισμού", "searchGo": "Δημιουργήστε", "searchDownload": "Κατεβάστε το αρχείο", "footer": "%{templateCount} λειτουργικό σύστημα, IDE και γλώσσα προγραμματισμού .gitignore templates", "commandLineTitle": "Command line τεκμηρίωση", "commandLineDescription": "Μάθετε πώς να εκτελείτε το .gitignore.io από τη command line", "videoTitle": "Παρακολουθήστε εκπαιδευτικό βίντεο", "videoDescription": "Παρακολουθήστε ένα βίντεο για να μάθετε πώς λειτουργεί το .gitignore.io", "sourceCodeTitle": "Πηγαίος κώδικας", "sourceCodeDescription": "Πηγαίος κώδικας στο GitHub για το .gitignore.io" } ================================================ FILE: Localizations/en.json ================================================ { "title": "gitignore.io - Create Useful .gitignore Files For Your Project", "description": "Create useful .gitignore files for your project by selecting from %{templateCount} Operating System, IDE, and Programming Language .gitignore templates", "subtitle": "Create useful .gitignore files for your project", "searchPlaceholder": "Search Operating Systems, IDEs, or Programming Languages", "searchGo": "Create", "searchDownload": "Download File", "footer": "%{templateCount} Operating System, IDE, and Programming Language .gitignore templates", "commandLineTitle": "Command Line Docs", "commandLineDescription": "Learn how to run .gitignore.io from the command line", "videoTitle": "Watch Video Tutorial", "videoDescription": "Watch a video to learn how .gitignore.io works", "sourceCodeTitle": "Source Code", "sourceCodeDescription": "GitHub hosted source code for .gitignore.io" } ================================================ FILE: Localizations/fa.json ================================================ { "title": "gitignore.io - فایل های .gitignore پروژه تان را بسازید", "description": "فایل های .gitignore پروژه تان را با استفاده از %{templateCount} قالب بنا به سیستم عامل، IDE و زیان برنامه نویسی بسازید.", "subtitle": "فایل های .gitignore پروژه تان را بسازید", "searchPlaceholder": "سیستم عامل، IDE و یا زبان برنامه نویسی تان را جستجو کنید.", "searchGo": "ایجاد", "searchDownload": "دانلود فایل", "footer": "%{templateCount} قالب سیستم عامل، IDE و زبان برنامه نویسی", "commandLineTitle": "مستندات خط فرمان", "commandLineDescription": "آموزش چگونگی استفاده از .gitignore.io در خط فرمان", "videoTitle": "تماشای ویدئو آموزشی", "videoDescription": "تماشای ویدئو آموزشی برای اینکه بدانیم .gitignore.io چگونه کار می کند.", "sourceCodeTitle": "منبع کد", "sourceCodeDescription": "میزبانی شده توسط Github" } ================================================ FILE: Localizations/fr.json ================================================ { "title": "gitignore.io - Créez des fichiers .gitignore utiles à votre Projet", "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", "subtitle": "Créez des fichiers .gitignore utiles à votre projet", "searchPlaceholder": "Recherchez des Systèmes d'Exploitation, IDEs ou Langages de Programmation", "searchGo": "Créer", "searchDownload": "Téléchargement du fichier", "footer": "%{templateCount} templates .gitignore.io de Système d'exploitation, IDE et Langage de Programmation", "commandLineTitle": "Documentation", "commandLineDescription": "Apprenez comment utiliser .gitignore.io en ligne de commande", "videoTitle": "Regardez une Vidéo Didacticielle", "videoDescription": "Regardez une vidéo pour apprendre comment fonctionne .gitignore.io", "sourceCodeTitle": "Code Source", "sourceCodeDescription": "Le code source de .gitignore.io est hébergé par GitHub" } ================================================ FILE: Localizations/id.json ================================================ { "title": "gitignore.io - Buat File .gitignore yang Berguna untuk Proyek Anda", "description": "Buat file .gitignore yang berguna untuk proyek anda dengan memilih template .gitginore dari %{templateCount} Sistem Operasi, IDE, dan Bahasa Pemrograman", "subtitle": "Buat file .gitignore yang berguna untuk proyek anda", "searchPlaceholder": "Cari Sistem Operasi, IDE, atau Bahasa Pemrograman", "searchGo": "Buat", "searchDownload": "Mengunduh File", "footer": "template .gitignore %{templateCount} Sistem Operasi, IDE, dan Bahasa Pemrograman", "commandLineTitle": "Dokumentasi Command Line", "commandLineDescription": "Pelajari cara menjalankan .gitignore.io dari Command Line", "videoTitle": "Menonton Video Tutorial", "videoDescription": "Menonton video untuk mempelajari bagaimana .gitignore.io bekerja", "sourceCodeTitle": "Kode Sumber", "sourceCodeDescription": "GitHub menghosting kode sumber untuk .gitignore.io" } ================================================ FILE: Localizations/ja.json ================================================ { "title": "gitignore.io - プロジェクトに役立つ.gitignoreファイルを作成しよう", "description": "%{templateCount} オペレーティングシステム、IDE、およびプログラミング言語の.gitignoreテンプレートから選択して、プロジェクトに役立つ.gitignoreファイルを作成しよう。", "subtitle": "プロジェクトに役立つ.gitignoreファイルを作成しよう", "searchPlaceholder": "オペレーティングシステム、IDE、プログラミング言語を検索する", "searchGo": "作成する", "searchDownload": "ファイルをダウンロードする", "footer": "%{templateCount} オペレーティングシステム、IDE、プログラミング言語の.gitignoreテンプレート", "commandLineTitle": "コマンドライン ドキュメンテーション", "commandLineDescription": "コマンドラインから.gitignore.ioを実行する方法を学ぶ", "videoTitle": "チュートリアルビデオを見る", "videoDescription": ".gitignore.ioの使い方を学ぶためにビデオを見る", "sourceCodeTitle": "ソースコード", "sourceCodeDescription": "GitHubでホスティングされた.gitignore.ioのソースコード" } ================================================ FILE: Localizations/ko.json ================================================ { "title": "gitignore.io - 자신의 프로젝트에 꼭 맞는 .gitignore 파일을 만드세요", "description": "자신의 프로젝트에 꼭 맞는 .gitignore 파일을 만드세요. %{templateCount} 개의 운영체제, 개발 환경(IDE), 프로그래밍 언어 .gitignore 템플릿이 준비되어 있습니다", "subtitle": "자신의 프로젝트에 꼭 맞는 .gitignore 파일을 만드세요", "searchPlaceholder": "운영체제, 개발 환경(IDE), 프로그래밍 언어 검색", "searchGo": "생성", "searchDownload": "파일 다운로드", "footer": "%{templateCount} 개의 운영체제, 개발 환경(IDE), 프로그래밍 언어 .gitignore 템플릿", "commandLineTitle": "커맨드라인 문서", "commandLineDescription": ".gitignore.io 를 커맨드 라인에서 실행하는 법 배우기", "videoTitle": "동영상 튜토리얼 보기", "videoDescription": ".gitignore.io 가 어떻게 동작하는지 동영상으로 배우기", "sourceCodeTitle": "소스 코드", "sourceCodeDescription": "깃헙(GitHub)에서 호스팅하는 .gitignore.io 소스 코드" } ================================================ FILE: Localizations/nl.json ================================================ { "title": "gitignore.io - Creëer nuttige .gitignore bestanden voor je project", "description": "Creëer nuttige .gitignore bestanden voor je project door te kiezen uit %{templateCount} besturingssysteem, IDE en programmeertaal .gitignore sjablonen", "subtitle": "Creëer nuttige .gitignore-bestanden voor je project", "searchPlaceholder": "Zoek besturingssystemen, IDEs of programmeertalen", "searchGo": "Creëer", "searchDownload": "Download bestand", "footer": "%{templateCount} besturingssysteem, IDE en programmeertaal .gitignore-sjablonen", "commandLineTitle": "Command Line documentatie", "commandLineDescription": "Leer hoe je .gitignore.io uitvoert vanaf de command line", "videoTitle": "Video handleiding bekijken", "videoDescription": "Bekijk een video om te leren hoe .gitignore.io werkt", "sourceCodeTitle": "Broncode", "sourceCodeDescription": "GitHub gehoste broncode voor .gitignore.io" } ================================================ FILE: Localizations/pt.json ================================================ { "title": "gitignore.io - Crie Arquivos .gitignore Úteis Para Seu Projeto.", "description": "Crie arquivos .gitignore úteis para o seu projeto selecionando os %{templateCount} templates de Sistemas Operacionais, IDEs e linguagens de Programação.", "subtitle": "Crie arquivos .gitignore úteis para o seu projeto.", "searchPlaceholder": "Pesquise Sistemas Operacionais, IDEs ou Linguagens de Programação.", "searchGo": "Criar", "searchDownload": "Baixar Arquivo", "footer": "%{templateCount} Templates de .gitignore de Sistemas Operacionais, IDEs e Linguagens de Programação.", "commandLineTitle": "Documentação", "commandLineDescription": "Saiba como executar o .gitignore.io a partir da Linha de Comando", "videoTitle": "Assista ao Vídeo Tutorial", "videoDescription": "Assista a um vídeo para aprender como funciona o .gitignore.io", "sourceCodeTitle": "Código-fonte", "sourceCodeDescription": "Código-fonte hospedado no GitHub" } ================================================ FILE: Localizations/ro.json ================================================ { "title": "gitignore.io - Creează fișiere .gitignore utile pentru proiectul tău", "description": "Creează fișiere .gitignore utile pentru proiectul tău selectând dintre %{templateCount} de șabloane .gitignore pentru sisteme de operare, IDE-uri și limbaje de programare.", "subtitle": "Creează fișiere .gitignore utile pentru proiectul tău", "searchPlaceholder": "Caută sisteme de operare, IDE-uri sau limbaje de programare", "searchGo": "Creează", "searchDownload": "Descarcă fișier", "footer": "%{templateCount} de șabloane .gitignore pentru sisteme de operare, IDE-uri și limbaje de programare", "commandLineTitle": "Documentație linie de comandă", "commandLineDescription": "Află cum să rulezi .gitignore.io din linie de comandă", "videoTitle": "Vizionează tutorialul video", "videoDescription": "Vizionează videoul să vezi cum funcționează .gitignore.io", "sourceCodeTitle": "Cod sursă", "sourceCodeDescription": "GitHub a găzduit codul sursă pentru .gitignore.io" } ================================================ FILE: Localizations/ru.json ================================================ { "title": "gitignore.io - Генерируйте удобные .gitignore файлы для вашего проекта", "description": "Генерируйте удобные .gitignore файлы для вашего проекта при помощи выбора из %{templateCount} шаблонов файла .gitignore для различных операционных систем, IDE и языков программирования", "subtitle": "Генерируйте удобные .gitignore файлы для вашего проекта", "searchPlaceholder": "Искать по операционным системам, IDE или языкам программирования", "searchGo": "Сгенерировать", "searchDownload": "Скачать файл", "footer": "%{templateCount} шаблонов файла .gitignore для различных операционных систем, IDE и языков программирования", "commandLineTitle": "Документация по работе из командной строки", "commandLineDescription": "Изучите, как запускать .gitignore.io из командной строки", "videoTitle": "Смотреть видео-туториал", "videoDescription": "Смотреть видео, рассказывающее, как работает .gitignore.io", "sourceCodeTitle": "Исходный код", "sourceCodeDescription": "Исходный код .gitignore.io на GitHub" } ================================================ FILE: Localizations/th.json ================================================ { "title": "gitignore.io - สร้างไฟล์ .gitignore ที่เป็นประโยชน์สำหรับโปรเจ็คต์ของคุณ", "description": "สร้างไฟล์ .gitignore ที่มีประโยชน์สำหรับโปรเจ็คต์ของคุณโดยเลือกจาก %{templateCount} เทมเพลตระบบปฏิบัติการ, IDE และภาษาการเขียนโปรแกรม .gitignore", "subtitle": "สร้างไฟล์ .gitignore ที่มีประโยชน์สำหรับโปรเจ็คต์ของคุณ", "searchPlaceholder": "ค้นหาระบบปฏิบัติการ IDE หรือภาษาการเขียนโปรแกรม", "searchGo": "สร้าง", "searchDownload": "ดาวน์โหลดไฟล์", "footer": "%{templateCount} เทมเพลตระบบปฏิบัติการ, IDE และภาษาการเขียนโปรแกรม .gitignore", "commandLineTitle": "ลองอ่านเอกสาร คำสั่งของ คอมมานด์ไลน์ ดูสิ!", "commandLineDescription": "เรียนรู้วิธีเรียกใช้ .gitignore.io จากคำสั่ง คอมมานด์ไลน์ ดูสิ!", "videoTitle": "ชมวิดีโอการสอนการใช้งาน", "videoDescription": "ดูวิดีโอเพื่อเรียนรู้วิธีการทำงานของ .gitignore.io", "sourceCodeTitle": "ซอร์สโค้ด", "sourceCodeDescription": "ไปที่ กิทฮับ ที่เก็บซอร์สโค้ด ของ .gitignore.io" } ================================================ FILE: Localizations/tr.json ================================================ { "title": "gitignore.io - Projen İçin İşe Yarar .gitignore Dosyaları Yarat", "description": "%{templateCount} İşletim Sistemi, IDE, ve Programlama Dili için .gitignore şablonlarından seçerek projen için işe yarar .gitignore dosyaları yarat", "subtitle": "Projen için işe yarar .gitignore dosyaları yarat", "searchPlaceholder": "İşletim Sistemleri, IDE'ler, ya da Programlama Dilleri ara", "searchGo": "Yarat", "searchDownload": "Dosyayı İndir", "footer": "%{templateCount} İşletim Sistemi, IDE, ve Programlama Dili için .gitignore şablonları", "commandLineTitle": "Komut Satırı Kılavuzu", "commandLineDescription": ".gitignore.io'u komut satırından çalıştırmayı öğren", "videoTitle": "Öğretici Videoyu İzle", "videoDescription": ".gitignore.io'nun nasıl çalıştığını öğrenmek için bir video izle", "sourceCodeTitle": "Kaynak Kod", "sourceCodeDescription": "GitHub'da tutulan .gitignore.io'un kaynak kodu" } ================================================ FILE: Localizations/zh.json ================================================ { "title": "gitignore.io - 为你的项目创建必要的 .gitignore 文件", "description": "从 %{templateCount} 操作系统, IDE, 和编程语言的 .gitignore 模板中为你的项目创建必要的 .gitignore 文件", "subtitle": "为你的项目创建必要的 .gitignore 文件", "searchPlaceholder": "搜索操作系统, IDEs, 或编程语言", "searchGo": "创建", "searchDownload": "文件下载", "footer": "%{templateCount} 操作系统, IDE, 和编程语言的 .gitignore 模板", "commandLineTitle": "命令行使用文档", "commandLineDescription": "学习如何从命令行运行 .gitignore.io", "videoTitle": "观看视频教程", "videoDescription": "通过视频学习 .gitignore.io 是如何工作的", "sourceCodeTitle": "源码", "sourceCodeDescription": ".gitignore.io 的源码托管在 github 上" } ================================================ FILE: Package.pins ================================================ { "autoPin": true, "pins": [ { "package": "CLibreSSL", "reason": null, "repositoryURL": "https://github.com/vapor/clibressl.git", "version": "1.0.0" }, { "package": "Console", "reason": null, "repositoryURL": "https://github.com/vapor/console.git", "version": "1.0.2" }, { "package": "Core", "reason": null, "repositoryURL": "https://github.com/vapor/core.git", "version": "1.1.1" }, { "package": "Crypto", "reason": null, "repositoryURL": "https://github.com/vapor/crypto.git", "version": "1.1.0" }, { "package": "Engine", "reason": null, "repositoryURL": "https://github.com/vapor/engine.git", "version": "1.3.12" }, { "package": "Fluent", "reason": null, "repositoryURL": "https://github.com/vapor/fluent.git", "version": "1.4.1" }, { "package": "JSON", "reason": null, "repositoryURL": "https://github.com/vapor/json.git", "version": "1.0.6" }, { "package": "Jay", "reason": null, "repositoryURL": "https://github.com/DanToml/Jay.git", "version": "1.0.1" }, { "package": "Leaf", "reason": null, "repositoryURL": "https://github.com/vapor/leaf.git", "version": "1.0.6" }, { "package": "Multipart", "reason": null, "repositoryURL": "https://github.com/vapor/multipart.git", "version": "1.0.2" }, { "package": "Node", "reason": null, "repositoryURL": "https://github.com/vapor/node.git", "version": "1.0.1" }, { "package": "PathIndexable", "reason": null, "repositoryURL": "https://github.com/vapor/path-indexable.git", "version": "1.0.0" }, { "package": "Polymorphic", "reason": null, "repositoryURL": "https://github.com/vapor/polymorphic.git", "version": "1.0.1" }, { "package": "Routing", "reason": null, "repositoryURL": "https://github.com/vapor/routing.git", "version": "1.1.0" }, { "package": "Socks", "reason": null, "repositoryURL": "https://github.com/vapor/socks.git", "version": "1.2.7" }, { "package": "TLS", "reason": null, "repositoryURL": "https://github.com/vapor/tls.git", "version": "1.1.2" }, { "package": "Turnstile", "reason": null, "repositoryURL": "https://github.com/stormpath/Turnstile.git", "version": "1.0.6" }, { "package": "Vapor", "reason": null, "repositoryURL": "https://github.com/vapor/vapor.git", "version": "1.5.13" } ], "version": 1 } ================================================ FILE: Package.resolved ================================================ { "object": { "pins": [ { "package": "Console", "repositoryURL": "https://github.com/vapor/console.git", "state": { "branch": null, "revision": "96617dcdcbb7572cbff0645a2e3362c042bfffad", "version": "3.0.3" } }, { "package": "Core", "repositoryURL": "https://github.com/vapor/core.git", "state": { "branch": null, "revision": "96ce86ebf9198328795c4b9cb711489460be083c", "version": "3.4.4" } }, { "package": "Crypto", "repositoryURL": "https://github.com/vapor/crypto.git", "state": { "branch": null, "revision": "5605334590affd4785a5839806b4504407e054ac", "version": "3.3.0" } }, { "package": "DatabaseKit", "repositoryURL": "https://github.com/vapor/database-kit.git", "state": { "branch": null, "revision": "3a17dbbe9be5f8c37703e4b7982c1332ad6b00c4", "version": "1.3.1" } }, { "package": "HTTP", "repositoryURL": "https://github.com/vapor/http.git", "state": { "branch": null, "revision": "272b22be8cb3364e42a4701c2e0676e37480ec5a", "version": "3.1.5" } }, { "package": "Leaf", "repositoryURL": "https://github.com/vapor/leaf.git", "state": { "branch": null, "revision": "d35f54cbac723e673f9bd5078361eea74049c8d7", "version": "3.0.2" } }, { "package": "Lingo", "repositoryURL": "https://github.com/miroslavkovac/Lingo.git", "state": { "branch": null, "revision": "f21f388b04239641b3e88d14f21762125faa9857", "version": "3.0.5" } }, { "package": "LingoVapor", "repositoryURL": "https://github.com/vapor-community/lingo-vapor.git", "state": { "branch": null, "revision": "56fdc7e7d531907ff97024a4aff8db90bcf0f965", "version": "3.0.0" } }, { "package": "Multipart", "repositoryURL": "https://github.com/vapor/multipart.git", "state": { "branch": null, "revision": "e57007c23a52b68e44ebdfc70cbe882a7c4f1ec3", "version": "3.0.2" } }, { "package": "Routing", "repositoryURL": "https://github.com/vapor/routing.git", "state": { "branch": null, "revision": "3219e328491b0853b8554c5a694add344d2c6cfb", "version": "3.0.1" } }, { "package": "Service", "repositoryURL": "https://github.com/vapor/service.git", "state": { "branch": null, "revision": "281a70b69783891900be31a9e70051b6fe19e146", "version": "1.0.0" } }, { "package": "swift-nio", "repositoryURL": "https://github.com/apple/swift-nio.git", "state": { "branch": null, "revision": "176dd6e8564d60e936b76f3a896d667ae3acba31", "version": "1.10.0" } }, { "package": "swift-nio-ssl", "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", "state": { "branch": null, "revision": "db16c3a90b101bb53b26a58867a344ad428072e0", "version": "1.3.2" } }, { "package": "swift-nio-ssl-support", "repositoryURL": "https://github.com/apple/swift-nio-ssl-support.git", "state": { "branch": null, "revision": "c02eec4e0e6d351cd092938cf44195a8e669f555", "version": "1.0.0" } }, { "package": "swift-nio-zlib-support", "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git", "state": { "branch": null, "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", "version": "1.0.0" } }, { "package": "TemplateKit", "repositoryURL": "https://github.com/vapor/template-kit.git", "state": { "branch": null, "revision": "db35b1c35aabd0f5db3abca0cfda7becfe9c43e2", "version": "1.1.0" } }, { "package": "URLEncodedForm", "repositoryURL": "https://github.com/vapor/url-encoded-form.git", "state": { "branch": null, "revision": "932024f363ee5ff59059cf7d67194a1c271d3d0c", "version": "1.0.5" } }, { "package": "Validation", "repositoryURL": "https://github.com/vapor/validation.git", "state": { "branch": null, "revision": "4de213cf319b694e4ce19e5339592601d4dd3ff6", "version": "2.1.1" } }, { "package": "Vapor", "repositoryURL": "https://github.com/vapor/vapor.git", "state": { "branch": null, "revision": "157d3b15336caa882662cc75024dd04b2e225246", "version": "3.1.0" } }, { "package": "WebSocket", "repositoryURL": "https://github.com/vapor/websocket.git", "state": { "branch": null, "revision": "eb4277f75f1d96a3d15c852cdd89af1799093dcd", "version": "1.1.0" } } ] }, "version": 1 } ================================================ FILE: Package.swift ================================================ // swift-tools-version:4.0 import PackageDescription let package = Package( name: "GitignoreIO", dependencies: [ .package( url: "https://github.com/vapor/vapor.git", from: "3.1.0" ), .package( url: "https://github.com/vapor/leaf.git", from: "3.0.0" ), .package( url: "https://github.com/vapor-community/lingo-vapor.git", from: "3.0.0" ) ], targets: [ .target( name: "App", dependencies: ["Vapor", "Leaf", "LingoVapor"], exclude: ["Config", "Localization", "Public", "Resources", "data", "wiki"] ), .target( name: "Run", dependencies: ["App"], exclude: ["Config", "Localization", "Public", "Resources", "data", "wiki"] ), .testTarget( name: "AppTests", dependencies: ["App"] ) ] ) ================================================ FILE: Procfile ================================================ web: Run serve --env production --port $PORT --hostname 0.0.0.0 ================================================ FILE: Public/assets/main.css ================================================ *,:after,:before{box-sizing:border-box}h1,h2,h3,h4,h5,h6{font-weight:500;line-height:1.2;margin-bottom:.5rem;margin-top:0}button,input,select{font-family:inherit;font-size:inherit;line-height:inherit;margin:0}.input-group>.form-control{background-color:#fff;-ms-flex:1 1 0%;flex:1 1 0%;margin-bottom:0;min-width:0}.input-group{-ms-flex-align:stretch;align-items:stretch;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;position:relative;width:100%}.input-group-append{display:-ms-flexbox;display:flex;margin-left:-1px}.input-group-append .btn{cursor:pointer;position:relative;z-index:2}.btn{border:1px solid transparent}.btn:focus{outline:0}.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;overflow:hidden;padding-left:8px;padding-right:20px;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-left:20px;padding-right:8px}.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{border:none;box-sizing:border-box;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:#fff;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;left:-100000px;position:absolute;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{box-sizing:border-box;padding:4px;width:100%}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{background-color:#fff;border:0;display:block;filter:alpha(opacity=0);height:auto;left:0;margin:0;min-height:100%;min-width:100%;opacity:0;padding:0;position:fixed;top:0;width:auto;z-index:99}.select2-hidden-accessible{clip:rect(0 0 0 0)!important;border:0!important;-webkit-clip-path:inset(50%)!important;clip-path:inset(50%)!important;height:1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!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:700}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;right:1px;top:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent;border-style:solid;border-width:5px 4px 0;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;border-width:0 4px 5px}.select2-container--default .select2-selection--multiple{background-color:#fff;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__clear{cursor:pointer;float:right;font-weight:700;margin-right:10px;margin-top:5px;padding:1px}.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:700;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-search--inline,.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice{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:1px solid #000;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--multiple,.select2-container--default.select2-container--open.select2-container--above .select2-selection--single{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple,.select2-container--default.select2-container--open.select2-container--below .select2-selection--single{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{-webkit-appearance:textfield;background:transparent;border:none;box-shadow:none;outline:0}.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:#fff}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;background-image:-webkit-linear-gradient(top,#fff 50%,#eee);background-image:-o-linear-gradient(top,#fff 50%,#eee 100%);background-image:linear-gradient(180deg,#fff 50%,#eee);background-repeat:repeat-x;border:1px solid #aaa;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF",endColorstr="#FFEEEEEE",GradientType=0);outline: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:700;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;background-image:-webkit-linear-gradient(top,#eee 50%,#ccc);background-image:-o-linear-gradient(top,#eee 50%,#ccc 100%);background-image:linear-gradient(180deg,#eee 50%,#ccc);background-repeat:repeat-x;border:none;border-bottom-right-radius:4px;border-left:1px solid #aaa;border-top-right-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE",endColorstr="#FFCCCCCC",GradientType=0);height:26px;position:absolute;right:1px;top:1px;width:20px}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent;border-style:solid;border-width:5px 4px 0;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-radius:0;border-bottom-left-radius:4px;border-right:1px solid #aaa;border-top-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;border-width:0 4px 5px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{background-image:-webkit-linear-gradient(top,#fff,#eee 50%);background-image:-o-linear-gradient(top,#fff 0,#eee 50%);background-image:linear-gradient(180deg,#fff 0,#eee 50%);background-repeat:repeat-x;border-top:none;border-top-left-radius:0;border-top-right-radius:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF",endColorstr="#FFEEEEEE",GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{background-image:-webkit-linear-gradient(top,#eee 50%,#fff);background-image:-o-linear-gradient(top,#eee 50%,#fff 100%);background-image:linear-gradient(180deg,#eee 50%,#fff);background-repeat:repeat-x;border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE",endColorstr="#FFFFFFFF",GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:#fff;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:700;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;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{box-shadow:none;outline:0}.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}.select2-container{display:block}.select2-container :focus{outline:0}.input-group .select2-container--toptal{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:calc(100% - 121px)}.input-group .input-group-append{height:46px;width:120px}@media (max-width:767px){.input-group{flex-direction:column}.input-group .select2-container--toptal{max-width:100%;width:100%!important}.input-group .input-group-append{margin-left:0;margin-top:12px;width:100%}}.select2-container--toptal .select2-selection{background-color:#fff;border:1px solid #d8d9dc;border-radius:0;box-shadow:none;-webkit-transition:border-color .15s ease-in-out,-webkit-box-shadow .15s ease-in-out;transition:border-color .15s ease-in-out,-webkit-box-shadow .15s ease-in-out;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-box-shadow .15s ease-in-out;width:100%}.select2-container--toptal .select2-selection .select2-search__field{-webkit-appearance:none;border-radius:0;caret-color:#204ecf;color:#000;font-size:16px;height:24px;line-height:24px;margin:10px 0}@media (min-width:768px){.select2-container--toptal .select2-selection .select2-search__field{font-size:13px;height:20px;line-height:20px;margin:12px 0}}.select2-container--toptal .select2-selection .select2-search__field::-webkit-search-decoration{-webkit-appearance:none}.select2-container--toptal .select2-selection .select2-search__field::placeholder{color:#d8d9dc}.select2-container--toptal .select2-selection .select2-search__field::-webkit-input-placeholder{color:#d8d9dc}.select2-container--toptal .select2-selection .select2-search__field:-ms-input-placeholder{color:#d8d9dc}.select2-container--toptal .select2-selection .select2-search__field::-moz-placeholder{color:#d8d9dc}.select2-container--toptal.select2-container--focus .select2-selection{border-color:#204ecf;box-shadow:none}.select2-container--toptal .select2-dropdown{background-color:#fff;border:none;box-shadow:0 4px 8px 0 rgba(0,0,0,.08);color:#000;font-size:13px;line-height:16px;margin-top:0}.select2-container--toptal .select2-dropdown .select2-results__option[aria-selected=true]{background-color:#d8d9dc}.select2-container--toptal .select2-results__option{padding:10px}.select2-container--toptal .select2-results__message,.select2-container--toptal .select2-results__option--highlighted,.select2-container--toptal .select2-results__option--highlighted.select2-results__option[aria-selected=true]{background-color:rgba(32,78,207,.08)}.select2-container--toptal .select2-results>.select2-results__options{max-height:15em;overflow-y:auto}.select2-container--toptal .select2-selection--multiple{min-height:46px}.select2-container--toptal .select2-selection--multiple .select2-selection__rendered{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;list-style:none;margin:0;padding:0 10px;width:100%}.select2-container--toptal .select2-selection--multiple .select2-selection__choice{border:1px solid #d8d9dc;border-radius:100px;color:#204ecf;cursor:pointer;float:left;font-size:12px;font-weight:600;line-height:22px;margin:10px 6px 0 0;padding:0 12px}.select2-container--toptal .select2-selection--multiple .select2-selection__choice__remove{color:#455065;float:right;font-size:18px;font-weight:400;margin-left:8px}.select2-container--toptal .select2-selection--multiple .select2-selection__choice__remove:hover{color:#a6abb5}.input-group-append>.btn-gitignore{background:#00cc83;border-radius:0;color:#fff;font-size:14px;line-height:16px;text-align:center;-webkit-transition:background .35s cubic-bezier(0,0,.2,1);transition:background .35s cubic-bezier(0,0,.2,1);width:100%}.input-group-append>.btn-gitignore:focus{border-color:#204ecf;box-shadow:none}.input-group-append>.btn-gitignore:hover{background:#00a369}.internal-linking{border:0;flex-basis:56px;flex-shrink:0;height:56px;overflow:hidden;width:100vw}@media (max-width:768px){.internal-linking{flex-basis:32px;height:32px}}@keyframes ticker{0%{transform:translateX(0)}to{transform:translateX(-50%)}}.internal-linking__container{align-items:center;background-color:#0f256e;color:#fff;display:flex;flex-direction:row;font-family:Proxima Nova,Arial,sans-serif;font-weight:400;height:56px;overflow:hidden;width:100%}.internal-linking__container .internal-linking__title{align-items:center;background-color:#fff;color:#204ecf;display:flex;flex-direction:row;flex-shrink:0;font-size:10px;font-weight:600;height:100%;line-height:12px;text-transform:uppercase;z-index:1}.internal-linking__container .internal-linking__title img{margin:22px 8px 18px 24px}.internal-linking__container .internal-linking__title span{margin:16px 24px 16px 0;white-space:nowrap}.internal-linking__container .internal-linking__ticker-list{animation-duration:180s;animation-iteration-count:infinite;animation-name:ticker;animation-timing-function:linear;display:flex;flex-direction:row;font-size:12px;line-height:16px}.internal-linking__container .internal-linking__ticker-list:hover{animation-play-state:paused}.internal-linking__container .internal-linking__ticker-list .internal-linking__link{color:#fff;margin:20px 28px;padding:5px 12px 3px;text-decoration:underline;white-space:nowrap}@media screen and (max-width:768px){.internal-linking__container{border:none;box-shadow:none;height:32px}.internal-linking__container .internal-linking__title img{margin:8px}.internal-linking__container .internal-linking__title span{font-size:8px;line-height:10px;margin:6px 16px 6px 0}}@media (max-width:768px){.internal-linking__container .internal-linking__ticker-list .internal-linking__link{border:1px solid #fff;border-radius:16px;margin:4px 16px;text-decoration:none}}@font-face{font-display:swap;font-family:Proxima Nova;font-style:normal;font-weight:400;src:url(../fonts/ProximaNova-Regular.woff2) format("woff2"),url(../fonts/ProximaNova-Regular.woff) format("woff"),url(../fonts/ProximaNova-Regular.otf) format("opentype")}@font-face{font-display:swap;font-family:Proxima Nova;font-style:normal;font-weight:600;src:url(../fonts/ProximaNova-Semibold.woff2) format("woff2"),url(../fonts/ProximaNova-Semibold.woff) format("woff"),url(../fonts/ProximaNova-Semibold.otf) format("opentype")}body,html{background-color:transparent;height:100%}body{color:#000;display:flex;flex-direction:column;font-family:Proxima Nova,Arial,sans-serif;font-size:16px;font-weight:400;line-height:1.5;margin:0;min-width:320px}a{color:#204ecf;text-decoration:none}a:focus,a:hover{text-decoration:underline}.content-wrapper{display:flex;flex-direction:column;min-height:100%;padding-top:72px;position:relative}header{background:#204ecf;color:#fff;height:72px;overflow-x:hidden;position:fixed;top:0;width:100%;z-index:1100}header .container{align-items:center;display:flex;height:100%;justify-content:space-between}header a{display:block;line-height:0}header .header-left-column{align-items:center;display:flex;padding:0 10px}header .header-left-column a{padding-right:16px}header .header-left-column a img{height:30px;min-width:100px}header .header-left-column h1{border-left:1px solid #ebeced;font-size:17px;line-height:28px;margin:0;padding-left:16px}header .header-right-column img{height:24px}main{flex:1 0 400px;width:100%}@media (min-width:768px){main{display:flex}}main .masthead{margin:0 auto;max-width:580px;overflow-y:auto;text-align:center}main .masthead-top{align-items:center;display:flex;flex-direction:column;margin-bottom:25px;margin-top:120px}@media (min-width:768px){main .masthead-top{margin-top:180px}}@media (max-width:320px){main .masthead-top{margin-top:42px}}main .masthead-top img{height:auto;max-width:370px;width:100%}main .masthead-top h2{color:#455065;font-size:16px;line-height:16px;margin:20px 0}main .input-group{overflow:auto}main .masthead-bottom{margin-bottom:60px;margin-top:40px}main .masthead-bottom ul{display:flex;flex-direction:column;justify-content:center;list-style:none;margin:0;padding:0}main .masthead-bottom ul li{margin-bottom:16px}main .masthead-bottom ul li a{font-size:16px;line-height:16px;padding-bottom:8px}main .masthead-bottom ul li a:focus,main .masthead-bottom ul li a:hover{border-bottom:1px solid #204ecf;text-decoration:none}footer{color:#000;height:142px;padding-bottom:64px}footer>div{margin:0 auto;max-width:624px;padding:0 16px;width:100%}footer .carbon-wrap{align-items:center;display:flex;justify-content:center}footer a.carbon-img{height:78px}footer a.carbon-img img{height:100%}footer a.carbon-text{font-size:12px;line-height:20px;padding-left:8px}footer .carbon-poweredby{display:none}.container{margin-left:auto;margin-right:auto;max-width:100%;padding-left:16px;padding-right:16px;position:relative}@media (min-width:1200px){.container{max-width:1344px}}@media (min-width:576px){.container{width:540px}main .masthead-bottom ul{flex-direction:row}main .masthead-bottom ul li:not(:first-child):before{background-color:#a6abb5;content:"";display:inline-block;height:12px;margin:0 21px;width:1px}}@media (min-width:768px){.container{width:720px}}@media (min-width:992px){.container{width:960px}}@media (min-width:1200px){.container{width:1376px}header .header-right-column{padding-right:98px}}#input-gitignore{-webkit-appearance:none;border:1px solid #d8d9dc;border-radius:0;height:46px;line-height:46px}#input-gitignore::-ms-expand{display:none}#internal-linking{border:0;box-shadow:0 -1px 3px 0 rgba(0,0,0,.1);height:56px}@media (max-width:768px){#internal-linking{height:32px}} ================================================ FILE: Public/assets/main.js ================================================ /*! For license information please see main.js.LICENSE.txt */ (()=>{var e={755:function(e,t){var n;!function(t,n){"use strict";"object"==typeof e.exports?e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return n(e)}:n(t)}("undefined"!=typeof window?window:this,(function(r,i){"use strict";var o=[],s=Object.getPrototypeOf,a=o.slice,l=o.flat?function(e){return o.flat.call(e)}:function(e){return o.concat.apply([],e)},c=o.push,u=o.indexOf,p={},d=p.toString,f=p.hasOwnProperty,h=f.toString,g=h.call(Object),m={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},b=r.document,x={type:!0,src:!0,nonce:!0,noModule:!0};function w(e,t,n){var r,i,o=(n=n||b).createElement("script");if(o.text=e,t)for(r in x)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function _(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?p[d.call(e)]||"object":typeof e}var T="3.6.0",C=function(e,t){return new C.fn.init(e,t)};function A(e){var t=!!e&&"length"in e&&e.length,n=_(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}C.fn=C.prototype={jquery:T,constructor:C,length:0,toArray:function(){return a.call(this)},get:function(e){return null==e?a.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=C.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return C.each(this,e)},map:function(e){return this.pushStack(C.map(this,(function(t,n){return e.call(t,n,t)})))},slice:function(){return this.pushStack(a.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(C.grep(this,(function(e,t){return(t+1)%2})))},odd:function(){return this.pushStack(C.grep(this,(function(e,t){return t%2})))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n+~]|[\\x20\\t\\r\\n\\f])[\\x20\\t\\r\\n\\f]*"),z=new RegExp(H+"|>"),G=new RegExp(M),Y=new RegExp("^"+I+"$"),X={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+R),PSEUDO:new RegExp("^"+M),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\([\\x20\\t\\r\\n\\f]*(even|odd|(([+-]|)(\\d*)n|)[\\x20\\t\\r\\n\\f]*(?:([+-]|)[\\x20\\t\\r\\n\\f]*(\\d+)|))[\\x20\\t\\r\\n\\f]*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^[\\x20\\t\\r\\n\\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\([\\x20\\t\\r\\n\\f]*((?:-\\d)?\\d*)[\\x20\\t\\r\\n\\f]*\\)|)(?=[^-]|$)","i")},K=/HTML$/i,V=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}[\\x20\\t\\r\\n\\f]?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){d()},se=xe((function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()}),{dir:"parentNode",next:"legend"});try{O.apply(k=q.call(w.childNodes),w.childNodes),k[w.childNodes.length].nodeType}catch(e){O={apply:k.length?function(e,t){L.apply(e,q.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function ae(e,t,r,i){var o,a,c,u,p,h,v,y=t&&t.ownerDocument,w=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==w&&9!==w&&11!==w)return r;if(!i&&(d(t),t=t||f,g)){if(11!==w&&(p=J.exec(e)))if(o=p[1]){if(9===w){if(!(c=t.getElementById(o)))return r;if(c.id===o)return r.push(c),r}else if(y&&(c=y.getElementById(o))&&b(t,c)&&c.id===o)return r.push(c),r}else{if(p[2])return O.apply(r,t.getElementsByTagName(e)),r;if((o=p[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!m||!m.test(e))&&(1!==w||"object"!==t.nodeName.toLowerCase())){if(v=e,y=t,1===w&&(z.test(e)||B.test(e))){for((y=ee.test(e)&&ve(t.parentNode)||t)===t&&n.scope||((u=t.getAttribute("id"))?u=u.replace(re,ie):t.setAttribute("id",u=x)),a=(h=s(e)).length;a--;)h[a]=(u?"#"+u:":scope")+" "+be(h[a]);v=h.join(",")}try{return O.apply(r,y.querySelectorAll(v)),r}catch(t){S(e,!0)}finally{u===x&&t.removeAttribute("id")}}}return l(e.replace(F,"$1"),t,r,i)}function le(){var e=[];return function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}}function ce(e){return e[x]=!0,e}function ue(e){var t=f.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function pe(e,t){for(var n=e.split("|"),i=n.length;i--;)r.attrHandle[n[i]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function he(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ge(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&se(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function me(e){return ce((function(t){return t=+t,ce((function(n,r){for(var i,o=e([],n.length,t),s=o.length;s--;)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))}))}))}function ve(e){return e&&void 0!==e.getElementsByTagName&&e}for(t in n=ae.support={},o=ae.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!K.test(t||n&&n.nodeName||"HTML")},d=ae.setDocument=function(e){var t,i,s=e?e.ownerDocument||e:w;return s!=f&&9===s.nodeType&&s.documentElement?(h=(f=s).documentElement,g=!o(f),w!=f&&(i=f.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",oe,!1):i.attachEvent&&i.attachEvent("onunload",oe)),n.scope=ue((function(e){return h.appendChild(e).appendChild(f.createElement("div")),void 0!==e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length})),n.attributes=ue((function(e){return e.className="i",!e.getAttribute("className")})),n.getElementsByTagName=ue((function(e){return e.appendChild(f.createComment("")),!e.getElementsByTagName("*").length})),n.getElementsByClassName=Z.test(f.getElementsByClassName),n.getById=ue((function(e){return h.appendChild(e).id=x,!f.getElementsByName||!f.getElementsByName(x).length})),n.getById?(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],m=[],(n.qsa=Z.test(f.querySelectorAll))&&(ue((function(e){var t;h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&m.push("[*^$]=[\\x20\\t\\r\\n\\f]*(?:''|\"\")"),e.querySelectorAll("[selected]").length||m.push("\\[[\\x20\\t\\r\\n\\f]*(?:value|"+P+")"),e.querySelectorAll("[id~="+x+"-]").length||m.push("~="),(t=f.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||m.push("\\[[\\x20\\t\\r\\n\\f]*name[\\x20\\t\\r\\n\\f]*=[\\x20\\t\\r\\n\\f]*(?:''|\"\")"),e.querySelectorAll(":checked").length||m.push(":checked"),e.querySelectorAll("a#"+x+"+*").length||m.push(".#.+[+~]"),e.querySelectorAll("\\\f"),m.push("[\\r\\n\\f]")})),ue((function(e){e.innerHTML="";var t=f.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&m.push("name[\\x20\\t\\r\\n\\f]*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&m.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&m.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),m.push(",.*:")}))),(n.matchesSelector=Z.test(y=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue((function(e){n.disconnectedMatch=y.call(e,"*"),y.call(e,"[s!='']:x"),v.push("!=",M)})),m=m.length&&new RegExp(m.join("|")),v=v.length&&new RegExp(v.join("|")),t=Z.test(h.compareDocumentPosition),b=t||Z.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},$=t?function(e,t){if(e===t)return p=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e==f||e.ownerDocument==w&&b(w,e)?-1:t==f||t.ownerDocument==w&&b(w,t)?1:u?N(u,e)-N(u,t):0:4&r?-1:1)}:function(e,t){if(e===t)return p=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],a=[t];if(!i||!o)return e==f?-1:t==f?1:i?-1:o?1:u?N(u,e)-N(u,t):0;if(i===o)return de(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)a.unshift(n);for(;s[r]===a[r];)r++;return r?de(s[r],a[r]):s[r]==w?-1:a[r]==w?1:0},f):f},ae.matches=function(e,t){return ae(e,null,null,t)},ae.matchesSelector=function(e,t){if(d(e),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!m||!m.test(t)))try{var r=y.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){S(t,!0)}return ae(t,f,null,[e]).length>0},ae.contains=function(e,t){return(e.ownerDocument||e)!=f&&d(e),b(e,t)},ae.attr=function(e,t){(e.ownerDocument||e)!=f&&d(e);var i=r.attrHandle[t.toLowerCase()],o=i&&D.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},ae.escape=function(e){return(e+"").replace(re,ie)},ae.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},ae.uniqueSort=function(e){var t,r=[],i=0,o=0;if(p=!n.detectDuplicates,u=!n.sortStable&&e.slice(0),e.sort($),p){for(;t=e[o++];)t===e[o]&&(i=r.push(o));for(;i--;)e.splice(r[i],1)}return u=null,e},i=ae.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r++];)n+=i(t);return n},(r=ae.selectors={cacheLength:50,createPseudo:ce,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ae.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ae.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return X.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&G.test(n)&&(t=s(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=new RegExp("(^|[\\x20\\t\\r\\n\\f])"+e+"("+H+"|$)"))&&C(e,(function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")}))},ATTR:function(e,t,n){return function(r){var i=ae.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace(U," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var c,u,p,d,f,h,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,v=a&&t.nodeName.toLowerCase(),y=!l&&!a,b=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(a?d.nodeName.toLowerCase()===v:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[s?m.firstChild:m.lastChild],s&&y){for(b=(f=(c=(u=(p=(d=m)[x]||(d[x]={}))[d.uniqueID]||(p[d.uniqueID]={}))[e]||[])[0]===_&&c[1])&&c[2],d=f&&m.childNodes[f];d=++f&&d&&d[g]||(b=f=0)||h.pop();)if(1===d.nodeType&&++b&&d===t){u[e]=[_,f,b];break}}else if(y&&(b=f=(c=(u=(p=(d=t)[x]||(d[x]={}))[d.uniqueID]||(p[d.uniqueID]={}))[e]||[])[0]===_&&c[1]),!1===b)for(;(d=++f&&d&&d[g]||(b=f=0)||h.pop())&&((a?d.nodeName.toLowerCase()!==v:1!==d.nodeType)||!++b||(y&&((u=(p=d[x]||(d[x]={}))[d.uniqueID]||(p[d.uniqueID]={}))[e]=[_,b]),d!==t)););return(b-=i)===r||b%r==0&&b/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||ae.error("unsupported pseudo: "+e);return i[x]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?ce((function(e,n){for(var r,o=i(e,t),s=o.length;s--;)e[r=N(e,o[s])]=!(n[r]=o[s])})):function(e){return i(e,0,n)}):i}},pseudos:{not:ce((function(e){var t=[],n=[],r=a(e.replace(F,"$1"));return r[x]?ce((function(e,t,n,i){for(var o,s=r(e,null,i,[]),a=e.length;a--;)(o=s[a])&&(e[a]=!(t[a]=o))})):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}})),has:ce((function(e){return function(t){return ae(e,t).length>0}})),contains:ce((function(e){return e=e.replace(te,ne),function(t){return(t.textContent||i(t)).indexOf(e)>-1}})),lang:ce((function(e){return Y.test(e||"")||ae.error("unsupported lang: "+e),e=e.replace(te,ne).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}})),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return V.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:me((function(){return[0]})),last:me((function(e,t){return[t-1]})),eq:me((function(e,t,n){return[n<0?n+t:n]})),even:me((function(e,t){for(var n=0;nt?t:n;--r>=0;)e.push(r);return e})),gt:me((function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function _e(e,t,n,r,i){for(var o,s=[],a=0,l=e.length,c=null!=t;a-1&&(o[c]=!(s[c]=p))}}else v=_e(v===s?v.splice(h,v.length):v),i?i(null,s,v,l):O.apply(s,v)}))}function Ce(e){for(var t,n,i,o=e.length,s=r.relative[e[0].type],a=s||r.relative[" "],l=s?1:0,u=xe((function(e){return e===t}),a,!0),p=xe((function(e){return N(t,e)>-1}),a,!0),d=[function(e,n,r){var i=!s&&(r||n!==c)||((t=n).nodeType?u(e,n,r):p(e,n,r));return t=null,i}];l1&&we(d),l>1&&be(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(F,"$1"),n,l0,i=e.length>0,o=function(o,s,a,l,u){var p,h,m,v=0,y="0",b=o&&[],x=[],w=c,T=o||i&&r.find.TAG("*",u),C=_+=null==w?1:Math.random()||.1,A=T.length;for(u&&(c=s==f||s||u);y!==A&&null!=(p=T[y]);y++){if(i&&p){for(h=0,s||p.ownerDocument==f||(d(p),a=!g);m=e[h++];)if(m(p,s||f,a)){l.push(p);break}u&&(_=C)}n&&((p=!m&&p)&&v--,o&&b.push(p))}if(v+=y,n&&y!==v){for(h=0;m=t[h++];)m(b,x,s,a);if(o){if(v>0)for(;y--;)b[y]||x[y]||(x[y]=j.call(l));x=_e(x)}O.apply(l,x),u&&!o&&x.length>0&&v+t.length>1&&ae.uniqueSort(l)}return u&&(_=C,c=w),b};return n?ce(o):o}(o,i))).selector=e}return a},l=ae.select=function(e,t,n,i){var o,l,c,u,p,d="function"==typeof e&&e,f=!i&&s(e=d.selector||e);if(n=n||[],1===f.length){if((l=f[0]=f[0].slice(0)).length>2&&"ID"===(c=l[0]).type&&9===t.nodeType&&g&&r.relative[l[1].type]){if(!(t=(r.find.ID(c.matches[0].replace(te,ne),t)||[])[0]))return n;d&&(t=t.parentNode),e=e.slice(l.shift().value.length)}for(o=X.needsContext.test(e)?0:l.length;o--&&(c=l[o],!r.relative[u=c.type]);)if((p=r.find[u])&&(i=p(c.matches[0].replace(te,ne),ee.test(l[0].type)&&ve(t.parentNode)||t))){if(l.splice(o,1),!(e=i.length&&be(l)))return O.apply(n,i),n;break}}return(d||a(e,f))(i,t,!g,n,!t||ee.test(e)&&ve(t.parentNode)||t),n},n.sortStable=x.split("").sort($).join("")===x,n.detectDuplicates=!!p,d(),n.sortDetached=ue((function(e){return 1&e.compareDocumentPosition(f.createElement("fieldset"))})),ue((function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")}))||pe("type|href|height|width",(function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)})),n.attributes&&ue((function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}))||pe("value",(function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue})),ue((function(e){return null==e.getAttribute("disabled")}))||pe(P,(function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null})),ae}(r);C.find=E,C.expr=E.selectors,C.expr[":"]=C.expr.pseudos,C.uniqueSort=C.unique=E.uniqueSort,C.text=E.getText,C.isXMLDoc=E.isXML,C.contains=E.contains,C.escapeSelector=E.escape;var S=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&C(e).is(n))break;r.push(e)}return r},$=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=C.expr.match.needsContext;function k(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var j=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function L(e,t,n){return v(t)?C.grep(e,(function(e,r){return!!t.call(e,r,e)!==n})):t.nodeType?C.grep(e,(function(e){return e===t!==n})):"string"!=typeof t?C.grep(e,(function(e){return u.call(t,e)>-1!==n})):C.filter(t,e,n)}C.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?C.find.matchesSelector(r,e)?[r]:[]:C.find.matches(e,C.grep(t,(function(e){return 1===e.nodeType})))},C.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(C(e).filter((function(){for(t=0;t1?C.uniqueSort(n):n},filter:function(e){return this.pushStack(L(this,e||[],!1))},not:function(e){return this.pushStack(L(this,e||[],!0))},is:function(e){return!!L(this,"string"==typeof e&&D.test(e)?C(e):e||[],!1).length}});var O,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(C.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||O,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof C?t[0]:t,C.merge(this,C.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:b,!0)),j.test(r[1])&&C.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=b.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(C):C.makeArray(e,this)}).prototype=C.fn,O=C(b);var N=/^(?:parents|prev(?:Until|All))/,P={children:!0,contents:!0,next:!0,prev:!0};function H(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}C.fn.extend({has:function(e){var t=C(e,this),n=t.length;return this.filter((function(){for(var e=0;e-1:1===n.nodeType&&C.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?C.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(C(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(C.uniqueSort(C.merge(this.get(),C(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),C.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return S(e,"parentNode")},parentsUntil:function(e,t,n){return S(e,"parentNode",n)},next:function(e){return H(e,"nextSibling")},prev:function(e){return H(e,"previousSibling")},nextAll:function(e){return S(e,"nextSibling")},prevAll:function(e){return S(e,"previousSibling")},nextUntil:function(e,t,n){return S(e,"nextSibling",n)},prevUntil:function(e,t,n){return S(e,"previousSibling",n)},siblings:function(e){return $((e.parentNode||{}).firstChild,e)},children:function(e){return $(e.firstChild)},contents:function(e){return null!=e.contentDocument&&s(e.contentDocument)?e.contentDocument:(k(e,"template")&&(e=e.content||e),C.merge([],e.childNodes))}},(function(e,t){C.fn[e]=function(n,r){var i=C.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=C.filter(r,i)),this.length>1&&(P[e]||C.uniqueSort(i),N.test(e)&&i.reverse()),this.pushStack(i)}}));var I=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function U(e,t,n,r){var i;try{e&&v(i=e.promise)?i.call(e).done(t).fail(n):e&&v(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}C.Callbacks=function(e){e="string"==typeof e?function(e){var t={};return C.each(e.match(I)||[],(function(e,n){t[n]=!0})),t}(e):C.extend({},e);var t,n,r,i,o=[],s=[],a=-1,l=function(){for(i=i||e.once,r=t=!0;s.length;a=-1)for(n=s.shift();++a-1;)o.splice(n,1),n<=a&&a--})),this},has:function(e){return e?C.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=s=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=s=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},C.extend({Deferred:function(e){var t=[["notify","progress",C.Callbacks("memory"),C.Callbacks("memory"),2],["resolve","done",C.Callbacks("once memory"),C.Callbacks("once memory"),0,"resolved"],["reject","fail",C.Callbacks("once memory"),C.Callbacks("once memory"),1,"rejected"]],n="pending",i={state:function(){return n},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe:function(){var e=arguments;return C.Deferred((function(n){C.each(t,(function(t,r){var i=v(e[r[4]])&&e[r[4]];o[r[1]]((function(){var e=i&&i.apply(this,arguments);e&&v(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[r[0]+"With"](this,i?[e]:arguments)}))})),e=null})).promise()},then:function(e,n,i){var o=0;function s(e,t,n,i){return function(){var a=this,l=arguments,c=function(){var r,c;if(!(e=o&&(n!==M&&(a=void 0,l=[r]),t.rejectWith(a,l))}};e?u():(C.Deferred.getStackHook&&(u.stackTrace=C.Deferred.getStackHook()),r.setTimeout(u))}}return C.Deferred((function(r){t[0][3].add(s(0,r,v(i)?i:R,r.notifyWith)),t[1][3].add(s(0,r,v(e)?e:R)),t[2][3].add(s(0,r,v(n)?n:M))})).promise()},promise:function(e){return null!=e?C.extend(e,i):i}},o={};return C.each(t,(function(e,r){var s=r[2],a=r[5];i[r[1]]=s.add,a&&s.add((function(){n=a}),t[3-e][2].disable,t[3-e][3].disable,t[0][2].lock,t[0][3].lock),s.add(r[3].fire),o[r[0]]=function(){return o[r[0]+"With"](this===o?void 0:this,arguments),this},o[r[0]+"With"]=s.fireWith})),i.promise(o),e&&e.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=a.call(arguments),o=C.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?a.call(arguments):n,--t||o.resolveWith(r,i)}};if(t<=1&&(U(e,o.done(s(n)).resolve,o.reject,!t),"pending"===o.state()||v(i[n]&&i[n].then)))return o.then();for(;n--;)U(i[n],s(n),o.reject);return o.promise()}});var F=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;C.Deferred.exceptionHook=function(e,t){r.console&&r.console.warn&&e&&F.test(e.name)&&r.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},C.readyException=function(e){r.setTimeout((function(){throw e}))};var W=C.Deferred();function B(){b.removeEventListener("DOMContentLoaded",B),r.removeEventListener("load",B),C.ready()}C.fn.ready=function(e){return W.then(e).catch((function(e){C.readyException(e)})),this},C.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--C.readyWait:C.isReady)||(C.isReady=!0,!0!==e&&--C.readyWait>0||W.resolveWith(b,[C]))}}),C.ready.then=W.then,"complete"===b.readyState||"loading"!==b.readyState&&!b.documentElement.doScroll?r.setTimeout(C.ready):(b.addEventListener("DOMContentLoaded",B),r.addEventListener("load",B));var z=function(e,t,n,r,i,o,s){var a=0,l=e.length,c=null==n;if("object"===_(n))for(a in i=!0,n)z(e,t,a,n[a],!0,o,s);else if(void 0!==r&&(i=!0,v(r)||(s=!0),c&&(s?(t.call(e,r),t=null):(c=t,t=function(e,t,n){return c.call(C(e),n)})),t))for(;a1,null,!0)},removeData:function(e){return this.each((function(){J.remove(this,e)}))}}),C.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Z.get(e,t),n&&(!r||Array.isArray(n)?r=Z.access(e,t,C.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=C.queue(e,t),r=n.length,i=n.shift(),o=C._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,(function(){C.dequeue(e,t)}),o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Z.get(e,n)||Z.access(e,n,{empty:C.Callbacks("once memory").add((function(){Z.remove(e,[t+"queue",n])}))})}}),C.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]*)/i,ye=/^$|^module$|\/(?:java|ecma)script/i;he=b.createDocumentFragment().appendChild(b.createElement("div")),(ge=b.createElement("input")).setAttribute("type","radio"),ge.setAttribute("checked","checked"),ge.setAttribute("name","t"),he.appendChild(ge),m.checkClone=he.cloneNode(!0).cloneNode(!0).lastChild.checked,he.innerHTML="",m.noCloneChecked=!!he.cloneNode(!0).lastChild.defaultValue,he.innerHTML="",m.option=!!he.lastChild;var be={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function xe(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&k(e,t)?C.merge([e],n):n}function we(e,t){for(var n=0,r=e.length;n",""]);var _e=/<|&#?\w+;/;function Te(e,t,n,r,i){for(var o,s,a,l,c,u,p=t.createDocumentFragment(),d=[],f=0,h=e.length;f-1)i&&i.push(o);else if(c=ae(o),s=xe(p.appendChild(o),"script"),c&&we(s),n)for(u=0;o=s[u++];)ye.test(o.type||"")&&n.push(o);return p}var Ce=/^([^.]*)(?:\.(.+)|)/;function Ae(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return b.activeElement}catch(e){}}()==("focus"===t)}function $e(e,t,n,r,i,o){var s,a;if("object"==typeof t){for(a in"string"!=typeof n&&(r=r||n,n=void 0),t)$e(e,a,n,r,t[a],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(s=i,(i=function(e){return C().off(e),s.apply(this,arguments)}).guid=s.guid||(s.guid=C.guid++)),e.each((function(){C.event.add(this,t,i,r,n)}))}function De(e,t,n){n?(Z.set(e,t,!1),C.event.add(e,t,{namespace:!1,handler:function(e){var r,i,o=Z.get(this,t);if(1&e.isTrigger&&this[t]){if(o.length)(C.event.special[t]||{}).delegateType&&e.stopPropagation();else if(o=a.call(arguments),Z.set(this,t,o),r=n(this,t),this[t](),o!==(i=Z.get(this,t))||r?Z.set(this,t,!1):i={},o!==i)return e.stopImmediatePropagation(),e.preventDefault(),i&&i.value}else o.length&&(Z.set(this,t,{value:C.event.trigger(C.extend(o[0],C.Event.prototype),o.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Z.get(e,t)&&C.event.add(e,t,Ae)}C.event={global:{},add:function(e,t,n,r,i){var o,s,a,l,c,u,p,d,f,h,g,m=Z.get(e);if(V(e))for(n.handler&&(n=(o=n).handler,i=o.selector),i&&C.find.matchesSelector(se,i),n.guid||(n.guid=C.guid++),(l=m.events)||(l=m.events=Object.create(null)),(s=m.handle)||(s=m.handle=function(t){return void 0!==C&&C.event.triggered!==t.type?C.event.dispatch.apply(e,arguments):void 0}),c=(t=(t||"").match(I)||[""]).length;c--;)f=g=(a=Ce.exec(t[c])||[])[1],h=(a[2]||"").split(".").sort(),f&&(p=C.event.special[f]||{},f=(i?p.delegateType:p.bindType)||f,p=C.event.special[f]||{},u=C.extend({type:f,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&C.expr.match.needsContext.test(i),namespace:h.join(".")},o),(d=l[f])||((d=l[f]=[]).delegateCount=0,p.setup&&!1!==p.setup.call(e,r,h,s)||e.addEventListener&&e.addEventListener(f,s)),p.add&&(p.add.call(e,u),u.handler.guid||(u.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,u):d.push(u),C.event.global[f]=!0)},remove:function(e,t,n,r,i){var o,s,a,l,c,u,p,d,f,h,g,m=Z.hasData(e)&&Z.get(e);if(m&&(l=m.events)){for(c=(t=(t||"").match(I)||[""]).length;c--;)if(f=g=(a=Ce.exec(t[c])||[])[1],h=(a[2]||"").split(".").sort(),f){for(p=C.event.special[f]||{},d=l[f=(r?p.delegateType:p.bindType)||f]||[],a=a[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=d.length;o--;)u=d[o],!i&&g!==u.origType||n&&n.guid!==u.guid||a&&!a.test(u.namespace)||r&&r!==u.selector&&("**"!==r||!u.selector)||(d.splice(o,1),u.selector&&d.delegateCount--,p.remove&&p.remove.call(e,u));s&&!d.length&&(p.teardown&&!1!==p.teardown.call(e,h,m.handle)||C.removeEvent(e,f,m.handle),delete l[f])}else for(f in l)C.event.remove(e,f+t[c],n,r,!0);C.isEmptyObject(l)&&Z.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,s,a=new Array(arguments.length),l=C.event.fix(e),c=(Z.get(this,"events")||Object.create(null))[l.type]||[],u=C.event.special[l.type]||{};for(a[0]=l,t=1;t=1))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&("click"!==e.type||!0!==c.disabled)){for(o=[],s={},n=0;n-1:C.find(i,this,null,[c]).length),s[i]&&o.push(r);o.length&&a.push({elem:c,handlers:o})}return c=this,l\s*$/g;function Oe(e,t){return k(e,"table")&&k(11!==t.nodeType?t:t.firstChild,"tr")&&C(e).children("tbody")[0]||e}function qe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Ne(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,s,a;if(1===t.nodeType){if(Z.hasData(e)&&(a=Z.get(e).events))for(i in Z.remove(t,"handle events"),a)for(n=0,r=a[i].length;n1&&"string"==typeof h&&!m.checkClone&&je.test(h))return e.each((function(i){var o=e.eq(i);g&&(t[0]=h.call(this,i,o.html())),Ie(o,t,n,r)}));if(d&&(o=(i=Te(t,e[0].ownerDocument,!1,e,r)).firstChild,1===i.childNodes.length&&(i=o),o||r)){for(a=(s=C.map(xe(i,"script"),qe)).length;p0&&we(s,!l&&xe(e,"script")),a},cleanData:function(e){for(var t,n,r,i=C.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Z.expando]){if(t.events)for(r in t.events)i[r]?C.event.remove(n,r):C.removeEvent(n,r,t.handle);n[Z.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),C.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return z(this,(function(e){return void 0===e?C.text(this):this.empty().each((function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)}))}),null,e,arguments.length)},append:function(){return Ie(this,arguments,(function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)}))},prepend:function(){return Ie(this,arguments,(function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}}))},before:function(){return Ie(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this)}))},after:function(){return Ie(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)}))},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(C.cleanData(xe(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map((function(){return C.clone(this,e,t)}))},html:function(e){return z(this,(function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ke.test(e)&&!be[(ve.exec(e)||["",""])[1].toLowerCase()]){e=C.htmlPrefilter(e);try{for(;n=0&&(l+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-l-a-.5))||0),l}function nt(e,t,n){var r=Ue(e),i=(!m.boxSizingReliable()||n)&&"border-box"===C.css(e,"boxSizing",!1,r),o=i,s=Be(e,t,r),a="offset"+t[0].toUpperCase()+t.slice(1);if(Me.test(s)){if(!n)return s;s="auto"}return(!m.boxSizingReliable()&&i||!m.reliableTrDimensions()&&k(e,"tr")||"auto"===s||!parseFloat(s)&&"inline"===C.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===C.css(e,"boxSizing",!1,r),(o=a in e)&&(s=e[a])),(s=parseFloat(s)||0)+tt(e,t,n||(i?"border":"content"),o,r,s)+"px"}function rt(e,t,n,r,i){return new rt.prototype.init(e,t,n,r,i)}C.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=K(t),l=Qe.test(t),c=e.style;if(l||(t=Ke(a)),s=C.cssHooks[t]||C.cssHooks[a],void 0===n)return s&&"get"in s&&void 0!==(i=s.get(e,!1,r))?i:c[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||l||(n+=i&&i[3]||(C.cssNumber[a]?"":"px")),m.clearCloneStyle||""!==n||0!==t.indexOf("background")||(c[t]="inherit"),s&&"set"in s&&void 0===(n=s.set(e,n,r))||(l?c.setProperty(t,n):c[t]=n))}},css:function(e,t,n,r){var i,o,s,a=K(t);return Qe.test(t)||(t=Ke(a)),(s=C.cssHooks[t]||C.cssHooks[a])&&"get"in s&&(i=s.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Je&&(i=Je[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),C.each(["height","width"],(function(e,t){C.cssHooks[t]={get:function(e,n,r){if(n)return!Ve.test(C.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?nt(e,t,r):Fe(e,Ze,(function(){return nt(e,t,r)}))},set:function(e,n,r){var i,o=Ue(e),s=!m.scrollboxSize()&&"absolute"===o.position,a=(s||r)&&"border-box"===C.css(e,"boxSizing",!1,o),l=r?tt(e,t,r,a,o):0;return a&&s&&(l-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-tt(e,t,"border",!1,o)-.5)),l&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=C.css(e,t)),et(0,n,l)}}})),C.cssHooks.marginLeft=ze(m.reliableMarginLeft,(function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-Fe(e,{marginLeft:0},(function(){return e.getBoundingClientRect().left})))+"px"})),C.each({margin:"",padding:"",border:"Width"},(function(e,t){C.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(C.cssHooks[e+t].set=et)})),C.fn.extend({css:function(e,t){return z(this,(function(e,t,n){var r,i,o={},s=0;if(Array.isArray(t)){for(r=Ue(e),i=t.length;s1)}}),C.Tween=rt,rt.prototype={constructor:rt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||C.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(C.cssNumber[n]?"":"px")},cur:function(){var e=rt.propHooks[this.prop];return e&&e.get?e.get(this):rt.propHooks._default.get(this)},run:function(e){var t,n=rt.propHooks[this.prop];return this.options.duration?this.pos=t=C.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rt.propHooks._default.set(this),this}},rt.prototype.init.prototype=rt.prototype,rt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=C.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){C.fx.step[e.prop]?C.fx.step[e.prop](e):1!==e.elem.nodeType||!C.cssHooks[e.prop]&&null==e.elem.style[Ke(e.prop)]?e.elem[e.prop]=e.now:C.style(e.elem,e.prop,e.now+e.unit)}}},rt.propHooks.scrollTop=rt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},C.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},C.fx=rt.prototype.init,C.fx.step={};var it,ot,st=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function lt(){ot&&(!1===b.hidden&&r.requestAnimationFrame?r.requestAnimationFrame(lt):r.setTimeout(lt,C.fx.interval),C.fx.tick())}function ct(){return r.setTimeout((function(){it=void 0})),it=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners["*"]),o=0,s=i.length;o1)},removeAttr:function(e){return this.each((function(){C.removeAttr(this,e)}))}}),C.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?C.prop(e,t,n):(1===o&&C.isXMLDoc(e)||(i=C.attrHooks[t.toLowerCase()]||(C.expr.match.bool.test(t)?ft:void 0)),void 0!==n?null===n?void C.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=C.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!m.radioValue&&"radio"===t&&k(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(I);if(i&&1===e.nodeType)for(;n=i[r++];)e.removeAttribute(n)}}),ft={set:function(e,t,n){return!1===t?C.removeAttr(e,n):e.setAttribute(n,n),n}},C.each(C.expr.match.bool.source.match(/\w+/g),(function(e,t){var n=ht[t]||C.find.attr;ht[t]=function(e,t,r){var i,o,s=t.toLowerCase();return r||(o=ht[s],ht[s]=i,i=null!=n(e,t,r)?s:null,ht[s]=o),i}}));var gt=/^(?:input|select|textarea|button)$/i,mt=/^(?:a|area)$/i;function vt(e){return(e.match(I)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function bt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(I)||[]}C.fn.extend({prop:function(e,t){return z(this,C.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each((function(){delete this[C.propFix[e]||e]}))}}),C.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&C.isXMLDoc(e)||(t=C.propFix[t]||t,i=C.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=C.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||mt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),m.optSelected||(C.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),C.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],(function(){C.propFix[this.toLowerCase()]=this})),C.fn.extend({addClass:function(e){var t,n,r,i,o,s,a,l=0;if(v(e))return this.each((function(t){C(this).addClass(e.call(this,t,yt(this)))}));if((t=bt(e)).length)for(;n=this[l++];)if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){for(s=0;o=t[s++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(a=vt(r))&&n.setAttribute("class",a)}return this},removeClass:function(e){var t,n,r,i,o,s,a,l=0;if(v(e))return this.each((function(t){C(this).removeClass(e.call(this,t,yt(this)))}));if(!arguments.length)return this.attr("class","");if((t=bt(e)).length)for(;n=this[l++];)if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){for(s=0;o=t[s++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");i!==(a=vt(r))&&n.setAttribute("class",a)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):v(e)?this.each((function(n){C(this).toggleClass(e.call(this,n,yt(this),t),t)})):this.each((function(){var t,i,o,s;if(r)for(i=0,o=C(this),s=bt(e);t=s[i++];)o.hasClass(t)?o.removeClass(t):o.addClass(t);else void 0!==e&&"boolean"!==n||((t=yt(this))&&Z.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":Z.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+vt(yt(n))+" ").indexOf(t)>-1)return!0;return!1}});var xt=/\r/g;C.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=v(e),this.each((function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,C(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=C.map(i,(function(e){return null==e?"":e+""}))),(t=C.valHooks[this.type]||C.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))}))):i?(t=C.valHooks[i.type]||C.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(xt,""):null==n?"":n:void 0}}),C.extend({valHooks:{option:{get:function(e){var t=C.find.attr(e,"value");return null!=t?t:vt(C.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,s="select-one"===e.type,a=s?null:[],l=s?o+1:i.length;for(r=o<0?l:s?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),C.each(["radio","checkbox"],(function(){C.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=C.inArray(C(e).val(),t)>-1}},m.checkOn||(C.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})})),m.focusin="onfocusin"in r;var wt=/^(?:focusinfocus|focusoutblur)$/,_t=function(e){e.stopPropagation()};C.extend(C.event,{trigger:function(e,t,n,i){var o,s,a,l,c,u,p,d,h=[n||b],g=f.call(e,"type")?e.type:e,m=f.call(e,"namespace")?e.namespace.split("."):[];if(s=d=a=n=n||b,3!==n.nodeType&&8!==n.nodeType&&!wt.test(g+C.event.triggered)&&(g.indexOf(".")>-1&&(m=g.split("."),g=m.shift(),m.sort()),c=g.indexOf(":")<0&&"on"+g,(e=e[C.expando]?e:new C.Event(g,"object"==typeof e&&e)).isTrigger=i?2:3,e.namespace=m.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:C.makeArray(t,[e]),p=C.event.special[g]||{},i||!p.trigger||!1!==p.trigger.apply(n,t))){if(!i&&!p.noBubble&&!y(n)){for(l=p.delegateType||g,wt.test(l+g)||(s=s.parentNode);s;s=s.parentNode)h.push(s),a=s;a===(n.ownerDocument||b)&&h.push(a.defaultView||a.parentWindow||r)}for(o=0;(s=h[o++])&&!e.isPropagationStopped();)d=s,e.type=o>1?l:p.bindType||g,(u=(Z.get(s,"events")||Object.create(null))[e.type]&&Z.get(s,"handle"))&&u.apply(s,t),(u=c&&s[c])&&u.apply&&V(s)&&(e.result=u.apply(s,t),!1===e.result&&e.preventDefault());return e.type=g,i||e.isDefaultPrevented()||p._default&&!1!==p._default.apply(h.pop(),t)||!V(n)||c&&v(n[g])&&!y(n)&&((a=n[c])&&(n[c]=null),C.event.triggered=g,e.isPropagationStopped()&&d.addEventListener(g,_t),n[g](),e.isPropagationStopped()&&d.removeEventListener(g,_t),C.event.triggered=void 0,a&&(n[c]=a)),e.result}},simulate:function(e,t,n){var r=C.extend(new C.Event,n,{type:e,isSimulated:!0});C.event.trigger(r,null,t)}}),C.fn.extend({trigger:function(e,t){return this.each((function(){C.event.trigger(e,t,this)}))},triggerHandler:function(e,t){var n=this[0];if(n)return C.event.trigger(e,t,n,!0)}}),m.focusin||C.each({focus:"focusin",blur:"focusout"},(function(e,t){var n=function(e){C.event.simulate(t,e.target,C.event.fix(e))};C.event.special[t]={setup:function(){var r=this.ownerDocument||this.document||this,i=Z.access(r,t);i||r.addEventListener(e,n,!0),Z.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this.document||this,i=Z.access(r,t)-1;i?Z.access(r,t,i):(r.removeEventListener(e,n,!0),Z.remove(r,t))}}}));var Tt=r.location,Ct={guid:Date.now()},At=/\?/;C.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new r.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||C.error("Invalid XML: "+(n?C.map(n.childNodes,(function(e){return e.textContent})).join("\n"):e)),t};var Et=/\[\]$/,St=/\r?\n/g,$t=/^(?:submit|button|image|reset|file)$/i,Dt=/^(?:input|select|textarea|keygen)/i;function kt(e,t,n,r){var i;if(Array.isArray(t))C.each(t,(function(t,i){n||Et.test(e)?r(e,i):kt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)}));else if(n||"object"!==_(t))r(e,t);else for(i in t)kt(e+"["+i+"]",t[i],n,r)}C.param=function(e,t){var n,r=[],i=function(e,t){var n=v(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!C.isPlainObject(e))C.each(e,(function(){i(this.name,this.value)}));else for(n in e)kt(n,e[n],t,i);return r.join("&")},C.fn.extend({serialize:function(){return C.param(this.serializeArray())},serializeArray:function(){return this.map((function(){var e=C.prop(this,"elements");return e?C.makeArray(e):this})).filter((function(){var e=this.type;return this.name&&!C(this).is(":disabled")&&Dt.test(this.nodeName)&&!$t.test(e)&&(this.checked||!me.test(e))})).map((function(e,t){var n=C(this).val();return null==n?null:Array.isArray(n)?C.map(n,(function(e){return{name:t.name,value:e.replace(St,"\r\n")}})):{name:t.name,value:n.replace(St,"\r\n")}})).get()}});var jt=/%20/g,Lt=/#.*$/,Ot=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Nt=/^(?:GET|HEAD)$/,Pt=/^\/\//,Ht={},It={},Rt="*/".concat("*"),Mt=b.createElement("a");function Ut(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(I)||[];if(v(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function Ft(e,t,n,r){var i={},o=e===It;function s(a){var l;return i[a]=!0,C.each(e[a]||[],(function(e,a){var c=a(t,n,r);return"string"!=typeof c||o||i[c]?o?!(l=c):void 0:(t.dataTypes.unshift(c),s(c),!1)})),l}return s(t.dataTypes[0])||!i["*"]&&s("*")}function Wt(e,t){var n,r,i=C.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&C.extend(!0,e,r),e}Mt.href=Tt.href,C.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Rt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":C.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Wt(Wt(e,C.ajaxSettings),t):Wt(C.ajaxSettings,e)},ajaxPrefilter:Ut(Ht),ajaxTransport:Ut(It),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var n,i,o,s,a,l,c,u,p,d,f=C.ajaxSetup({},t),h=f.context||f,g=f.context&&(h.nodeType||h.jquery)?C(h):C.event,m=C.Deferred(),v=C.Callbacks("once memory"),y=f.statusCode||{},x={},w={},_="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s)for(s={};t=qt.exec(o);)s[t[1].toLowerCase()+" "]=(s[t[1].toLowerCase()+" "]||[]).concat(t[2]);t=s[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return c?o:null},setRequestHeader:function(e,t){return null==c&&(e=w[e.toLowerCase()]=w[e.toLowerCase()]||e,x[e]=t),this},overrideMimeType:function(e){return null==c&&(f.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)T.always(e[T.status]);else for(t in e)y[t]=[y[t],e[t]];return this},abort:function(e){var t=e||_;return n&&n.abort(t),A(0,t),this}};if(m.promise(T),f.url=((e||f.url||Tt.href)+"").replace(Pt,Tt.protocol+"//"),f.type=t.method||t.type||f.method||f.type,f.dataTypes=(f.dataType||"*").toLowerCase().match(I)||[""],null==f.crossDomain){l=b.createElement("a");try{l.href=f.url,l.href=l.href,f.crossDomain=Mt.protocol+"//"+Mt.host!=l.protocol+"//"+l.host}catch(e){f.crossDomain=!0}}if(f.data&&f.processData&&"string"!=typeof f.data&&(f.data=C.param(f.data,f.traditional)),Ft(Ht,f,t,T),c)return T;for(p in(u=C.event&&f.global)&&0==C.active++&&C.event.trigger("ajaxStart"),f.type=f.type.toUpperCase(),f.hasContent=!Nt.test(f.type),i=f.url.replace(Lt,""),f.hasContent?f.data&&f.processData&&0===(f.contentType||"").indexOf("application/x-www-form-urlencoded")&&(f.data=f.data.replace(jt,"+")):(d=f.url.slice(i.length),f.data&&(f.processData||"string"==typeof f.data)&&(i+=(At.test(i)?"&":"?")+f.data,delete f.data),!1===f.cache&&(i=i.replace(Ot,"$1"),d=(At.test(i)?"&":"?")+"_="+Ct.guid+++d),f.url=i+d),f.ifModified&&(C.lastModified[i]&&T.setRequestHeader("If-Modified-Since",C.lastModified[i]),C.etag[i]&&T.setRequestHeader("If-None-Match",C.etag[i])),(f.data&&f.hasContent&&!1!==f.contentType||t.contentType)&&T.setRequestHeader("Content-Type",f.contentType),T.setRequestHeader("Accept",f.dataTypes[0]&&f.accepts[f.dataTypes[0]]?f.accepts[f.dataTypes[0]]+("*"!==f.dataTypes[0]?", "+Rt+"; q=0.01":""):f.accepts["*"]),f.headers)T.setRequestHeader(p,f.headers[p]);if(f.beforeSend&&(!1===f.beforeSend.call(h,T,f)||c))return T.abort();if(_="abort",v.add(f.complete),T.done(f.success),T.fail(f.error),n=Ft(It,f,t,T)){if(T.readyState=1,u&&g.trigger("ajaxSend",[T,f]),c)return T;f.async&&f.timeout>0&&(a=r.setTimeout((function(){T.abort("timeout")}),f.timeout));try{c=!1,n.send(x,A)}catch(e){if(c)throw e;A(-1,e)}}else A(-1,"No Transport");function A(e,t,s,l){var p,d,b,x,w,_=t;c||(c=!0,a&&r.clearTimeout(a),n=void 0,o=l||"",T.readyState=e>0?4:0,p=e>=200&&e<300||304===e,s&&(x=function(e,t,n){for(var r,i,o,s,a=e.contents,l=e.dataTypes;"*"===l[0];)l.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){l.unshift(i);break}if(l[0]in n)o=l[0];else{for(i in n){if(!l[0]||e.converters[i+" "+l[0]]){o=i;break}s||(s=i)}o=o||s}if(o)return o!==l[0]&&l.unshift(o),n[o]}(f,T,s)),!p&&C.inArray("script",f.dataTypes)>-1&&C.inArray("json",f.dataTypes)<0&&(f.converters["text script"]=function(){}),x=function(e,t,n,r){var i,o,s,a,l,c={},u=e.dataTypes.slice();if(u[1])for(s in e.converters)c[s.toLowerCase()]=e.converters[s];for(o=u.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=u.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(!(s=c[l+" "+o]||c["* "+o]))for(i in c)if((a=i.split(" "))[1]===o&&(s=c[l+" "+a[0]]||c["* "+a[0]])){!0===s?s=c[i]:!0!==c[i]&&(o=a[0],u.unshift(a[1]));break}if(!0!==s)if(s&&e.throws)t=s(t);else try{t=s(t)}catch(e){return{state:"parsererror",error:s?e:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}(f,x,T,p),p?(f.ifModified&&((w=T.getResponseHeader("Last-Modified"))&&(C.lastModified[i]=w),(w=T.getResponseHeader("etag"))&&(C.etag[i]=w)),204===e||"HEAD"===f.type?_="nocontent":304===e?_="notmodified":(_=x.state,d=x.data,p=!(b=x.error))):(b=_,!e&&_||(_="error",e<0&&(e=0))),T.status=e,T.statusText=(t||_)+"",p?m.resolveWith(h,[d,_,T]):m.rejectWith(h,[T,_,b]),T.statusCode(y),y=void 0,u&&g.trigger(p?"ajaxSuccess":"ajaxError",[T,f,p?d:b]),v.fireWith(h,[T,_]),u&&(g.trigger("ajaxComplete",[T,f]),--C.active||C.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return C.get(e,t,n,"json")},getScript:function(e,t){return C.get(e,void 0,t,"script")}}),C.each(["get","post"],(function(e,t){C[t]=function(e,n,r,i){return v(n)&&(i=i||r,r=n,n=void 0),C.ajax(C.extend({url:e,type:t,dataType:i,data:n,success:r},C.isPlainObject(e)&&e))}})),C.ajaxPrefilter((function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")})),C._evalUrl=function(e,t,n){return C.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){C.globalEval(e,t,n)}})},C.fn.extend({wrapAll:function(e){var t;return this[0]&&(v(e)&&(e=e.call(this[0])),t=C(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map((function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e})).append(this)),this},wrapInner:function(e){return v(e)?this.each((function(t){C(this).wrapInner(e.call(this,t))})):this.each((function(){var t=C(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)}))},wrap:function(e){var t=v(e);return this.each((function(n){C(this).wrapAll(t?e.call(this,n):e)}))},unwrap:function(e){return this.parent(e).not("body").each((function(){C(this).replaceWith(this.childNodes)})),this}}),C.expr.pseudos.hidden=function(e){return!C.expr.pseudos.visible(e)},C.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},C.ajaxSettings.xhr=function(){try{return new r.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},zt=C.ajaxSettings.xhr();m.cors=!!zt&&"withCredentials"in zt,m.ajax=zt=!!zt,C.ajaxTransport((function(e){var t,n;if(m.cors||zt&&!e.crossDomain)return{send:function(i,o){var s,a=e.xhr();if(a.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(s in e.xhrFields)a[s]=e.xhrFields[s];for(s in e.mimeType&&a.overrideMimeType&&a.overrideMimeType(e.mimeType),e.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest"),i)a.setRequestHeader(s,i[s]);t=function(e){return function(){t&&(t=n=a.onload=a.onerror=a.onabort=a.ontimeout=a.onreadystatechange=null,"abort"===e?a.abort():"error"===e?"number"!=typeof a.status?o(0,"error"):o(a.status,a.statusText):o(Bt[a.status]||a.status,a.statusText,"text"!==(a.responseType||"text")||"string"!=typeof a.responseText?{binary:a.response}:{text:a.responseText},a.getAllResponseHeaders()))}},a.onload=t(),n=a.onerror=a.ontimeout=t("error"),void 0!==a.onabort?a.onabort=n:a.onreadystatechange=function(){4===a.readyState&&r.setTimeout((function(){t&&n()}))},t=t("abort");try{a.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}})),C.ajaxPrefilter((function(e){e.crossDomain&&(e.contents.script=!1)})),C.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return C.globalEval(e),e}}}),C.ajaxPrefilter("script",(function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")})),C.ajaxTransport("script",(function(e){var t,n;if(e.crossDomain||e.scriptAttrs)return{send:function(r,i){t=C("
Toptal

gitignore.io

gitignore.io

#(subtitleString)

#embed("internal-linking")
================================================ FILE: Resources/Views/internal-linking.leaf ================================================
Skills in High Demand
by Toptal Clients
#for(link in links.links) { #(link.title) }
================================================ FILE: Resources/links.json ================================================ [ { "url": "https://www.toptal.com/freelance-jobs/developers/react", "title": "React.js Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/nodejs", "title": "Node.js Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/ruby-on-rails", "title": "Ruby on Rails Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/azure", "title": "Azure Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/react-native", "title": "React Native Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/qa", "title": "QA Engineer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/go", "title": "Go Engineer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/javascript", "title": "JavaScript Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/python", "title": "Python Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/django", "title": "Django Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/php", "title": "PHP Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/c-sharp", "title": "C# Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/ios", "title": "iOS Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/blockchain", "title": "Blockchain Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/swift", "title": "Swift Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/aws", "title": "AWS Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/vue-js", "title": "Vue.js Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/java", "title": "Java Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/dot-net", "title": ".NET Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/angular", "title": "Angular Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/android", "title": "Android Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/magento", "title": "Magento Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/shopify", "title": "Shopify Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/wordpress", "title": "WordPress Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/laravel", "title": "Laravel Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/elixir", "title": "Elixir Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/docker", "title": "Docker Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/flutter", "title": "Flutter Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/software-architect", "title": "Software Architect Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/unity-unity3d", "title": "Unity or Unity3D Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/cloud", "title": "Cloud Engineer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/asp-dot-net", "title": "ASP.NET Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/kubernetes", "title": "Kubernetes Expert Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/security", "title": "System Security Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/kotlin", "title": "Kotlin Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/css", "title": "CSS Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/computer-vision", "title": "Computer Vision Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/artificial-intelligence", "title": "AI Engineer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/drupal", "title": "Drupal Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/sql", "title": "SQL Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/symfony", "title": "Symfony Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/ruby", "title": "Ruby Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/data-science", "title": "Data Scientist Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/business-intelligence", "title": "Business Intelligence Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/c-plus-plus", "title": "C++ Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/ionic", "title": "Ionic Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/graphql", "title": "GraphQL Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/machine-learning", "title": "Machine Learning Engineer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/xamarin", "title": "Xamarin Developer Jobs" }, { "url": "https://www.toptal.com/freelance-jobs/developers/firebase", "title": "Firebase Developer Jobs" } ] ================================================ FILE: Sources/App/Controllers/InternalLinkingController.swift ================================================ import Vapor internal protocol ReadOnlyInternalLinkingProtocol { var links: InternalLinks { get } } internal struct InternalLinkingController: ReadOnlyInternalLinkingProtocol { internal var links = InternalLinks(links: [InternalLink]()) init() { let directory = DirectoryConfig.detect() let internalLinksFilePath = URL(fileURLWithPath: directory.workDir) .appendingPathComponent("Resources", isDirectory: true) .appendingPathComponent("links.json", isDirectory: false) var rawLinks = [InternalLink]() do { let jsonData = try Data(contentsOf: internalLinksFilePath) rawLinks = try JSONDecoder().decode([InternalLink].self, from: jsonData) self.links = InternalLinks(links: rawLinks) } catch { print("‼️ Could not load internal links from json, check:\n‼️ Resources/links.json") } } } ================================================ FILE: Sources/App/Controllers/ReadOnlyTemplateManagerProtocol.swift ================================================ // // ReadOnlyTemplateManagerProtocol.swift // GitignoreIO // // Created by Joseph Blau on 1/29/17. // // internal protocol ReadOnlyTemplateManagerProtocol { var order: [String: Int] { get } var count: Int { get } var templates: [String: IgnoreTemplateModel] { get } } ================================================ FILE: Sources/App/Controllers/TemplateController.swift ================================================ // // TemplateController.swift // GitignoreIO // // Created by Joe Blau on 12/17/16. // // import Foundation internal struct TemplateController: ReadOnlyTemplateManagerProtocol { internal var order = [String: Int]() internal var count = 0 internal var templates = [String: IgnoreTemplateModel]() /// Create Template Controller /// /// - Returns: Template Controller init(dataDirectory: URL, orderFile: URL) { do { order = try parseFile(orderFile: orderFile) templates = try parseTemplateDirectory(dataDirectory: dataDirectory) try templates.patchTemplates(dataDirectory: dataDirectory) try templates.stackTempaltes(dataDirectory: dataDirectory) count = templates.count } catch { print("‼️ You might not have done a recursive clone to update your submodules:\n‼️ `git submodule update --init --recursive`") } } // MARK: - Private /// Parse file which defines template order precedence /// /// - Parameter orderFile: The dependency order file /// - Returns: List of templates in order precedence private func parseFile(orderFile: URL) throws -> [String: Int] { return try String(contentsOf: orderFile, encoding: String.Encoding.utf8) .replacingOccurrences(of: "\r\n", with: "\n", options: .regularExpression) .components(separatedBy: "\n") .map({ (line) -> String in line.trimmingCharacters(in: .whitespaces).lowercased() }) .filter({ (line) -> Bool in !line.hasPrefix("#") && !line.isEmpty }) .enumerated() .reduce([String: Int](), { (orderedDict, line : (offset: Int, text: String)) -> [String: Int] in var mutableOrderedDict = orderedDict mutableOrderedDict[line.text] = line.offset return mutableOrderedDict }) } /// Parse template directory /// /// - Parameter dataDirectory: The path to the data directory /// - Returns: Ignore template model dictionary private func parseTemplateDirectory(dataDirectory: URL) throws -> [String: IgnoreTemplateModel] { return try FileManager().enumerator(at: dataDirectory, includingPropertiesForKeys: nil)! .allObjects .compactMap({ (templatePath: Any) -> URL? in templatePath as? URL }) .filter({ (templatePath: URL) -> Bool in templatePath.pathExtension == TemplateSuffix.template.extension }) .compactMap({ (templatePath: URL) -> (key: String, model: IgnoreTemplateModel) in let fileContents = try String(contentsOf: templatePath, encoding: String.Encoding.utf8) .replacingOccurrences(of: "\r\n", with: "\n", options: .regularExpression) return (key: templatePath.name.lowercased(), model: IgnoreTemplateModel(key: templatePath.name.lowercased(), name: templatePath.name, fileName: templatePath.fileName, contents: TemplateSuffix.template.header(name: templatePath.name).appending(fileContents))) }) .reduce([String: IgnoreTemplateModel]()) { (currentTemplateModels, templateData) in var mutableCurrentTemplates = currentTemplateModels mutableCurrentTemplates[templateData.key] = templateData.model return mutableCurrentTemplates } } } ================================================ FILE: Sources/App/Enum/TemplateSuffix.swift ================================================ // // TemplateSuffix.swift // GitignoreIO // // Created by Joseph Blau on 1/29/17. // // /// Template Suffix Enum internal enum TemplateSuffix { case template, patch, stack internal var `extension`: String { switch self { case .template: return "gitignore" case .patch: return "patch" case .stack: return "stack" } } internal func header(name: String) -> String { switch self { case .template: return "\n### \(name) ###\n" case .patch: return "\n### \(name) Patch ###\n" case .stack: return "\n### \(name) Stack ###\n" } } } ================================================ FILE: Sources/App/Extensions/Dictionary+Extensions.swift ================================================ // // Dictionary+Extensions.swift // GitignoreIO // // Created by Joseph Blau on 1/29/17. // // import Foundation internal extension Dictionary where Key: ExpressibleByStringLiteral, Value: IgnoreTemplateModeling { /// Append template patches to template contents /// /// - Parameter dataDirectory: The path to the data directory mutating func patchTemplates(dataDirectory: URL) throws { try FileManager().templatePathsFor(dataDirectory)? .filter({ (templatePath: URL) -> Bool in templatePath.pathExtension == TemplateSuffix.patch.extension }) .forEach({ (templatePath: URL) in let fileContents = try String(contentsOf: templatePath, encoding: String.Encoding.utf8) if let path = templatePath.name.lowercased() as? Key { self[path]? .contents .append(TemplateSuffix.patch.header(name: templatePath.name) + fileContents) } }) } /// Append stacks to template contents /// /// - Parameter dataDictionary: The path to the data dictionary mutating func stackTempaltes(dataDirectory: URL) throws { try FileManager().templatePathsFor(dataDirectory)? .filter({ (templatePath: URL) -> Bool in templatePath.pathExtension == TemplateSuffix.stack.extension }) .forEach({ (templatePath: URL) in let fileContents = try String(contentsOf: templatePath, encoding: String.Encoding.utf8) if let path = templatePath.stackName?.lowercased() as? Key { self[path]? .contents .append(TemplateSuffix.stack.header(name: templatePath.name) + fileContents) } }) } } ================================================ FILE: Sources/App/Extensions/FileManager+Extensions.swift ================================================ // // FileManager+Extensions.swift // App // // Created by Joe Blau on 6/23/18. // import Foundation extension FileManager { func templatePathsFor(_ dataDirectory: URL) -> [URL]? { return self.enumerator(at: dataDirectory, includingPropertiesForKeys: nil)? .allObjects .compactMap { (templatePath: Any) -> URL? in templatePath as? URL } } } ================================================ FILE: Sources/App/Extensions/Router+Extensions.swift ================================================ // // Router+Extensions.swift // App // // Created by Joe Blau on 7/2/18. // import Vapor extension Request { var acceptLanguage: String { get { let acceptLanguage = String(self.http .headers .firstValue(name: .acceptLanguage)? .split(separator: ",") .first? .split(separator: "-") .first ?? "en") let supportedLanguages = ["ar", "cs", "de", "en", "fa", "fr", "id", "ja", "ko", "pt", "ro", "ru", "tr", "zh", "nl", "el", "th"] if supportedLanguages.contains(acceptLanguage) { return acceptLanguage } else { return "en" } } } } ================================================ FILE: Sources/App/Extensions/Sequence+Extensions.swift ================================================ // // Sequence+Extensions.swift // GitignoreIO // // Created by Joseph Blau on 1/29/17. // // import Foundation public extension Sequence where Iterator.Element: Hashable { var uniqueElements: [Iterator.Element] { return Array( Set(self) ) } } ================================================ FILE: Sources/App/Extensions/String+Extensions.swift ================================================ // // String+Extensions.swift // GitignoreIO // // Created by Joe Blau on 12/18/16. // // import Foundation internal extension String { /// Remove duplicate lines, except blank strings or comment strings /// /// - Returns: String with duplicate lines removed func removeDuplicateLines() -> String { return self.components(separatedBy: "\n") .reduce([String]()) { if !$1.isEmpty && !$1.hasPrefix("# ") && $0.contains($1) { return $0 } return $0 + [$1] } .joined(separator: "\n") } } ================================================ FILE: Sources/App/Extensions/URL+Extensions.swift ================================================ // // URL+Extensions.swift // GitignoreIO // // Created by Joseph Blau on 1/29/17. // // import Foundation internal extension URL { /// Name of file without extension var name: String { return self.deletingPathExtension().lastPathComponent } /// Name of file first component var stackName: String? { return self.deletingPathExtension().lastPathComponent.components(separatedBy: ".").first } /// Name of file with extension var fileName: String { return self.lastPathComponent } } ================================================ FILE: Sources/App/Middleware/FileMiddlewareWithBasePrefix.swift ================================================ /// Serves static files from a public directory. /// /// middlewareConfig = MiddlewareConfig() /// middlewareConfig.use(FileMiddlewareWithBasePrefix.self) /// services.register(middlewareConfig) /// /// `FileMiddlewareWithBasePrefix` will default to `DirectoryConfig`'s working directory with `"/Public"` appended. import Vapor public final class FileMiddlewareWithBasePrefix: Middleware, ServiceType { /// See `ServiceType`. public static func makeService(for container: Container) throws -> FileMiddlewareWithBasePrefix { return try .init(publicDirectory: container.make(DirectoryConfig.self).workDir + "Public/") } /// The public directory. /// - note: Must end with a slash. private let publicDirectory: String /// Creates a new `FileMiddlewareWithBasePrefix`. public init(publicDirectory: String) { self.publicDirectory = publicDirectory.hasSuffix("/") ? publicDirectory : publicDirectory + "/" } /// See `Middleware`. public func respond(to req: Request, chainingTo next: Responder) throws -> Future { // make a copy of the path var path = req.http.url.path if let basePrefix = Environment.get("BASE_PREFIX") { if path.hasPrefix(basePrefix) { path = String(path.dropFirst(basePrefix.count)) } } // path must be relative. while path.hasPrefix("/") { path = String(path.dropFirst()) } // protect against relative paths guard !path.contains("../") else { throw Abort(.forbidden) } // create absolute file path let filePath = publicDirectory + path // check if file exists and is not a directory var isDir: ObjCBool = false guard FileManager.default.fileExists(atPath: filePath, isDirectory: &isDir), !isDir.boolValue else { return try next.respond(to: req) } // stream the file return try req.streamFile(at: filePath) } } ================================================ FILE: Sources/App/Models/Dropdown.swift ================================================ // // Dropdown.swift // App // // Created by Joe Blau on 6/9/18. // import Vapor internal struct Dropdown: Content { var id: String var text: String } ================================================ FILE: Sources/App/Models/Flags.swift ================================================ // // Flags.swift // App // // Created by Joe Blau on 6/21/18. // import Vapor struct Flags: Content { var term: String? var format: String? } ================================================ FILE: Sources/App/Models/IgnoreTemplateModel.swift ================================================ // // IgnoreTemplateModel.swift // GitignoreIO // // Created by Joe Blau on 12/18/16. // // import Vapor internal struct IgnoreTemplateModel: IgnoreTemplateModeling { var key: String var name: String var fileName: String var contents: String } extension IgnoreTemplateModel: CustomStringConvertible { var description: String { return "KEY: \(key)\nNAME: \(name)FILE NAME: \(fileName)\nCONTENTS: \(contents)\n" } } ================================================ FILE: Sources/App/Models/IgnoreTemplateModeling.swift ================================================ // // IgnoreTemplateModeling.swift // GitignoreIO // // Created by Joseph Blau on 1/29/17. // // internal protocol IgnoreTemplateModeling: Codable { var key: String { get set } var name: String { get set } var fileName: String { get set } var contents: String { get set } } ================================================ FILE: Sources/App/Models/InternalLink.swift ================================================ struct InternalLink: Codable { let title: String let url: String } struct InternalLinks: Encodable { var links: [InternalLink] } ================================================ FILE: Sources/App/RouteHandlers/APIRouteHandlers.swift ================================================ // // APIRouteHandler.swift // GitignoreIO // // Created by Joe Blau on 12/17/16. // // import Foundation import Vapor import HTTP import Lingo internal class APIHandlers { private let splitSize = 5 private var order: [String: Int]! private var templates: [String: IgnoreTemplateModel]! /// Initialze the API Handlers extension /// /// - Parameter templateController: All of the gitignore template objects init(templateController: TemplateController) { templates = templateController.templates order = templateController.order } /// Create the API endpoint for serving ignore templates /// /// - Parameter router: Vapor server side Swift router internal func createIgnoreEndpoint(router: Router) { router.get(UrlResolver.withBasePrefix("/api"), String.parameter) { request -> Response in let response = request.response() let ignoreString = try request.parameters.next(String.self) let (template, status) = self.createTemplate(ignoreString: ignoreString) try response.content.encode(template) response.http.status = status return response } } /// Create the API endpoint for downloading ignore templates /// /// - Parameter router: Vapor server side Swift router internal func createTemplateDownloadEndpoint(router: Router) { router.get(UrlResolver.withBasePrefix("/api/f"), String.parameter) { request -> HTTPResponse in let ignoreString = try request.parameters.next(String.self) let (template, status) = self.createTemplate(ignoreString: ignoreString) return HTTPResponse(status: status, version: HTTPVersion(major: 1, minor: 0), headers: HTTPHeaders([(HTTPHeaderName.contentDisposition.description, "attachment; filename=\"gitignore\"")]), body: template) } } /// Create the API endpoint for showing the list of templates /// /// - Parameter router: Vapor server side Swift router internal func createListEndpoint(router: Router) { router.get(UrlResolver.withBasePrefix("/api/list")) { request -> Response in let response = request.response() let templateKeys = self.templates.keys.sorted() guard let flags = try? request.query.decode(Flags.self), let format = flags.format else { let groupedLines = stride(from: 0, to: templateKeys.count, by: self.splitSize) .map { templateKeys[$0.. Response in let response = request.response() try response.content.encode(json: self.order) return response } } /// Create the API endpoint for help /// /// - Parameter router: Vapor server side Swift router internal func createHelp(router: Router) { router.get(UrlResolver.withBasePrefix("/api/")) { _ in """ gitignore.io help: list - lists the operating systems, programming languages and IDE input types :types: - creates .gitignore files for types of operating systems, programming languages or IDEs """ } } // MARK: - Private /// Create final output template sorted based on `data/order` file with headers /// and footers applied to templates /// /// - Parameter ignoreString: Comma separated string of templates to generate /// /// - Peturns: Final formatted template with headers and footers private func createTemplate(ignoreString: String) -> (template: String, status: HTTPResponseStatus) { guard let urlDecoded = ignoreString.removingPercentEncoding else { return (""" #!! ERROR: url decoding \(ignoreString) !# """, .internalServerError) } var createStatus: HTTPResponseStatus = .ok let canonicalUrl = UrlResolver.getCanonicalUrl() let template = urlDecoded .lowercased() .components(separatedBy: ",") .uniqueElements .sorted() .sorted(by: { (left: String, right: String) -> Bool in (self.order[left] ?? 0) < (self.order[right] ?? 0) }) .map { (templateKey) -> String in guard let contents = self.templates[templateKey]?.contents else { createStatus = .notFound return """ #!! ERROR: \(templateKey) is undefined. Use list command to see defined gitignore types !!# """ } return contents.replacingOccurrences(of: "Icon\r\n", with: "Icon\r\r\n", options: .regularExpression) } .reduce(""" # Created by \(canonicalUrl)/api/\(urlDecoded) # Edit at \(canonicalUrl)?templates=\(urlDecoded) """) { (currentTemplate, contents) -> String in return currentTemplate.appending(contents) } .appending(""" # End of \(canonicalUrl)/api/\(urlDecoded) """) .removeDuplicateLines() return (template: template, status: createStatus) } } ================================================ FILE: Sources/App/RouteHandlers/SiteRouteHandlers.swift ================================================ // // SiteRouteHandlers.swift // GitignoreIO // // Created by Joe Blau on 11/7/16. // // import Vapor import Leaf import Lingo struct IndexPageContext: Encodable { var titleString: String? var basePrefixString: String? var canonicalUrlString: String? var googleAnalyticsUIDString: String? var descriptionString: String? var searchPlaceholderString: String? var searchGoString: String? var searchDownloadString: String? var subtitleString: String? var sourceCodeDescriptionString: String? var sourceCodeTitleString: String? var commandLineDescriptionString: String? var commandLineTitleString: String? var videoDescriptionString: String? var videoTitleString: String? var footerString: String? var links: InternalLinks? } internal class SiteHandlers { private let count: String private let templates: [String: IgnoreTemplateModel] private let env: Environment! private var links: InternalLinks /// Initialze the Site Handlers extension /// /// - Parameter templateController: All of the gitignore template objects init(templateController: TemplateController, env: Environment, internalLinkingController: InternalLinkingController) { self.count = String(templateController.count) self.templates = templateController.templates self.env = env self.links = internalLinkingController.links } /// Create Index Page /// /// - Parameter router: Vapor server side Swift Router internal func createIndexPage(router: Router) { router.get(UrlResolver.withBasePrefix("/")) { request -> Future in let leaf = try request.make(LeafRenderer.self) let lingo = try request.make(Lingo.self) let locale = request.acceptLanguage let context = IndexPageContext( titleString: lingo.localize("title", locale: locale), basePrefixString: UrlResolver.withBasePrefix("/"), canonicalUrlString: UrlResolver.getCanonicalUrl(), googleAnalyticsUIDString: Environment.get("GOOGLE_ANALYTICS_UID"), descriptionString: lingo.localize("description", locale: locale, interpolations: ["templateCount": self.count]), searchPlaceholderString: lingo.localize("searchPlaceholder", locale: locale), searchGoString: lingo.localize("searchGo", locale: locale), searchDownloadString: lingo.localize("searchDownload", locale: locale), subtitleString: lingo.localize("subtitle", locale: locale), sourceCodeDescriptionString: lingo.localize("sourceCodeDescription", locale: locale), sourceCodeTitleString: lingo.localize("sourceCodeTitle", locale: locale), commandLineDescriptionString: lingo.localize("commandLineDescription", locale: locale), commandLineTitleString: lingo.localize("commandLineTitle", locale: locale), videoDescriptionString: lingo.localize("videoDescription", locale: locale), videoTitleString: lingo.localize("videoTitle", locale: locale), footerString: lingo.localize("footer", locale: locale, interpolations: ["templateCount": self.count]), links: self.links ) return leaf.render("index", context) } } /// Create health check endpoint /// /// - Parameter router: Vapor server side Swift Router internal func addHealthEndpoint(router: Router) { router.get(UrlResolver.withBasePrefix("/health")) { request -> HTTPResponse in return HTTPResponse(status: .ok, body: "ok") } } /// Create dropdown template JSON list /// /// - Parameter router: Vapor server side Swift Router internal func createDropdownTemplates(router: Router) { router.get(UrlResolver.withBasePrefix("/dropdown/templates.json")) { request -> [Dropdown] in guard let flags = try? request.query.decode(Flags.self), let term = flags.term else { return self.createSortedDropdownTemplates() } return self.createSortedDropdownTemplates(query: term) } } /// Create dropdown list template /// /// - Parameter templates: Template controller template dictionary /// /// - Returns: JSON array containing all templates private func createSortedDropdownTemplates(query: String? = nil) -> [Dropdown] { return templates .values .filter({ (templateModel) -> Bool in guard let query = query else { return true } return templateModel.key.contains(query) }) .sorted(by: { $0.key < $1.key }) .sorted(by: { $0.key.count < $1.key.count }) .map { (templateModel) -> Dropdown in return Dropdown(id: templateModel.key, text: templateModel.name) } } } ================================================ FILE: Sources/App/RouteHandlers/UrlResolver.swift ================================================ import Vapor public final class UrlResolver { static let HOST_ORIGIN_FALLBACK = "https://www.toptal.com" // reads "HOST_ORIGIN" from environment variables, leading/trailing "/"s will be removed public static func getHostOrigin() -> String { guard let hostOrigin = Environment.get("HOST_ORIGIN") else { return HOST_ORIGIN_FALLBACK } return hostOrigin.trimmingCharacters(in: ["/"]) } // generates canonical URL, based on "HOST_ORIGIN" and "BASE_PREFIX" envvars public static func getCanonicalUrl() -> String { let hostOrigin = self.getHostOrigin() guard let prefix = Environment.get("BASE_PREFIX") else { return hostOrigin } return hostOrigin + "/" + prefix.trimmingCharacters(in: ["/"]) } // adds "BASE_PREFIX" envvar to "route" (coming as a parameter) // used in route handlers public static func withBasePrefix(_ route: String) -> String { guard let prefix = Environment.get("BASE_PREFIX") else { return route } return "/" + prefix.trimmingCharacters(in: ["/"]) + route } } ================================================ FILE: Sources/App/Server.swift ================================================ // // Server.swift // GitignoreIO // // Created by Joe Blau on 12/22/16. // // import Vapor import Leaf import LingoVapor public class Gitignore { fileprivate let config: Config fileprivate var services: Services fileprivate let lingoProvider: LingoProvider fileprivate var middlewares: MiddlewareConfig public init() { config = Config.default() services = Services.default() middlewares = MiddlewareConfig() lingoProvider = LingoProvider(defaultLocale: "en", localizationsDir: "Localizations") } public func app(_ env: Environment) throws -> Application { try configure(env: env) let app = try Application(config: config, environment: env, services: services) return app } private func configure(env: Environment) throws { let router = EngineRouter.default() try routes(router, env: env) services.register(router, as: Router.self) try services.register(LeafProvider()) try services.register(lingoProvider) services.register(FileMiddlewareWithBasePrefix.self) middlewares.use(FileMiddlewareWithBasePrefix.self) middlewares.use(ErrorMiddleware.self) services.register(middlewares) } /// Register your application's routes here. private func routes(_ router: Router, env: Environment) throws { let dataDirectory = URL(fileURLWithPath: DirectoryConfig.detect().workDir, isDirectory: true) .absoluteURL.appendingPathComponent("gitignore", isDirectory: true) .absoluteURL.appendingPathComponent("templates", isDirectory: true) let orderFile = dataDirectory.absoluteURL.appendingPathComponent("order", isDirectory: false) let templateController = TemplateController(dataDirectory: dataDirectory, orderFile: orderFile) let internalLinkingController = InternalLinkingController() let siteHandlers = SiteHandlers(templateController: templateController, env: env, internalLinkingController: internalLinkingController) siteHandlers.createIndexPage(router: router) siteHandlers.createDropdownTemplates(router: router) siteHandlers.addHealthEndpoint(router: router) let apiHandlers = APIHandlers(templateController: templateController) apiHandlers.createIgnoreEndpoint(router: router) apiHandlers.createTemplateDownloadEndpoint(router: router) apiHandlers.createListEndpoint(router: router) apiHandlers.createOrderEndpoint(router: router) apiHandlers.createHelp(router: router) } } ================================================ FILE: Sources/Run/main.swift ================================================ import App let gitignore = Gitignore() try gitignore.app(.detect()).run() ================================================ FILE: Tests/AppTests/Controllers/TemplateControllerTests.swift ================================================ // // TemplateControllerTests.swift // GitignoreIO // // Created by Joe Blau on 12/22/16. // // import XCTest import Vapor import Foundation @testable import App class TemplateControllerTests: XCTestCase { static let allTests = [ ("testIncorrectDataDirectory", testIncorrectDataDirectory), ] func testIncorrectDataDirectory() { let rootDirectory = URL(fileURLWithPath: "") let noFile = URL(fileURLWithPath: "") let templateController = TemplateController(dataDirectory: rootDirectory, orderFile: noFile) XCTAssertEqual(templateController.order.count , 0) } } ================================================ FILE: Tests/AppTests/Extensions/Sequence+ExtensionsTest.swift ================================================ // // Sequence+ExtensionsTest.swift // AppTests // // Created by Joe Blau on 6/22/18. // import XCTest @testable import App class Sequence_ExtensionsTest: XCTestCase { static let allTests = [ ("testUniqueElements_numbers", testUniqueElements_numbers), ("testUniqueElements_strings", testUniqueElements_strings), ("testUniqueElements_emoji", testUniqueElements_emoji) ] func testUniqueElements_numbers() { let sequenceOfDuplciates = [1,2,3,3,4,5,6,1] let sequenceOfUniques = sequenceOfDuplciates.uniqueElements XCTAssertEqual(sequenceOfUniques.count, 6) } func testUniqueElements_strings() { let sequenceOfDuplciates = ["abc","def","hij","abc","abc","xyz","abc","def"] let sequenceOfUniques = sequenceOfDuplciates.uniqueElements XCTAssertEqual(sequenceOfUniques.count, 4) } func testUniqueElements_emoji() { let sequenceOfDuplciates = ["😂","😃","☺️","😂","😅","😘","😅"] let sequenceOfUniques = sequenceOfDuplciates.uniqueElements XCTAssertEqual(sequenceOfUniques.count, 5) } } ================================================ FILE: Tests/AppTests/Extensions/String+ExtensionsTests.swift ================================================ // // String+ExtensionsTests.swift // GitignoreIO // // Created by Joe Blau on 12/21/16. // // import XCTest import Foundation @testable import App class String_ExtensionsTests: XCTestCase { static let allTests = [ ("testStringName_valid", testStringName_valid), ("testStringName_empty", testStringName_empty), ("testStringFileName_valid", testStringFileName_valid), ("testStringFileName_empty", testStringFileName_empty), ("testRemoveDuplicateLines", testRemoveDuplicateLines), ] func testStringName_valid() { let path = URL(fileURLWithPath: "/User/ElonMusk/Developer/GitIgnoreIO/data/custom/tesla.gitignore") XCTAssertEqual(path.name, "tesla") } func testStringName_empty() { let path = URL(fileURLWithPath: "") XCTAssertFalse(path.name.isEmpty) } func testStringFileName_valid() { let path = URL(fileURLWithPath: "/User/ElonMusk/Developer/GitIgnoreIO/data/custom/tesla.gitignore") XCTAssertEqual(path.fileName, "tesla.gitignore") } func testStringFileName_empty() { let path = URL(fileURLWithPath: "") XCTAssertFalse(path.fileName.isEmpty) } func testRemoveDuplicateLines() { let string = "abc\n" .appending("#comment\n") .appending("\n") .appending("dup\n") .appending("\n") .appending("dup\n") .appending("xyz\n") let answer = "abc\n" .appending("#comment\n") .appending("\n") .appending("dup\n") .appending("\n") .appending("xyz\n") XCTAssertEqual(string.removeDuplicateLines(), answer) } } ================================================ FILE: Tests/AppTests/Extensions/URL+ExtensionsTests.swift ================================================ // // URL+ExtensionsTests.swift // GitignoreIO // // Created by Joseph Blau on 2/12/17. // // import XCTest import Vapor @testable import App class URL_ExtensionsTests: XCTestCase { static let allTests = [ ("testName", testName), ("testStackName", testStackName), ("testFileName", testFileName) ] func testName() { guard let mockURL = URL(string: "file://this/is/a/test/file.txt") else { XCTFail() return } XCTAssertEqual(mockURL.name, "file") } func testStackName() { guard let mockURL = URL(string: "file://this/is/a/test/file.txt") else { XCTFail() return } XCTAssertEqual(mockURL.stackName, "file") } func testFileName() { guard let mockURL = URL(string: "file://this/is/a/test/file.txt") else { XCTFail() return } XCTAssertEqual(mockURL.fileName, "file.txt") } } ================================================ FILE: Tests/AppTests/Models/IgnoreTemplateModelTests.swift ================================================ // // IgnoreTemplateModelTests.swift // GitignoreIO // // Created by Joe Blau on 12/21/16. // // import XCTest @testable import App class IgnoreTemplateModelTests: XCTestCase { static let allTests = [ ("testDescription", testDescription), ("testJSON", testJSON), ] func testDescription() { let item = IgnoreTemplateModel(key: "a", name: "b", fileName: "c", contents: "d") XCTAssertEqual("\(item)", "KEY: a\nNAME: bFILE NAME: c\nCONTENTS: d\n") } func testJSON() { let item = IgnoreTemplateModel(key: "a", name: "b", fileName: "c", contents: "d") XCTAssertEqual(item.name, "b") XCTAssertEqual(item.fileName, "c") XCTAssertEqual(item.contents, "d") } } ================================================ FILE: Tests/AppTests/RouteHandlers/APIHandlersTests.swift ================================================ // // APIHandlers.swift // GitignoreIO // // Created by Joe Blau on 12/22/16. // // import XCTest import Vapor import HTTP @testable import App class APIHandlersTests: XCTestCase { static let allTests = [ ("testServer_api_template", testServer_api_template), ("testServer_api_no_template", testServer_api_no_template), ("testServer_api_file_template", testServer_api_file_template), ("testServer_api_list", testServer_api_list), ("testServer_api_list_lines", testServer_api_list_lines), ("testServer_api_list_json", testServer_api_list_json), ("testServer_api_list_xyz", testServer_api_list_xyz), ("testServer_api_force_sort_sortable", testServer_api_force_sort_sortable), ("testServer_api_no_sort_sortalbe", testServer_api_no_sort_sortalbe), ("testServer_api_no_sort_not_sortable", testServer_api_no_sort_not_sortable), ("testServer_api_order", testServer_api_order), ("testServer_api", testServer_api), ] func testServer_api_template() throws { if let byteCount = try responseForRequest("/api/swift").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_no_template() throws { if let byteCount = try responseForRequest("/api/f/tesla").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_file_template() throws { if let byteCount = try responseForRequest("/api/f/swift").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_list() throws { if let byteCount = try responseForRequest("/api/list").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_list_lines() throws { if let byteCount = try responseForRequest("/api/list?format=lines").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_list_json() throws { if let byteCount = try responseForRequest("/api/list?format=json").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_list_xyz() throws { if let byteCount = try responseForRequest("/api/list?format=xyz").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_force_sort_sortable() throws { if let byteCount = try responseForRequest("/api/gradle,java").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_no_sort_sortalbe() throws { if let byteCount = try responseForRequest("/api/java,gradle").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_no_sort_not_sortable() throws { let body = try responseForRequest("/api/macos,swift").http.body XCTAssertFalse(body.description.contains("!! ERROR:")) XCTAssertTrue(body.description.contains("### macOS ###")) XCTAssertTrue(body.description.contains("### Swift ###")) if let byteCount = body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_url_multiple_url_encoded() throws { let body = try responseForRequest("/api/sbt%2Cscala%2Cintellij").http.body XCTAssertFalse(body.description.contains("!! ERROR:")) XCTAssertTrue(body.description.contains("### SBT ###")) XCTAssertTrue(body.description.contains("### Scala ###")) XCTAssertTrue(body.description.contains("### Intellij ###")) if let byteCount = body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api_order() throws { if let byteCount = try responseForRequest("/api/order").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_api() throws { if let byteCount = try responseForRequest("/api/").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } // MARK: - Private private func responseForRequest(_ url: String) throws -> Response { let application = try Gitignore().app(.detect()) let request = HTTPRequest(method: .GET, url: URL(string: url)!) let wrappedRequest = Request(http: request, using: application) let responder = try application.make(Responder.self) return try responder.respond(to: wrappedRequest).wait() } } ================================================ FILE: Tests/AppTests/RouteHandlers/SiteHandlersTests.swift ================================================ // // SiteHandlers.swift // GitignoreIO // // Created by Joe Blau on 12/22/16. // // import XCTest import Vapor import HTTP @testable import App class SiteHandlersTests: XCTestCase { static let allTests = [ ("testServer_index", testServer_index), ("testServer_docs", testServer_docs), ("testServer_templatesJSON_noTerm", testServer_templatesJSON_noTerm), ("testServer_templatesJSON_term", testServer_templatesJSON_term), ("testServer_templatesJSON_term_capitalLetter", testServer_templatesJSON_term_capitalLetter), ("testServer_templatesJSON_multipleTerms", testServer_templatesJSON_multipleTerms) ] func testServer_index() throws { if let byteCount = try responseForRequest("/").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_docs() throws { if let byteCount = try responseForRequest("/docs").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_templatesJSON_noTerm() throws { if let byteCount = try responseForRequest("/dropdown/templates.json").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_templatesJSON_term() throws { if let byteCount = try responseForRequest("/dropdown/templates.json?term=java").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_templatesJSON_term_capitalLetter() throws { if let byteCount = try responseForRequest("/dropdown/templates.json?term=Java").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } func testServer_templatesJSON_multipleTerms() throws { if let byteCount = try responseForRequest("/dropdown/templates.json?term=java,ada").http.body.count { XCTAssertGreaterThan(byteCount, 0) } else { XCTFail() } } // MARK: - Private private func responseForRequest(_ url: String) throws -> Response { let application = try Gitignore().app(.detect()) let request = HTTPRequest(method: .GET, url: URL(string: url)!) let wrappedRequest = Request(http: request, using: application) let responder = try application.make(Responder.self) return try responder.respond(to: wrappedRequest).wait() } } ================================================ FILE: Tests/LinuxMain.swift ================================================ #if os(Linux) import XCTest @testable import AppTests XCTMain([ testCase(TemplateControllerTests.allTests), testCase(IgnoreTemplateModelTests.allTests), testCase(String_ExtensionsTests.allTests), testCase(URL_ExtensionsTests.allTests), testCase(APIHandlersTests.allTests), testCase(SiteHandlersTests.allTests), ]) #endif ================================================ FILE: app.json ================================================ { "name": "GitignoreIO", "scripts": {}, "env": {}, "formation": {}, "addons": [], "buildpacks": [ { "url": "https://github.com/kylef/heroku-buildpack-swift" } ] } ================================================ FILE: docker-compose-dev.yml ================================================ # This serves ONLY local testing purposes! version: "3.5" services: app: platform: linux/x86_64 image: gitignore-io:latest build: context: ./ dockerfile: Dockerfile environment: HOST_ORIGIN: BASE_PREFIX: GOOGLE_ANALYTICS_UID: volumes: - ./Public:/app/Public - ./Resources:/app/Resources ports: - 8080:8080 command: vapor run ================================================ FILE: docker-compose.yml ================================================ version: "3.9" services: app: image: gitignore-io:latest build: context: ./ dockerfile: Dockerfile ports: - 8080:8080 ================================================ FILE: e2e-tests/api/index.test.js ================================================ const superagent = require('superagent'); const { templates } = require('../utils/templates'); let response; describe('/api/list as lines', () => { beforeAll(async () => { response = await superagent.get(`${BASE_URL}/api/list?format=lines`); }); it('should be successful', async () => { expect(response.status).toBe(200); }); it('should contain all valid templates', async () => { templates.forEach((template) => expect(response.text).toContain(template.toLowerCase())); }); }); describe('/api/list as json', () => { beforeAll(async () => { response = await superagent.get(`${BASE_URL}/api/list?format=json`); }); it('should be successful', async () => { expect(response.status).toBe(200); }); it('should contain all valid templates', async () => { templates.forEach((template) => expect(Object.keys(response.body)).toContain(template.toLowerCase())); }); }); ================================================ FILE: e2e-tests/api/show.test.js ================================================ const superagent = require('superagent'); const { randomTemplates } = require('../utils/templates'); let response; describe('/api/show single template', () => { randomTemplates(10).forEach((template) => { it(`${template} should be successful`, async () => { response = await superagent.get(`${BASE_URL}/api/${template}`); expect(response.status).toBe(200); }); it(`should return ${template} template`, async () => { response = await superagent.get(`${BASE_URL}/api/${template}`); expect(response.text).toContain(template); }); }); }); let testTemplates = randomTemplates(3); describe('/api/show multiple templates', () => { beforeAll(async () => { response = await superagent.get(`${BASE_URL}/api/${testTemplates.join(',')}`); }); it(`${testTemplates.join(',')} should be successful`, async () => { expect(response.status).toBe(200); }); it(`should return ${testTemplates.join(',')} templates`, async () => { testTemplates.forEach((template) => expect(response.text).toContain(template)); }); }); ================================================ FILE: e2e-tests/pages/homepage.test.js ================================================ const { randomTemplate, randomTemplates } = require('../utils/templates'); describe('Home page', () => { const templateSearchResultSelector = 'li.select2-results__option' const selectedTemplatesSelector = 'li.select2-selection__choice'; const searchInputSelector = 'input[type="search"]'; const submitButtonSelector = '.btn-gitignore'; const loadPage = (templates) => { const templatesQuery = templates !== undefined ? `/?templates=${templates.join(',')}` : '' return page.goto(`${BASE_URL}${templatesQuery}`, {waitUntil: 'networkidle2'}); }; const searchFor = async (template) => { const searchInput = await page.$(searchInputSelector); await searchInput.type(template); await expect(page).toClick(templateSearchResultSelector); } beforeEach(async () => { await page.setViewport({ width: 1440, height: 900 }); }); it('should successfully submit a single item', async () => { const template = randomTemplate(); await loadPage(); await searchFor(template); await expect(await page.$(selectedTemplatesSelector)).toMatch(template, {timeout: 10000}); await page.click(submitButtonSelector); await page.waitForFunction(`window.location.href.includes('${template.toLowerCase()}')`); await expect(page).toMatch(template, {timeout: 10000}); }); it('should successfully submit multiple items', async () => { const testTemplates = randomTemplates(3); await loadPage(); for (const template of testTemplates) { await searchFor(template); } await expect((await page.$$(selectedTemplatesSelector)).length).toEqual(testTemplates.length); await page.click(submitButtonSelector); await page.waitForFunction(`window.location.href.includes('${testTemplates[0].toLowerCase()}')`); for (const template of testTemplates) { await expect(page).toMatch(template, {timeout: 10000}); } }); it('should successfully load query params templates in search bar', async () => { const testTemplates = randomTemplates(2); await loadPage(testTemplates); await expect((await page.$$(selectedTemplatesSelector)).length).toEqual(testTemplates.length); }); }); ================================================ FILE: e2e-tests/utils/templates.js ================================================ const fs = require('fs'); let templates = []; try { fs.readdirSync('./gitignore/templates').forEach(file => { if (file.includes('.gitignore')) { const filenameWithouthExtension = file.split('.')[0]; templates.push(filenameWithouthExtension); } }); } catch (e) { console.log(e); } const randomTemplate = () => randomTemplates(1)[0]; const randomTemplates = (n) => { testTemplates = []; for (let index = 0; index < n; index++) { const myNumArr = new Uint32Array(1); crypto.getRandomValues(myNumArr); const randomNumber = Number(`0.${myNumArr[0]}`); testTemplates.push(templates[Math.floor(randomNumber * templates.length)]) } return testTemplates; } module.exports = { randomTemplate, randomTemplates, templates } ================================================ FILE: jest-puppeteer.config.js ================================================ module.exports = { launch: { dumpio: true, headless: true, }, browser: 'chromium', browserContext: 'incognito' } ================================================ FILE: jest.config.js ================================================ module.exports = { globals: { 'BASE_URL': process.env.BASE_URL || 'http://localhost:8080' }, preset: 'jest-puppeteer', testTimeout: 30000 }; ================================================ FILE: package.json ================================================ { "name": "gitignore.io", "version": "1.0.0", "license": "MIT", "private": true, "devDependencies": { "jest": "^27.5.1", "jest-puppeteer": "^6.1.0", "puppeteer": "^2.1.1" }, "scripts": { "build": "webpack --mode production", "gitupdate": "git submodule update --init --recursive", "test": "jest e2e-tests" }, "dependencies": { "css-loader": "^6.7.1", "css-minimizer-webpack-plugin": "^3.4.1", "file-loader": "^6.2.0", "jquery": "^3.6.0", "less": "^4.1.1", "less-loader": "^10.0.0", "mini-css-extract-plugin": "^1.6.0", "style-loader": "^2.0.0", "superagent": "^5.2.2", "web-vitals": "^2.1.0", "webpack": "^5.40.0", "webpack-cli": "^4.7.2" } } ================================================ FILE: src/css/bootstrap-extract.css ================================================ *, ::after, ::before { box-sizing: border-box; } h1, h2, h3, h4, h5, h6 { margin-top: 0; margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; } input, button, select { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; } .input-group > .form-control { -ms-flex: 1 1 0%; flex: 1 1 0%; min-width: 0; margin-bottom: 0; background-color: #fff; } .input-group { position: relative; display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; -ms-flex-align: stretch; align-items: stretch; width: 100%; } .input-group-append { margin-left: -1px; display: -ms-flexbox; display: flex; } .input-group-append .btn { position: relative; z-index: 2; cursor: pointer; } .btn { border: 1px solid transparent; } .btn:focus { outline: 0; } ================================================ FILE: src/index.js ================================================ import "./css/bootstrap-extract.css"; import "./css/select2.min.css"; import "./less/select2-toptal-theme.less"; import "./less/app.less"; import "./js/select2-4.0.13/select2.min.js" import "./js/url-search-params-1.1.0/url-search-params.min.js" import "./js/app.js" ================================================ FILE: src/js/app.js ================================================ import $ from "jquery"; import { getCLS, getFID, getLCP } from "web-vitals"; export class GoogleAnalytics { sendToGoogleAnalytics({ name, delta, id }) { window.gtag("event", name, { event_category: "web_vitals", event_label: id, value: Math.round(name === "CLS" ? delta * 1000 : delta), non_interaction: true, }); } trackCoreWebVitals() { getCLS(this.sendToGoogleAnalytics); getFID(this.sendToGoogleAnalytics); getLCP(this.sendToGoogleAnalytics); } } $(function () { $.ajax(window.BASE_PREFIX + "/dropdown/templates.json").done(function (data) { const GAInstance = new GoogleAnalytics(); GAInstance.trackCoreWebVitals(); // bootstrap select2 $("#input-gitignore").select2({ data: data, theme: "toptal", // customized theme multiple: true, allowClear: false, minimumInputLength: 1, selectOnClose: true, placeholder: $("#input-gitignore-placeholder").text(), sorter: function (results) { const query = $(".select2-search__field").val().toLowerCase(); return results.sort(function (a, b) { return ( a.text.toLowerCase().indexOf(query) - b.text.toLowerCase().indexOf(query) ); }); }, }); // load pre-selected tags from URL search params const urlParams = new URLSearchParams(window.location.search); if (urlParams.get("templates") != null) { const preFilledSearchTerms = urlParams .get("templates") .replace(/\s/g, "+") .toLowerCase() .split(","); const validIDs = data.map(function (datum) { return datum.id; }); const validPreFilledSearchTerms = preFilledSearchTerms.filter(function ( term ) { return validIDs.indexOf(term) >= 0; }); $("#input-gitignore") .val(validPreFilledSearchTerms) .trigger("change.select2"); } else { // in order to fix the problem where placeholder gets cut off $("#input-gitignore").val("").trigger("change.select2"); } // Highlight input on site load setTimeout(function () { $(".select2-search__field").focus(); // prevent dropdown opening on page load focus $("#input-gitignore").on("select2:opening", function (e) { e.preventDefault(); $("#input-gitignore").off("select2:opening"); }); }); }); // All users to press ctrl+enter to create template $("#input-gitignore").on("select2:selecting", function (e) { setTimeout(function () { $(".select2-search__field").keydown(function (e) { if (e.keyCode == 13 && (e.metaKey || e.ctrlKey)) { generateGitIgnore(); } }); }); }); // prevent auto sorting of tags selection, keep the order in which they are added // @ref https://github.com/select2/select2/issues/3106 $("#input-gitignore").on("select2:select", function (e) { var id = e.params.data.id; var option = $(e.target).children('[value="' + id + '"]'); option.detach(); $(e.target).append(option).change(); }); // bind click handler to "Create" button $("#btn-gitignore").click(function () { generateGitIgnore(); }); // Delete selections by tag instead of individual letter $.fn.select2.amd.require(["select2/selection/search"], function (Search) { Search.prototype.searchRemoveChoice = function (decorated, item) { this.trigger("unselect", { data: item, }); this.$search.val(""); this.handleSearch(); }; }); // Generate gitignore template function generateGitIgnore() { const searchString = $("#input-gitignore") .map(function () { return $(this).val(); }) .get() .join(","); const searchLength = searchString.length; if (searchLength > 0) { const files = searchString.replace(/^,/, ""); window.location = window.BASE_PREFIX + "/api/" + files; $("#input-gitignore").val(""); } } // Generate gitignore file template function generateGitIgnoreFile() { const searchString = $("#input-gitignore") .map(function () { return $(this).val(); }) .get() .join(","); const searchLength = searchString.length; if (searchLength > 0) { const files = searchString.replace(/^,/, ""); window.location = window.BASE_PREFIX + "/api/f/" + files; } } }); ================================================ FILE: src/less/app.less ================================================ @import "variables.less"; @import "internal-linking.less"; @font-face { font-display: swap; font-weight: 400; font-family: "Proxima Nova"; font-style: normal; src: url("../fonts/ProximaNova-Regular.woff2") format("woff2"), url("../fonts/ProximaNova-Regular.woff") format("woff"), url("../fonts/ProximaNova-Regular.otf") format("opentype"); } @font-face { font-display: swap; font-weight: 600; font-family: "Proxima Nova"; font-style: normal; src: url("../fonts/ProximaNova-Semibold.woff2") format("woff2"), url("../fonts/ProximaNova-Semibold.woff") format("woff"), url("../fonts/ProximaNova-Semibold.otf") format("opentype"); } body, html { height: 100%; background-color: @background; } body { min-width: 320px; color: @text; margin: 0; font-family: "Proxima Nova", Arial, sans-serif; font-size: 16px; font-weight: @weight-regular; line-height: 1.5; display: flex; flex-direction: column; } a { color: @link; text-decoration: none; &:hover, &:focus { text-decoration: underline; } } .content-wrapper { min-height: 100%; display: flex; flex-direction: column; position: relative; padding-top: 72px; } /* --------- header --------- */ header { background: @blue; color: @white; height: 72px; position: fixed; top: 0; width: 100%; overflow-x: hidden; z-index: 1100; .container { display: flex; justify-content: space-between; align-items: center; height: 100%; } a { display: block; line-height: 0; } .header-left-column { display: flex; align-items: center; padding: 0 10px; a { padding-right: 16px; img { min-width: 100px; height: 30px; } } h1 { font-size: 17px; line-height: 28px; border-left: 1px solid @logo-divider; padding-left: 16px; margin: 0; } } .header-right-column { img { height: 24px; } } } /* --------- END of header --------- */ /* --------- main --------- */ main { width: 100%; flex: 1 0 400px; @media (min-width: 768px) { display: flex; } .masthead { margin: 0 auto; max-width: 580px; overflow-y: auto; text-align: center; } .masthead-top { display: flex; flex-direction: column; align-items: center; margin-bottom: 25px; margin-top: 120px; @media (min-width: 768px) { margin-top: 180px; } @media(max-width: 320px) { margin-top: 42px; } img { width: 100%; height: auto; max-width: 370px; } h2 { color: @text-secondary; margin: 20px 0; font-size: 16px; line-height: 16px; } } .input-group { overflow: auto; } .masthead-bottom { margin-top: 40px; margin-bottom: 60px; ul { display: flex; flex-direction: column; justify-content: center; list-style: none; margin: 0; padding: 0; li { margin-bottom: 16px; a { font-size: 16px; line-height: 16px; padding-bottom: 8px; &:hover, &:focus { text-decoration: none; border-bottom: 1px solid @link; } } } } } } /* --------- END of main --------- */ /* --------- footer --------- */ footer { height: 142px; color: @text; padding-bottom: 64px; & > div { width: 100%; max-width: 624px; margin: 0 auto; padding: 0 16px; } .carbon-wrap { display: flex; align-items: center; justify-content: center; } a.carbon-img { height: 78px; img { height: 100%; } } a.carbon-text { font-size: 12px; line-height: 20px; padding-left: 8px; } .carbon-poweredby { display: none; } } /* --------- END of footer --------- */ /* --------- responsiveness --------- */ .container { position: relative; max-width: 100%; padding-right: 16px; padding-left: 16px; margin-right: auto; margin-left: auto; @media (min-width: 1200px) { max-width: 1344px; } } @media (min-width: 576px) { .container { width: 540px; } main .masthead-bottom ul { flex-direction: row; li:not(:first-child) { &::before { display: inline-block; content: ""; width: 1px; height: 12px; background-color: @nav-divider; margin: 0 21px; } } } } @media (min-width: 768px) { .container { width: 720px; } } @media (min-width: 992px) { .container { width: 960px; } } @media (min-width: 1200px) { .container { width: 1376px; } header .header-right-column { padding-right: 98px; } } /* --------- END of responsiveness --------- */ #input-gitignore { -webkit-appearance: none; border: 1px solid @lightgray; border-radius: 0; height: 46px; line-height: 46px; } #input-gitignore::-ms-expand { display: none; } #internal-linking { border: 0; height: 56px; box-shadow: 0px -1px 3px 0px rgba(0, 0, 0, 0.1); @media (max-width: 768px) { height: 32px; } } ================================================ FILE: src/less/internal-linking.less ================================================ .internal-linking { border: 0; width: 100vw; height: @internalLinkingHeightDesktop; overflow: hidden; flex-shrink: 0; flex-basis: @internalLinkingHeightDesktop; @media (max-width: 768px) { height: @internalLinkingHeightMobile; flex-basis: @internalLinkingHeightMobile; } } @keyframes ticker { 0% { transform: translateX(0%); } 100% { transform: translateX(-50%); } } .internal-linking__container { font-weight: 400; font-family: Proxima Nova, Arial, sans-serif; display: flex; flex-direction: row; align-items: center; width: 100%; height: 56px; overflow: hidden; color: @white; background-color: @darkBlue; .internal-linking__title { z-index: 1; display: flex; flex-direction: row; flex-shrink: 0; align-items: center; height: 100%; color: @blue; font-weight: 600; font-size: 10px; line-height: 12px; text-transform: uppercase; background-color: @white; img { margin: 22px 8px 18px 24px; } span { margin: 16px 24px 16px 0; white-space: nowrap; } } .internal-linking__ticker-list { display: flex; flex-direction: row; font-size: 12px; line-height: 16px; animation-name: ticker; animation-duration: 180s; animation-timing-function: linear; animation-iteration-count: infinite; &:hover { animation-play-state: paused; } .internal-linking__link { margin: 20px 28px; padding: 5px 12px 3px 12px; color: @white; white-space: nowrap; text-decoration: underline; } } } @media screen and (max-width: 768px) { .internal-linking__container { height: 32px; border: none; box-shadow: none; .internal-linking__title { img { margin: 8px; } span { margin: 6px 16px 6px 0; font-size: 8px; line-height: 10px; } } } } @media (max-width: 768px) { .internal-linking__container { .internal-linking__ticker-list { .internal-linking__link { margin: 4px 16px; text-decoration: none; border: 1px solid @white; border-radius: 16px; } } } } ================================================ FILE: src/less/select2-toptal-theme.less ================================================ @import "variables.less"; /* * @reference https://github.com/ttskch/select2-bootstrap4-theme/tree/master/src */ /******** layout.less ********/ // basic .select2-container { display: block; *:focus { outline: 0; } } // input-group .input-group { .select2-container--toptal { -webkit-box-flex: 1; -ms-flex-positive: 1; flex-grow: 1; max-width: calc(100% - ~"@{button-width}" - 1px); } .input-group-append { width: @button-width; height: @input-height; } @media (max-width: 767px) { flex-direction: column; .select2-container--toptal { width: 100% !important; max-width: 100%; } .input-group-append { width: 100%; margin-top: 12px; margin-left: 0; } } } .select2-container--toptal { // input box .select2-selection { background-color: @input-bg; border-radius: 0; border: 1px solid @input-border-color; box-shadow: none; width: 100%; -webkit-transition: border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; transition: border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out; .select2-search__field { font-size: 16px; line-height: 24px; height: 24px; margin: 10px 0; color: @input-text-color; caret-color: @input-caret-color; -webkit-appearance: none; border-radius: 0; @media (min-width: 768px) { font-size: 13px; line-height: 20px; height: 20px; margin: 12px 0; } &::-webkit-search-decoration { -webkit-appearance: none; } &::placeholder { color: @input-placeholder; } &::-webkit-input-placeholder { color: @input-placeholder; } &:-ms-input-placeholder { color: @input-placeholder; } &::-moz-placeholder { color: @input-placeholder; } } } // focused input box &.select2-container--focus { .select2-selection { box-shadow: none; border-color: @input-focus-border-color; } // when open, hide bottom border &.select2-container--open .select2-selection { // border-bottom: none; // border-bottom-left-radius: 0; // border-bottom-right-radius: 0; } } // dropdown .select2-dropdown { border: none; background-color: @dropdown-bg; box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.08); color: @dropdown-text-color; font-size: 13px; line-height: 16px; margin-top: 0; // dropdown opened above &.select2-dropdown--above { // border-top: 1px solid $input-border-color; // border-top-left-radius: $input-border-radius; // border-top-right-radius: $input-border-radius; } // selected item .select2-results__option[aria-selected=true] { background-color: @option-selected-color; } } .select2-results__option { padding: 10px; } // mouse hovered item .select2-results__message, .select2-results__option--highlighted, .select2-results__option--highlighted.select2-results__option[aria-selected=true] { background-color: @option-highlighted-color; } // fixes vertical overflow .select2-results > .select2-results__options { max-height: @dropdown-max-height; overflow-y: auto; } } /******** end of layout.less ********/ /******** multiple.less ********/ .select2-container--toptal { .select2-selection--multiple { // height of input box min-height: @input-height; // input box .select2-selection__rendered { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; list-style: none; margin: 0; padding: 0 10px; width: 100%; display: block; } // each selected item in input box .select2-selection__choice { font-size: 12px; font-weight: @weight-semibold; line-height: 22px; color: @tag-color; padding: 0 12px; border-radius: @tag-border-radius; border: 1px solid @tag-border-color; margin: 10px 6px 0 0; float: left; cursor: pointer; } // x button of each selected item in input box .select2-selection__choice__remove { color: @tag-remove-color; float: right; margin-left: 8px; font-size: 18px; font-weight: @weight-regular; &:hover { color: @tag-remove-color-hover; } } } } /******** end of multiple.less ********/ /******** button.less ********/ .input-group-append { & > .btn-gitignore { width: 100%; color: @button-text; background: @button-bg; -webkit-transition: background .35s cubic-bezier(0,0,.2,1); transition: background .35s cubic-bezier(0,0,.2,1); font-size: 14px; line-height: 16px; text-align: center; border-radius: 0; &:focus { box-shadow: none; border-color: @input-focus-border-color; } &:hover { background: @button-bg-hover; } } } /******** end of button.less ********/ ================================================ FILE: src/less/variables.less ================================================ // colors @black: #000000; @white: #ffffff; @semi-white: #ebeced; @blue: #204ecf; @green: #00cc83; @darkgreen: #00a369; @darkgray: #455065; @gray: #a6abb5; @lightgray: #d8d9dc; @darkBlue: #0f256e; // fonts @weight-thin: 100; @weight-light: 300; @weight-regular: 400; @weight-semibold: 600; @weight-bold: 700; // objects @background: transparent; @text: @black; @text-secondary: @darkgray; @link: @blue; @link-hover: @blue; @logo-divider: @semi-white; @nav-divider: @gray; @border: @lightgray; // input @input-height: 46px; @input-bg: @white; @input-border-color: @lightgray; @input-focus-border-color: @blue; @input-caret-color: @blue; @input-text-color: @black; @input-placeholder: @lightgray; // button @button-bg: @green; @button-bg-hover: @darkgreen; @button-text: @white; @button-width: 120px; // select dropdown @dropdown-max-height: 15em; @dropdown-bg: @white; @dropdown-text-color: @black; @option-selected-color: @lightgray; @option-highlighted-color: rgba(32, 78, 207, 0.08); // rgba(@blue, 0.08) // select tags @tag-color: @blue; @tag-border-radius: 100px; @tag-border-color: @lightgray; @tag-remove-color: @darkgray; @tag-remove-color-hover: @gray; // internal-linking @internalLinkingHeightDesktop: 56px; @internalLinkingHeightMobile: 32px; ================================================ FILE: webpack.config.js ================================================ const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); module.exports = { output: { path: __dirname + '/Public/assets', }, plugins: [ new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: '[name].css', chunkFilename: '[id].css', }), ], module: { rules: [ { test: /\.(le|sa|sc|c)ss$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { publicPath: '../Public/assets/', }, }, { loader: 'css-loader', options: { url: false, }, }, { loader: "less-loader", options: { lessOptions: { strictMath: true, }, }, }, ], }, ], }, optimization: { minimizer: [ // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line `...`, new CssMinimizerPlugin(), ], }, };